fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / ext2 / dir.c
index 6af2765..0b02ba9 100644 (file)
@@ -159,8 +159,7 @@ fail:
 static struct page * ext2_get_page(struct inode *dir, unsigned long n)
 {
        struct address_space *mapping = dir->i_mapping;
-       struct page *page = read_cache_page(mapping, n,
-                               (filler_t*)mapping->a_ops->readpage, NULL);
+       struct page *page = read_mapping_page(mapping, n, NULL);
        if (!IS_ERR(page)) {
                wait_on_page_locked(page);
                kmap(page);
@@ -249,18 +248,17 @@ static int
 ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
 {
        loff_t pos = filp->f_pos;
-       struct inode *inode = filp->f_dentry->d_inode;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        struct super_block *sb = inode->i_sb;
-       unsigned offset = pos & ~PAGE_CACHE_MASK;
+       unsigned int offset = pos & ~PAGE_CACHE_MASK;
        unsigned long n = pos >> PAGE_CACHE_SHIFT;
        unsigned long npages = dir_pages(inode);
        unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
        unsigned char *types = NULL;
-       int need_revalidate = (filp->f_version != inode->i_version);
-       int ret;
+       int need_revalidate = filp->f_version != inode->i_version;
 
        if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
-               goto success;
+               return 0;
 
        if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
                types = ext2_filetype_table;
@@ -270,11 +268,20 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
                ext2_dirent *de;
                struct page *page = ext2_get_page(inode, n);
 
-               if (IS_ERR(page))
-                       continue;
+               if (IS_ERR(page)) {
+                       ext2_error(sb, __FUNCTION__,
+                                  "bad page in #%lu",
+                                  inode->i_ino);
+                       filp->f_pos += PAGE_CACHE_SIZE - offset;
+                       return -EIO;
+               }
                kaddr = page_address(page);
-               if (need_revalidate) {
-                       offset = ext2_validate_entry(kaddr, offset, chunk_mask);
+               if (unlikely(need_revalidate)) {
+                       if (offset) {
+                               offset = ext2_validate_entry(kaddr, offset, chunk_mask);
+                               filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+                       }
+                       filp->f_version = inode->i_version;
                        need_revalidate = 0;
                }
                de = (ext2_dirent *)(kaddr+offset);
@@ -283,9 +290,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
                        if (de->rec_len == 0) {
                                ext2_error(sb, __FUNCTION__,
                                        "zero-length directory entry");
-                               ret = -EIO;
                                ext2_put_page(page);
-                               goto done;
+                               return -EIO;
                        }
                        if (de->inode) {
                                int over;
@@ -300,19 +306,14 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
                                                le32_to_cpu(de->inode), d_type);
                                if (over) {
                                        ext2_put_page(page);
-                                       goto success;
+                                       return 0;
                                }
                        }
+                       filp->f_pos += le16_to_cpu(de->rec_len);
                }
                ext2_put_page(page);
        }
-
-success:
-       ret = 0;
-done:
-       filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-       filp->f_version = inode->i_version;
-       return ret;
+       return 0;
 }
 
 /*
@@ -398,8 +399,7 @@ ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
        de = ext2_find_entry (dir, dentry, &page);
        if (de) {
                res = le32_to_cpu(de->inode);
-               kunmap(page);
-               page_cache_release(page);
+               ext2_put_page(page);
        }
        return res;
 }
@@ -414,13 +414,12 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
 
        lock_page(page);
        err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
-       if (err)
-               BUG();
+       BUG_ON(err);
        de->inode = cpu_to_le32(inode->i_ino);
        ext2_set_de_type (de, inode);
        err = ext2_commit_chunk(page, from, to);
        ext2_put_page(page);
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
        mark_inode_dirty(dir);
 }
@@ -510,7 +509,7 @@ got_it:
        de->inode = cpu_to_le32(inode->i_ino);
        ext2_set_de_type (de, inode);
        err = ext2_commit_chunk(page, from, to);
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
        mark_inode_dirty(dir);
        /* OFFSET_CACHE */
@@ -552,13 +551,12 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
                from = (char*)pde - (char*)page_address(page);
        lock_page(page);
        err = mapping->a_ops->prepare_write(NULL, page, from, to);
-       if (err)
-               BUG();
+       BUG_ON(err);
        if (pde)
                pde->rec_len = cpu_to_le16(to-from);
        dir->inode = 0;
        err = ext2_commit_chunk(page, from, to);
-       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
        EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
        mark_inode_dirty(inode);
 out:
@@ -586,6 +584,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
                goto fail;
        }
        kaddr = kmap_atomic(page, KM_USER0);
+       memset(kaddr, 0, chunk_size);
        de = (struct ext2_dir_entry_2 *)kaddr;
        de->name_len = 1;
        de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
@@ -657,10 +656,13 @@ not_empty:
        return 0;
 }
 
-struct file_operations ext2_dir_operations = {
+const struct file_operations ext2_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ext2_readdir,
        .ioctl          = ext2_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ext2_compat_ioctl,
+#endif
        .fsync          = ext2_sync_file,
 };