X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=fs%2Fext3%2Fdir.c;h=665adee99b311fbfce6ada8fb94ee163b4969bc4;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=6611801322ce8e231272a3a18720422ae6f227aa;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 661180132..665adee99 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -39,11 +39,14 @@ static int ext3_dx_readdir(struct file * filp, static int ext3_release_dir (struct inode * inode, struct file * filp); -struct file_operations ext3_dir_operations = { +const struct file_operations ext3_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = ext3_readdir, /* we take BKL. needed?*/ .ioctl = ext3_ioctl, /* BKL held */ +#ifdef CONFIG_COMPAT + .compat_ioctl = ext3_compat_ioctl, +#endif .fsync = ext3_sync_file, /* BKL held */ #ifdef CONFIG_EXT3_INDEX .release = ext3_release_dir, @@ -59,7 +62,7 @@ static unsigned char get_dtype(struct super_block *sb, int filetype) return (ext3_filetype_table[filetype]); } - + int ext3_check_dir_entry (const char * function, struct inode * dir, struct ext3_dir_entry_2 * de, @@ -67,7 +70,7 @@ int ext3_check_dir_entry (const char * function, struct inode * dir, unsigned long offset) { const char * error_msg = NULL; - const int rlen = le16_to_cpu(de->rec_len); + const int rlen = le16_to_cpu(de->rec_len); if (rlen < EXT3_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; @@ -95,13 +98,12 @@ static int ext3_readdir(struct file * filp, void * dirent, filldir_t filldir) { int error = 0; - unsigned long offset, blk; - int i, num, stored; - struct buffer_head * bh, * tmp, * bha[16]; - struct ext3_dir_entry_2 * de; - struct super_block * sb; + unsigned long offset; + int i, stored; + struct ext3_dir_entry_2 *de; + struct super_block *sb; int err; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; int ret = 0; sb = inode->i_sb; @@ -120,16 +122,34 @@ static int ext3_readdir(struct file * filp, * We don't set the inode dirty flag since it's not * critical that it get flushed back to the disk. */ - EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; + EXT3_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; } #endif stored = 0; - bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { - blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb); - bh = ext3_bread(NULL, inode, blk, 0, &err); + unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb); + struct buffer_head map_bh; + struct buffer_head *bh = NULL; + + map_bh.b_state = 0; + err = ext3_get_blocks_handle(NULL, inode, blk, 1, + &map_bh, 0, 0); + if (err > 0) { + page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, + &filp->f_ra, + filp, + map_bh.b_blocknr >> + (PAGE_CACHE_SHIFT - inode->i_blkbits), + 1); + bh = ext3_bread(NULL, inode, blk, 0, &err); + } + + /* + * We ignore I/O errors on directories so users have a chance + * of recovering data when there's a bad sector + */ if (!bh) { ext3_error (sb, "ext3_readdir", "directory #%lu contains a hole at offset %lu", @@ -141,26 +161,6 @@ static int ext3_readdir(struct file * filp, continue; } - /* - * Do the readahead - */ - if (!offset) { - for (i = 16 >> (EXT3_BLOCK_SIZE_BITS(sb) - 9), num = 0; - i > 0; i--) { - tmp = ext3_getblk (NULL, inode, ++blk, 0, &err); - if (tmp && !buffer_uptodate(tmp) && - !buffer_locked(tmp)) - bha[num++] = tmp; - else - brelse (tmp); - } - if (num) { - ll_rw_block (READA, num, bha); - for (i = 0; i < num; i++) - brelse (bha[i]); - } - } - revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid @@ -168,7 +168,7 @@ revalidate: * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext3_dir_entry_2 *) + de = (struct ext3_dir_entry_2 *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -187,7 +187,7 @@ revalidate: filp->f_version = inode->i_version; } - while (!error && filp->f_pos < inode->i_size + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); if (!ext3_check_dir_entry ("ext3_readdir", inode, de, @@ -235,7 +235,7 @@ out: /* * These functions convert from the major/minor hash to an f_pos * value. - * + * * Currently we only use major hash numer. This is unfortunate, but * on 32-bit machines, the same VFS interface is used for lseek and * llseek, so if we use the 64 bit offset, then the 32-bit versions of @@ -256,7 +256,7 @@ out: struct fname { __u32 hash; __u32 minor_hash; - struct rb_node rb_hash; + struct rb_node rb_hash; struct fname *next; __u32 inode; __u8 name_len; @@ -290,7 +290,7 @@ static void free_rb_tree_fname(struct rb_root *root) * beginning of the loop and try to free the parent * node. */ - parent = n->rb_parent; + parent = rb_parent(n); fname = rb_entry(n, struct fname, rb_hash); while (fname) { struct fname * old = fname; @@ -349,10 +349,9 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, /* Create and allocate the fname structure */ len = sizeof(struct fname) + dirent->name_len + 1; - new_fn = kmalloc(len, GFP_KERNEL); + new_fn = kzalloc(len, GFP_KERNEL); if (!new_fn) return -ENOMEM; - memset(new_fn, 0, len); new_fn->hash = hash; new_fn->minor_hash = minor_hash; new_fn->inode = le32_to_cpu(dirent->inode); @@ -403,7 +402,7 @@ static int call_filldir(struct file * filp, void * dirent, { struct dir_private_info *info = filp->private_data; loff_t curr_pos; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct super_block * sb; int error; @@ -416,7 +415,7 @@ static int call_filldir(struct file * filp, void * dirent, curr_pos = hash2pos(fname->hash, fname->minor_hash); while (fname) { error = filldir(dirent, fname->name, - fname->name_len, curr_pos, + fname->name_len, curr_pos, fname->inode, get_dtype(sb, fname->file_type)); if (error) { @@ -433,7 +432,7 @@ static int ext3_dx_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dir_private_info *info = filp->private_data; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct fname *fname; int ret; @@ -471,7 +470,7 @@ static int ext3_dx_readdir(struct file * filp, /* * Fill the rbtree if we have no more entries, * or the inode has changed since we last read in the - * cached entries. + * cached entries. */ if ((!info->curr_node) || (filp->f_version != inode->i_version)) {