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        umode_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 *file, struct dir_context *ctx)
 243{
 244        loff_t pos = ctx->pos;
 245        struct inode *inode = file_inode(file);
 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        int need_revalidate = (file->f_version != inode->i_version);
 251
 252        if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
 253                return 0;
 254
 255        for ( ; n < npages; n++, offset = 0) {
 256                char *kaddr, *limit;
 257                struct exofs_dir_entry *de;
 258                struct page *page = exofs_get_page(inode, n);
 259
 260                if (IS_ERR(page)) {
 261                        EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
 262                                  inode->i_ino);
 263                        ctx->pos += PAGE_CACHE_SIZE - offset;
 264                        return PTR_ERR(page);
 265                }
 266                kaddr = page_address(page);
 267                if (unlikely(need_revalidate)) {
 268                        if (offset) {
 269                                offset = exofs_validate_entry(kaddr, offset,
 270                                                                chunk_mask);
 271                                ctx->pos = (n<<PAGE_CACHE_SHIFT) + offset;
 272                        }
 273                        file->f_version = inode->i_version;
 274                        need_revalidate = 0;
 275                }
 276                de = (struct exofs_dir_entry *)(kaddr + offset);
 277                limit = kaddr + exofs_last_byte(inode, n) -
 278                                                        EXOFS_DIR_REC_LEN(1);
 279                for (; (char *)de <= limit; de = exofs_next_entry(de)) {
 280                        if (de->rec_len == 0) {
 281                                EXOFS_ERR("ERROR: "
 282                                     "zero-length entry in directory(0x%lx)\n",
 283                                     inode->i_ino);
 284                                exofs_put_page(page);
 285                                return -EIO;
 286                        }
 287                        if (de->inode_no) {
 288                                unsigned char t;
 289
 290                                if (de->file_type < EXOFS_FT_MAX)
 291                                        t = exofs_filetype_table[de->file_type];
 292                                else
 293                                        t = DT_UNKNOWN;
 294
 295                                if (!dir_emit(ctx, de->name, de->name_len,
 296                                                le64_to_cpu(de->inode_no),
 297                                                t)) {
 298                                        exofs_put_page(page);
 299                                        return 0;
 300                                }
 301                        }
 302                        ctx->pos += le16_to_cpu(de->rec_len);
 303                }
 304                exofs_put_page(page);
 305        }
 306        return 0;
 307}
 308
 309struct exofs_dir_entry *exofs_find_entry(struct inode *dir,
 310                        struct dentry *dentry, struct page **res_page)
 311{
 312        const unsigned char *name = dentry->d_name.name;
 313        int namelen = dentry->d_name.len;
 314        unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
 315        unsigned long start, n;
 316        unsigned long npages = dir_pages(dir);
 317        struct page *page = NULL;
 318        struct exofs_i_info *oi = exofs_i(dir);
 319        struct exofs_dir_entry *de;
 320
 321        if (npages == 0)
 322                goto out;
 323
 324        *res_page = NULL;
 325
 326        start = oi->i_dir_start_lookup;
 327        if (start >= npages)
 328                start = 0;
 329        n = start;
 330        do {
 331                char *kaddr;
 332                page = exofs_get_page(dir, n);
 333                if (!IS_ERR(page)) {
 334                        kaddr = page_address(page);
 335                        de = (struct exofs_dir_entry *) kaddr;
 336                        kaddr += exofs_last_byte(dir, n) - reclen;
 337                        while ((char *) de <= kaddr) {
 338                                if (de->rec_len == 0) {
 339                                        EXOFS_ERR("ERROR: zero-length entry in "
 340                                                  "directory(0x%lx)\n",
 341                                                  dir->i_ino);
 342                                        exofs_put_page(page);
 343                                        goto out;
 344                                }
 345                                if (exofs_match(namelen, name, de))
 346                                        goto found;
 347                                de = exofs_next_entry(de);
 348                        }
 349                        exofs_put_page(page);
 350                }
 351                if (++n >= npages)
 352                        n = 0;
 353        } while (n != start);
 354out:
 355        return NULL;
 356
 357found:
 358        *res_page = page;
 359        oi->i_dir_start_lookup = n;
 360        return de;
 361}
 362
 363struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p)
 364{
 365        struct page *page = exofs_get_page(dir, 0);
 366        struct exofs_dir_entry *de = NULL;
 367
 368        if (!IS_ERR(page)) {
 369                de = exofs_next_entry(
 370                                (struct exofs_dir_entry *)page_address(page));
 371                *p = page;
 372        }
 373        return de;
 374}
 375
 376ino_t exofs_parent_ino(struct dentry *child)
 377{
 378        struct page *page;
 379        struct exofs_dir_entry *de;
 380        ino_t ino;
 381
 382        de = exofs_dotdot(child->d_inode, &page);
 383        if (!de)
 384                return 0;
 385
 386        ino = le64_to_cpu(de->inode_no);
 387        exofs_put_page(page);
 388        return ino;
 389}
 390
 391ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry)
 392{
 393        ino_t res = 0;
 394        struct exofs_dir_entry *de;
 395        struct page *page;
 396
 397        de = exofs_find_entry(dir, dentry, &page);
 398        if (de) {
 399                res = le64_to_cpu(de->inode_no);
 400                exofs_put_page(page);
 401        }
 402        return res;
 403}
 404
 405int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
 406                        struct page *page, struct inode *inode)
 407{
 408        loff_t pos = page_offset(page) +
 409                        (char *) de - (char *) page_address(page);
 410        unsigned len = le16_to_cpu(de->rec_len);
 411        int err;
 412
 413        lock_page(page);
 414        err = exofs_write_begin(NULL, page->mapping, pos, len,
 415                                AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
 416        if (err)
 417                EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n",
 418                          err);
 419
 420        de->inode_no = cpu_to_le64(inode->i_ino);
 421        exofs_set_de_type(de, inode);
 422        if (likely(!err))
 423                err = exofs_commit_chunk(page, pos, len);
 424        exofs_put_page(page);
 425        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 426        mark_inode_dirty(dir);
 427        return err;
 428}
 429
 430int exofs_add_link(struct dentry *dentry, struct inode *inode)
 431{
 432        struct inode *dir = dentry->d_parent->d_inode;
 433        const unsigned char *name = dentry->d_name.name;
 434        int namelen = dentry->d_name.len;
 435        unsigned chunk_size = exofs_chunk_size(dir);
 436        unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
 437        unsigned short rec_len, name_len;
 438        struct page *page = NULL;
 439        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
 440        struct exofs_dir_entry *de;
 441        unsigned long npages = dir_pages(dir);
 442        unsigned long n;
 443        char *kaddr;
 444        loff_t pos;
 445        int err;
 446
 447        for (n = 0; n <= npages; n++) {
 448                char *dir_end;
 449
 450                page = exofs_get_page(dir, n);
 451                err = PTR_ERR(page);
 452                if (IS_ERR(page))
 453                        goto out;
 454                lock_page(page);
 455                kaddr = page_address(page);
 456                dir_end = kaddr + exofs_last_byte(dir, n);
 457                de = (struct exofs_dir_entry *)kaddr;
 458                kaddr += PAGE_CACHE_SIZE - reclen;
 459                while ((char *)de <= kaddr) {
 460                        if ((char *)de == dir_end) {
 461                                name_len = 0;
 462                                rec_len = chunk_size;
 463                                de->rec_len = cpu_to_le16(chunk_size);
 464                                de->inode_no = 0;
 465                                goto got_it;
 466                        }
 467                        if (de->rec_len == 0) {
 468                                EXOFS_ERR("ERROR: exofs_add_link: "
 469                                      "zero-length entry in directory(0x%lx)\n",
 470                                      inode->i_ino);
 471                                err = -EIO;
 472                                goto out_unlock;
 473                        }
 474                        err = -EEXIST;
 475                        if (exofs_match(namelen, name, de))
 476                                goto out_unlock;
 477                        name_len = EXOFS_DIR_REC_LEN(de->name_len);
 478                        rec_len = le16_to_cpu(de->rec_len);
 479                        if (!de->inode_no && rec_len >= reclen)
 480                                goto got_it;
 481                        if (rec_len >= name_len + reclen)
 482                                goto got_it;
 483                        de = (struct exofs_dir_entry *) ((char *) de + rec_len);
 484                }
 485                unlock_page(page);
 486                exofs_put_page(page);
 487        }
 488
 489        EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=0x%lx\n",
 490                  dentry, inode->i_ino);
 491        return -EINVAL;
 492
 493got_it:
 494        pos = page_offset(page) +
 495                (char *)de - (char *)page_address(page);
 496        err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0,
 497                                                        &page, NULL);
 498        if (err)
 499                goto out_unlock;
 500        if (de->inode_no) {
 501                struct exofs_dir_entry *de1 =
 502                        (struct exofs_dir_entry *)((char *)de + name_len);
 503                de1->rec_len = cpu_to_le16(rec_len - name_len);
 504                de->rec_len = cpu_to_le16(name_len);
 505                de = de1;
 506        }
 507        de->name_len = namelen;
 508        memcpy(de->name, name, namelen);
 509        de->inode_no = cpu_to_le64(inode->i_ino);
 510        exofs_set_de_type(de, inode);
 511        err = exofs_commit_chunk(page, pos, rec_len);
 512        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 513        mark_inode_dirty(dir);
 514        sbi->s_numfiles++;
 515
 516out_put:
 517        exofs_put_page(page);
 518out:
 519        return err;
 520out_unlock:
 521        unlock_page(page);
 522        goto out_put;
 523}
 524
 525int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
 526{
 527        struct address_space *mapping = page->mapping;
 528        struct inode *inode = mapping->host;
 529        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
 530        char *kaddr = page_address(page);
 531        unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1);
 532        unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
 533        loff_t pos;
 534        struct exofs_dir_entry *pde = NULL;
 535        struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from);
 536        int err;
 537
 538        while (de < dir) {
 539                if (de->rec_len == 0) {
 540                        EXOFS_ERR("ERROR: exofs_delete_entry:"
 541                                  "zero-length entry in directory(0x%lx)\n",
 542                                  inode->i_ino);
 543                        err = -EIO;
 544                        goto out;
 545                }
 546                pde = de;
 547                de = exofs_next_entry(de);
 548        }
 549        if (pde)
 550                from = (char *)pde - (char *)page_address(page);
 551        pos = page_offset(page) + from;
 552        lock_page(page);
 553        err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
 554                                                        &page, NULL);
 555        if (err)
 556                EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n",
 557                          err);
 558        if (pde)
 559                pde->rec_len = cpu_to_le16(to - from);
 560        dir->inode_no = 0;
 561        if (likely(!err))
 562                err = exofs_commit_chunk(page, pos, to - from);
 563        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 564        mark_inode_dirty(inode);
 565        sbi->s_numfiles--;
 566out:
 567        exofs_put_page(page);
 568        return err;
 569}
 570
 571/* kept aligned on 4 bytes */
 572#define THIS_DIR ".\0\0"
 573#define PARENT_DIR "..\0"
 574
 575int exofs_make_empty(struct inode *inode, struct inode *parent)
 576{
 577        struct address_space *mapping = inode->i_mapping;
 578        struct page *page = grab_cache_page(mapping, 0);
 579        unsigned chunk_size = exofs_chunk_size(inode);
 580        struct exofs_dir_entry *de;
 581        int err;
 582        void *kaddr;
 583
 584        if (!page)
 585                return -ENOMEM;
 586
 587        err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0,
 588                                                        &page, NULL);
 589        if (err) {
 590                unlock_page(page);
 591                goto fail;
 592        }
 593
 594        kaddr = kmap_atomic(page);
 595        de = (struct exofs_dir_entry *)kaddr;
 596        de->name_len = 1;
 597        de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1));
 598        memcpy(de->name, THIS_DIR, sizeof(THIS_DIR));
 599        de->inode_no = cpu_to_le64(inode->i_ino);
 600        exofs_set_de_type(de, inode);
 601
 602        de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1));
 603        de->name_len = 2;
 604        de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1));
 605        de->inode_no = cpu_to_le64(parent->i_ino);
 606        memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR));
 607        exofs_set_de_type(de, inode);
 608        kunmap_atomic(kaddr);
 609        err = exofs_commit_chunk(page, 0, chunk_size);
 610fail:
 611        page_cache_release(page);
 612        return err;
 613}
 614
 615int exofs_empty_dir(struct inode *inode)
 616{
 617        struct page *page = NULL;
 618        unsigned long i, npages = dir_pages(inode);
 619
 620        for (i = 0; i < npages; i++) {
 621                char *kaddr;
 622                struct exofs_dir_entry *de;
 623                page = exofs_get_page(inode, i);
 624
 625                if (IS_ERR(page))
 626                        continue;
 627
 628                kaddr = page_address(page);
 629                de = (struct exofs_dir_entry *)kaddr;
 630                kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1);
 631
 632                while ((char *)de <= kaddr) {
 633                        if (de->rec_len == 0) {
 634                                EXOFS_ERR("ERROR: exofs_empty_dir: "
 635                                          "zero-length directory entry"
 636                                          "kaddr=%p, de=%p\n", kaddr, de);
 637                                goto not_empty;
 638                        }
 639                        if (de->inode_no != 0) {
 640                                /* check for . and .. */
 641                                if (de->name[0] != '.')
 642                                        goto not_empty;
 643                                if (de->name_len > 2)
 644                                        goto not_empty;
 645                                if (de->name_len < 2) {
 646                                        if (le64_to_cpu(de->inode_no) !=
 647                                            inode->i_ino)
 648                                                goto not_empty;
 649                                } else if (de->name[1] != '.')
 650                                        goto not_empty;
 651                        }
 652                        de = exofs_next_entry(de);
 653                }
 654                exofs_put_page(page);
 655        }
 656        return 1;
 657
 658not_empty:
 659        exofs_put_page(page);
 660        return 0;
 661}
 662
 663const struct file_operations exofs_dir_operations = {
 664        .llseek         = generic_file_llseek,
 665        .read           = generic_read_dir,
 666        .iterate        = exofs_readdir,
 667};
 668