linux/fs/exofs/dir.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005, 2006
   3 * Avishay Traeger (avishay@gmail.com)
   4 * Copyright (C) 2008, 2009
   5 * Boaz Harrosh <bharrosh@panasas.com>
   6 *
   7 * Copyrights for code taken from ext2:
   8 *     Copyright (C) 1992, 1993, 1994, 1995
   9 *     Remy Card (card@masi.ibp.fr)
  10 *     Laboratoire MASI - Institut Blaise Pascal
  11 *     Universite Pierre et Marie Curie (Paris VI)
  12 *     from
  13 *     linux/fs/minix/inode.c
  14 *     Copyright (C) 1991, 1992  Linus Torvalds
  15 *
  16 * This file is part of exofs.
  17 *
  18 * exofs is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation.  Since it is based on ext2, and the only
  21 * valid version of GPL for the Linux kernel is version 2, the only valid
  22 * version of GPL for exofs is version 2.
  23 *
  24 * exofs is distributed in the hope that it will be useful,
  25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27 * GNU General Public License for more details.
  28 *
  29 * You should have received a copy of the GNU General Public License
  30 * along with exofs; if not, write to the Free Software
  31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  32 */
  33
  34#include "exofs.h"
  35
  36static inline unsigned exofs_chunk_size(struct inode *inode)
  37{
  38        return inode->i_sb->s_blocksize;
  39}
  40
  41static inline void exofs_put_page(struct page *page)
  42{
  43        kunmap(page);
  44        page_cache_release(page);
  45}
  46
  47/* Accesses dir's inode->i_size must be called under inode lock */
  48static inline unsigned long dir_pages(struct inode *inode)
  49{
  50        return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  51}
  52
  53static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr)
  54{
  55        loff_t last_byte = inode->i_size;
  56
  57        last_byte -= page_nr << PAGE_CACHE_SHIFT;
  58        if (last_byte > PAGE_CACHE_SIZE)
  59                last_byte = PAGE_CACHE_SIZE;
  60        return last_byte;
  61}
  62
  63static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len)
  64{
  65        struct address_space *mapping = page->mapping;
  66        struct inode *dir = mapping->host;
  67        int err = 0;
  68
  69        dir->i_version++;
  70
  71        if (!PageUptodate(page))
  72                SetPageUptodate(page);
  73
  74        if (pos+len > dir->i_size) {
  75                i_size_write(dir, pos+len);
  76                mark_inode_dirty(dir);
  77        }
  78        set_page_dirty(page);
  79
  80        if (IS_DIRSYNC(dir))
  81                err = write_one_page(page, 1);
  82        else
  83                unlock_page(page);
  84
  85        return err;
  86}
  87
  88static void exofs_check_page(struct page *page)
  89{
  90        struct inode *dir = page->mapping->host;
  91        unsigned chunk_size = exofs_chunk_size(dir);
  92        char *kaddr = page_address(page);
  93        unsigned offs, rec_len;
  94        unsigned limit = PAGE_CACHE_SIZE;
  95        struct exofs_dir_entry *p;
  96        char *error;
  97
  98        /* if the page is the last one in the directory */
  99        if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
 100                limit = dir->i_size & ~PAGE_CACHE_MASK;
 101                if (limit & (chunk_size - 1))
 102                        goto Ebadsize;
 103                if (!limit)
 104                        goto out;
 105        }
 106        for (offs = 0; offs <= limit - EXOFS_DIR_REC_LEN(1); offs += rec_len) {
 107                p = (struct exofs_dir_entry *)(kaddr + offs);
 108                rec_len = le16_to_cpu(p->rec_len);
 109
 110                if (rec_len < EXOFS_DIR_REC_LEN(1))
 111                        goto Eshort;
 112                if (rec_len & 3)
 113                        goto Ealign;
 114                if (rec_len < EXOFS_DIR_REC_LEN(p->name_len))
 115                        goto Enamelen;
 116                if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
 117                        goto Espan;
 118        }
 119        if (offs != limit)
 120                goto Eend;
 121out:
 122        SetPageChecked(page);
 123        return;
 124
 125Ebadsize:
 126        EXOFS_ERR("ERROR [exofs_check_page]: "
 127                "size of directory(0x%lx) is not a multiple of chunk size\n",
 128                dir->i_ino
 129        );
 130        goto fail;
 131Eshort:
 132        error = "rec_len is smaller than minimal";
 133        goto bad_entry;
 134Ealign:
 135        error = "unaligned directory entry";
 136        goto bad_entry;
 137Enamelen:
 138        error = "rec_len is too small for name_len";
 139        goto bad_entry;
 140Espan:
 141        error = "directory entry across blocks";
 142        goto bad_entry;
 143bad_entry:
 144        EXOFS_ERR(
 145                "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - "
 146                "offset=%lu, inode=0x%llu, rec_len=%d, name_len=%d\n",
 147                dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
 148                _LLU(le64_to_cpu(p->inode_no)),
 149                rec_len, p->name_len);
 150        goto fail;
 151Eend:
 152        p = (struct exofs_dir_entry *)(kaddr + offs);
 153        EXOFS_ERR("ERROR [exofs_check_page]: "
 154                "entry in directory(0x%lx) spans the page boundary"
 155                "offset=%lu, inode=0x%llx\n",
 156                dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
 157                _LLU(le64_to_cpu(p->inode_no)));
 158fail:
 159        SetPageChecked(page);
 160        SetPageError(page);
 161}
 162
 163static struct page *exofs_get_page(struct inode *dir, unsigned long n)
 164{
 165        struct address_space *mapping = dir->i_mapping;
 166        struct page *page = read_mapping_page(mapping, n, NULL);
 167
 168        if (!IS_ERR(page)) {
 169                kmap(page);
 170                if (!PageChecked(page))
 171                        exofs_check_page(page);
 172                if (PageError(page))
 173                        goto fail;
 174        }
 175        return page;
 176
 177fail:
 178        exofs_put_page(page);
 179        return ERR_PTR(-EIO);
 180}
 181
 182static inline int exofs_match(int len, const unsigned char *name,
 183                                        struct exofs_dir_entry *de)
 184{
 185        if (len != de->name_len)
 186                return 0;
 187        if (!de->inode_no)
 188                return 0;
 189        return !memcmp(name, de->name, len);
 190}
 191
 192static inline
 193struct exofs_dir_entry *exofs_next_entry(struct exofs_dir_entry *p)
 194{
 195        return (struct exofs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len));
 196}
 197
 198static inline unsigned
 199exofs_validate_entry(char *base, unsigned offset, unsigned mask)
 200{
 201        struct exofs_dir_entry *de = (struct exofs_dir_entry *)(base + offset);
 202        struct exofs_dir_entry *p =
 203                        (struct exofs_dir_entry *)(base + (offset&mask));
 204        while ((char *)p < (char *)de) {
 205                if (p->rec_len == 0)
 206                        break;
 207                p = exofs_next_entry(p);
 208        }
 209        return (char *)p - base;
 210}
 211
 212static unsigned char exofs_filetype_table[EXOFS_FT_MAX] = {
 213        [EXOFS_FT_UNKNOWN]      = DT_UNKNOWN,
 214        [EXOFS_FT_REG_FILE]     = DT_REG,
 215        [EXOFS_FT_DIR]          = DT_DIR,
 216        [EXOFS_FT_CHRDEV]       = DT_CHR,
 217        [EXOFS_FT_BLKDEV]       = DT_BLK,
 218        [EXOFS_FT_FIFO]         = DT_FIFO,
 219        [EXOFS_FT_SOCK]         = DT_SOCK,
 220        [EXOFS_FT_SYMLINK]      = DT_LNK,
 221};
 222
 223#define S_SHIFT 12
 224static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = {
 225        [S_IFREG >> S_SHIFT]    = EXOFS_FT_REG_FILE,
 226        [S_IFDIR >> S_SHIFT]    = EXOFS_FT_DIR,
 227        [S_IFCHR >> S_SHIFT]    = EXOFS_FT_CHRDEV,
 228        [S_IFBLK >> S_SHIFT]    = EXOFS_FT_BLKDEV,
 229        [S_IFIFO >> S_SHIFT]    = EXOFS_FT_FIFO,
 230        [S_IFSOCK >> S_SHIFT]   = EXOFS_FT_SOCK,
 231        [S_IFLNK >> S_SHIFT]    = EXOFS_FT_SYMLINK,
 232};
 233
 234static inline
 235void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode)
 236{
 237        mode_t mode = inode->i_mode;
 238        de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
 239}
 240
 241static int
 242exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 243{
 244        loff_t pos = filp->f_pos;
 245        struct inode *inode = filp->f_path.dentry->d_inode;
 246        unsigned int offset = pos & ~PAGE_CACHE_MASK;
 247        unsigned long n = pos >> PAGE_CACHE_SHIFT;
 248        unsigned long npages = dir_pages(inode);
 249        unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
 250        unsigned char *types = NULL;
 251        int need_revalidate = (filp->f_version != inode->i_version);
 252
 253        if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
 254                return 0;
 255
 256        types = exofs_filetype_table;
 257
 258        for ( ; n < npages; n++, offset = 0) {
 259                char *kaddr, *limit;
 260                struct exofs_dir_entry *de;
 261                struct page *page = exofs_get_page(inode, n);
 262
 263                if (IS_ERR(page)) {
 264                        EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
 265                                  inode->i_ino);
 266                        filp->f_pos += PAGE_CACHE_SIZE - offset;
 267                        return PTR_ERR(page);
 268                }
 269                kaddr = page_address(page);
 270                if (unlikely(need_revalidate)) {
 271                        if (offset) {
 272                                offset = exofs_validate_entry(kaddr, offset,
 273                                                                chunk_mask);
 274                                filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
 275                        }
 276                        filp->f_version = inode->i_version;
 277                        need_revalidate = 0;
 278                }
 279                de = (struct exofs_dir_entry *)(kaddr + offset);
 280                limit = kaddr + exofs_last_byte(inode, n) -
 281                                                        EXOFS_DIR_REC_LEN(1);
 282                for (; (char *)de <= limit; de = exofs_next_entry(de)) {
 283                        if (de->rec_len == 0) {
 284                                EXOFS_ERR("ERROR: "
 285                                     "zero-length entry in directory(0x%lx)\n",
 286                                     inode->i_ino);
 287                                exofs_put_page(page);
 288                                return -EIO;
 289                        }
 290                        if (de->inode_no) {
 291                                int over;
 292                                unsigned char d_type = DT_UNKNOWN;
 293
 294                                if (types && de->file_type < EXOFS_FT_MAX)
 295                                        d_type = types[de->file_type];
 296
 297                                offset = (char *)de - kaddr;
 298                                over = filldir(dirent, de->name, de->name_len,
 299                                                (n<<PAGE_CACHE_SHIFT) | offset,
 300                                                le64_to_cpu(de->inode_no),
 301                                                d_type);
 302                                if (over) {
 303                                        exofs_put_page(page);
 304                                        return 0;
 305                                }
 306                        }
 307                        filp->f_pos += le16_to_cpu(de->rec_len);
 308                }
 309                exofs_put_page(page);
 310        }
 311
 312        return 0;
 313}
 314
 315struct exofs_dir_entry *exofs_find_entry(struct inode *dir,
 316                        struct dentry *dentry, struct page **res_page)
 317{
 318        const unsigned char *name = dentry->d_name.name;
 319        int namelen = dentry->d_name.len;
 320        unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
 321        unsigned long start, n;
 322        unsigned long npages = dir_pages(dir);
 323        struct page *page = NULL;
 324        struct exofs_i_info *oi = exofs_i(dir);
 325        struct exofs_dir_entry *de;
 326
 327        if (npages == 0)
 328                goto out;
 329
 330        *res_page = NULL;
 331
 332        start = oi->i_dir_start_lookup;
 333        if (start >= npages)
 334                start = 0;
 335        n = start;
 336        do {
 337                char *kaddr;
 338                page = exofs_get_page(dir, n);
 339                if (!IS_ERR(page)) {
 340                        kaddr = page_address(page);
 341                        de = (struct exofs_dir_entry *) kaddr;
 342                        kaddr += exofs_last_byte(dir, n) - reclen;
 343                        while ((char *) de <= kaddr) {
 344                                if (de->rec_len == 0) {
 345                                        EXOFS_ERR("ERROR: zero-length entry in "
 346                                                  "directory(0x%lx)\n",
 347                                                  dir->i_ino);
 348                                        exofs_put_page(page);
 349                                        goto out;
 350                                }
 351                                if (exofs_match(namelen, name, de))
 352                                        goto found;
 353                                de = exofs_next_entry(de);
 354                        }
 355                        exofs_put_page(page);
 356                }
 357                if (++n >= npages)
 358                        n = 0;
 359        } while (n != start);
 360out:
 361        return NULL;
 362
 363found:
 364        *res_page = page;
 365        oi->i_dir_start_lookup = n;
 366        return de;
 367}
 368
 369struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p)
 370{
 371        struct page *page = exofs_get_page(dir, 0);
 372        struct exofs_dir_entry *de = NULL;
 373
 374        if (!IS_ERR(page)) {
 375                de = exofs_next_entry(
 376                                (struct exofs_dir_entry *)page_address(page));
 377                *p = page;
 378        }
 379        return de;
 380}
 381
 382ino_t exofs_parent_ino(struct dentry *child)
 383{
 384        struct page *page;
 385        struct exofs_dir_entry *de;
 386        ino_t ino;
 387
 388        de = exofs_dotdot(child->d_inode, &page);
 389        if (!de)
 390                return 0;
 391
 392        ino = le64_to_cpu(de->inode_no);
 393        exofs_put_page(page);
 394        return ino;
 395}
 396
 397ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry)
 398{
 399        ino_t res = 0;
 400        struct exofs_dir_entry *de;
 401        struct page *page;
 402
 403        de = exofs_find_entry(dir, dentry, &page);
 404        if (de) {
 405                res = le64_to_cpu(de->inode_no);
 406                exofs_put_page(page);
 407        }
 408        return res;
 409}
 410
 411int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
 412                        struct page *page, struct inode *inode)
 413{
 414        loff_t pos = page_offset(page) +
 415                        (char *) de - (char *) page_address(page);
 416        unsigned len = le16_to_cpu(de->rec_len);
 417        int err;
 418
 419        lock_page(page);
 420        err = exofs_write_begin(NULL, page->mapping, pos, len,
 421                                AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
 422        if (err)
 423                EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n",
 424                          err);
 425
 426        de->inode_no = cpu_to_le64(inode->i_ino);
 427        exofs_set_de_type(de, inode);
 428        if (likely(!err))
 429                err = exofs_commit_chunk(page, pos, len);
 430        exofs_put_page(page);
 431        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 432        mark_inode_dirty(dir);
 433        return err;
 434}
 435
 436int exofs_add_link(struct dentry *dentry, struct inode *inode)
 437{
 438        struct inode *dir = dentry->d_parent->d_inode;
 439        const unsigned char *name = dentry->d_name.name;
 440        int namelen = dentry->d_name.len;
 441        unsigned chunk_size = exofs_chunk_size(dir);
 442        unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
 443        unsigned short rec_len, name_len;
 444        struct page *page = NULL;
 445        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
 446        struct exofs_dir_entry *de;
 447        unsigned long npages = dir_pages(dir);
 448        unsigned long n;
 449        char *kaddr;
 450        loff_t pos;
 451        int err;
 452
 453        for (n = 0; n <= npages; n++) {
 454                char *dir_end;
 455
 456                page = exofs_get_page(dir, n);
 457                err = PTR_ERR(page);
 458                if (IS_ERR(page))
 459                        goto out;
 460                lock_page(page);
 461                kaddr = page_address(page);
 462                dir_end = kaddr + exofs_last_byte(dir, n);
 463                de = (struct exofs_dir_entry *)kaddr;
 464                kaddr += PAGE_CACHE_SIZE - reclen;
 465                while ((char *)de <= kaddr) {
 466                        if ((char *)de == dir_end) {
 467                                name_len = 0;
 468                                rec_len = chunk_size;
 469                                de->rec_len = cpu_to_le16(chunk_size);
 470                                de->inode_no = 0;
 471                                goto got_it;
 472                        }
 473                        if (de->rec_len == 0) {
 474                                EXOFS_ERR("ERROR: exofs_add_link: "
 475                                      "zero-length entry in directory(0x%lx)\n",
 476                                      inode->i_ino);
 477                                err = -EIO;
 478                                goto out_unlock;
 479                        }
 480                        err = -EEXIST;
 481                        if (exofs_match(namelen, name, de))
 482                                goto out_unlock;
 483                        name_len = EXOFS_DIR_REC_LEN(de->name_len);
 484                        rec_len = le16_to_cpu(de->rec_len);
 485                        if (!de->inode_no && rec_len >= reclen)
 486                                goto got_it;
 487                        if (rec_len >= name_len + reclen)
 488                                goto got_it;
 489                        de = (struct exofs_dir_entry *) ((char *) de + rec_len);
 490                }
 491                unlock_page(page);
 492                exofs_put_page(page);
 493        }
 494
 495        EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=0x%lx\n",
 496                  dentry, inode->i_ino);
 497        return -EINVAL;
 498
 499got_it:
 500        pos = page_offset(page) +
 501                (char *)de - (char *)page_address(page);
 502        err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0,
 503                                                        &page, NULL);
 504        if (err)
 505                goto out_unlock;
 506        if (de->inode_no) {
 507                struct exofs_dir_entry *de1 =
 508                        (struct exofs_dir_entry *)((char *)de + name_len);
 509                de1->rec_len = cpu_to_le16(rec_len - name_len);
 510                de->rec_len = cpu_to_le16(name_len);
 511                de = de1;
 512        }
 513        de->name_len = namelen;
 514        memcpy(de->name, name, namelen);
 515        de->inode_no = cpu_to_le64(inode->i_ino);
 516        exofs_set_de_type(de, inode);
 517        err = exofs_commit_chunk(page, pos, rec_len);
 518        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 519        mark_inode_dirty(dir);
 520        sbi->s_numfiles++;
 521
 522out_put:
 523        exofs_put_page(page);
 524out:
 525        return err;
 526out_unlock:
 527        unlock_page(page);
 528        goto out_put;
 529}
 530
 531int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
 532{
 533        struct address_space *mapping = page->mapping;
 534        struct inode *inode = mapping->host;
 535        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
 536        char *kaddr = page_address(page);
 537        unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1);
 538        unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
 539        loff_t pos;
 540        struct exofs_dir_entry *pde = NULL;
 541        struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from);
 542        int err;
 543
 544        while (de < dir) {
 545                if (de->rec_len == 0) {
 546                        EXOFS_ERR("ERROR: exofs_delete_entry:"
 547                                  "zero-length entry in directory(0x%lx)\n",
 548                                  inode->i_ino);
 549                        err = -EIO;
 550                        goto out;
 551                }
 552                pde = de;
 553                de = exofs_next_entry(de);
 554        }
 555        if (pde)
 556                from = (char *)pde - (char *)page_address(page);
 557        pos = page_offset(page) + from;
 558        lock_page(page);
 559        err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
 560                                                        &page, NULL);
 561        if (err)
 562                EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n",
 563                          err);
 564        if (pde)
 565                pde->rec_len = cpu_to_le16(to - from);
 566        dir->inode_no = 0;
 567        if (likely(!err))
 568                err = exofs_commit_chunk(page, pos, to - from);
 569        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 570        mark_inode_dirty(inode);
 571        sbi->s_numfiles--;
 572out:
 573        exofs_put_page(page);
 574        return err;
 575}
 576
 577/* kept aligned on 4 bytes */
 578#define THIS_DIR ".\0\0"
 579#define PARENT_DIR "..\0"
 580
 581int exofs_make_empty(struct inode *inode, struct inode *parent)
 582{
 583        struct address_space *mapping = inode->i_mapping;
 584        struct page *page = grab_cache_page(mapping, 0);
 585        unsigned chunk_size = exofs_chunk_size(inode);
 586        struct exofs_dir_entry *de;
 587        int err;
 588        void *kaddr;
 589
 590        if (!page)
 591                return -ENOMEM;
 592
 593        err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0,
 594                                                        &page, NULL);
 595        if (err) {
 596                unlock_page(page);
 597                goto fail;
 598        }
 599
 600        kaddr = kmap_atomic(page, KM_USER0);
 601        de = (struct exofs_dir_entry *)kaddr;
 602        de->name_len = 1;
 603        de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1));
 604        memcpy(de->name, THIS_DIR, sizeof(THIS_DIR));
 605        de->inode_no = cpu_to_le64(inode->i_ino);
 606        exofs_set_de_type(de, inode);
 607
 608        de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1));
 609        de->name_len = 2;
 610        de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1));
 611        de->inode_no = cpu_to_le64(parent->i_ino);
 612        memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR));
 613        exofs_set_de_type(de, inode);
 614        kunmap_atomic(kaddr, KM_USER0);
 615        err = exofs_commit_chunk(page, 0, chunk_size);
 616fail:
 617        page_cache_release(page);
 618        return err;
 619}
 620
 621int exofs_empty_dir(struct inode *inode)
 622{
 623        struct page *page = NULL;
 624        unsigned long i, npages = dir_pages(inode);
 625
 626        for (i = 0; i < npages; i++) {
 627                char *kaddr;
 628                struct exofs_dir_entry *de;
 629                page = exofs_get_page(inode, i);
 630
 631                if (IS_ERR(page))
 632                        continue;
 633
 634                kaddr = page_address(page);
 635                de = (struct exofs_dir_entry *)kaddr;
 636                kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1);
 637
 638                while ((char *)de <= kaddr) {
 639                        if (de->rec_len == 0) {
 640                                EXOFS_ERR("ERROR: exofs_empty_dir: "
 641                                          "zero-length directory entry"
 642                                          "kaddr=%p, de=%p\n", kaddr, de);
 643                                goto not_empty;
 644                        }
 645                        if (de->inode_no != 0) {
 646                                /* check for . and .. */
 647                                if (de->name[0] != '.')
 648                                        goto not_empty;
 649                                if (de->name_len > 2)
 650                                        goto not_empty;
 651                                if (de->name_len < 2) {
 652                                        if (le64_to_cpu(de->inode_no) !=
 653                                            inode->i_ino)
 654                                                goto not_empty;
 655                                } else if (de->name[1] != '.')
 656                                        goto not_empty;
 657                        }
 658                        de = exofs_next_entry(de);
 659                }
 660                exofs_put_page(page);
 661        }
 662        return 1;
 663
 664not_empty:
 665        exofs_put_page(page);
 666        return 0;
 667}
 668
 669const struct file_operations exofs_dir_operations = {
 670        .llseek         = generic_file_llseek,
 671        .read           = generic_read_dir,
 672        .readdir        = exofs_readdir,
 673};
 674