From fb7f7773c0d96957ca48b07915252615ef66989e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:10:13 -0700 Subject: [PATCH] remove devfs_register From: Christoph Hellwig Whee! devfs_register isn't used anymore in the whole tree and with it some other devfs crap. Kill it for good. --- fs/devfs/base.c | 94 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 93 deletions(-) (limited to 'fs') diff --git a/fs/devfs/base.c b/fs/devfs/base.c index fa63dc1820a5..6ca2544a5322 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -752,6 +752,7 @@ # define DPRINTK(flag, format, args...) #endif +typedef struct devfs_entry *devfs_handle_t; struct directory_type { @@ -1424,98 +1425,6 @@ static void devfsd_notify (struct devfs_entry *de,unsigned short type) current->egid, &fs_info); } - -/** - * devfs_register - Register a device entry. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * new name is relative to the root of the devfs. - * @name: The name of the entry. - * @flags: Must be 0 - * @major: The major number. Not needed for regular files. - * @minor: The minor number. Not needed for regular files. - * @mode: The default file mode. - * @ops: The &file_operations or &block_device_operations structure. - * This must not be externally deallocated. - * @info: An arbitrary pointer which will be written to the @private_data - * field of the &file structure passed to the device driver. You can set - * this to whatever you like, and change it once the file is opened (the next - * file opened will not see this change). - * - * On failure %NULL is returned. - */ - -devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, - unsigned int flags, - unsigned int major, unsigned int minor, - umode_t mode, void *ops, void *info) -{ - int err; - dev_t devnum = 0, dev = MKDEV(major, minor); - struct devfs_entry *de; - - /* we don't accept any flags anymore. prototype will change soon. */ - WARN_ON(flags); - WARN_ON(dir); - WARN_ON(!S_ISCHR(mode)); - - if (name == NULL) - { - PRINTK ("(): NULL name pointer\n"); - return NULL; - } - if (ops == NULL) - { - PRINTK ("(%s): NULL ops pointer\n", name); - return NULL; - } - if ( S_ISDIR (mode) ) - { - PRINTK ("(%s): creating directories is not allowed\n", name); - return NULL; - } - if ( S_ISLNK (mode) ) - { - PRINTK ("(%s): creating symlinks is not allowed\n", name); - return NULL; - } - if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL ) - { - PRINTK ("(%s): could not prepare leaf\n", name); - if (devnum) devfs_dealloc_devnum (mode, devnum); - return NULL; - } - if (S_ISCHR (mode)) { - de->u.cdev.dev = dev; - de->u.cdev.autogen = devnum != 0; - de->u.cdev.ops = ops; - } else if (S_ISBLK (mode)) { - de->u.bdev.dev = dev; - de->u.cdev.autogen = devnum != 0; - } else { - PRINTK ("(%s): illegal mode: %x\n", name, mode); - devfs_put (de); - devfs_put (dir); - return (NULL); - } - de->info = info; - de->inode.uid = 0; - de->inode.gid = 0; - err = _devfs_append_entry(dir, de, NULL); - if (err) - { - PRINTK ("(%s): could not append to parent, err: %d\n", name, err); - devfs_put (dir); - if (devnum) devfs_dealloc_devnum (mode, devnum); - return NULL; - } - DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n", - name, de, dir, dir->name, dir->parent); - devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED); - devfs_put (dir); - return de; -} /* End Function devfs_register */ - - int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) { struct devfs_entry *dir = NULL, *de; @@ -1935,7 +1844,6 @@ static int __init devfs_setup (char *str) __setup("devfs=", devfs_setup); EXPORT_SYMBOL(devfs_put); -EXPORT_SYMBOL(devfs_register); EXPORT_SYMBOL(devfs_mk_symlink); EXPORT_SYMBOL(devfs_mk_dir); EXPORT_SYMBOL(devfs_remove); -- cgit v1.2.3 From a3db5a33a37367163b9ad7b45c7b8378f82e3fb8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:10:30 -0700 Subject: [PATCH] fat cluster search speedup From: Bjorn Stenberg OGAWA Hirofumi This simple patch makes the linux fat filesystem driver use the next_cluster field in the fat_boot_fsinfo structure. This field is a hint where to start looking for free clusters. Using this field makes a big difference for disks connected over slow links such as USB 1.1. Finding the first free cluster on a 40gig fat-formatted usb disk can today take several minutes. This patch cuts it down to a fraction of a second. Also, commit the next_cluster search hint toand from the superblock in write_super/fill_super. --- fs/fat/inode.c | 1 + fs/fat/misc.c | 17 +++++++++++------ include/linux/msdos_fs.h | 3 +-- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 866edb62fad5..282c0c22db6f 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -897,6 +897,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, sbi->fsinfo_sector); } else { sbi->free_clusters = CF_LE_L(fsinfo->free_clusters); + sbi->prev_free = CF_LE_L(fsinfo->next_cluster); } brelse(fsinfo_bh); diff --git a/fs/fat/misc.c b/fs/fat/misc.c index f7043d09f086..6e3e86c8899b 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -74,6 +74,7 @@ void fat_clusters_flush(struct super_block *sb) MSDOS_SB(sb)->fsinfo_sector); } else { fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters); + fsinfo->next_cluster = CF_LE_L(MSDOS_SB(sb)->prev_free); mark_buffer_dirty(bh); } brelse(bh); @@ -130,19 +131,23 @@ int fat_add_cluster(struct inode *inode) unlock_fat(sb); return -ENOSPC; } - limit = MSDOS_SB(sb)->clusters; - for (count = 0; count < limit; count++) { - nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2; + + limit = MSDOS_SB(sb)->clusters + 2; + nr = MSDOS_SB(sb)->prev_free + 1; + for (count = 0; count < MSDOS_SB(sb)->clusters; count++, nr++) { + nr = nr % limit; + if (nr < 2) + nr = 2; if (fat_access(sb, nr, -1) == FAT_ENT_FREE) break; } - if (count >= limit) { + if (count >= MSDOS_SB(sb)->clusters) { MSDOS_SB(sb)->free_clusters = 0; unlock_fat(sb); return -ENOSPC; } - - MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit; + MSDOS_SB(sb)->prev_free = nr; + fat_access(sb, nr, FAT_ENT_EOF); if (MSDOS_SB(sb)->free_clusters != -1) MSDOS_SB(sb)->free_clusters--; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 2945cb406b64..bd09a8135e79 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -146,8 +146,7 @@ struct fat_boot_fsinfo { __u32 reserved1[120]; /* Nothing as far as I can tell */ __u32 signature2; /* 0x61417272L */ __u32 free_clusters; /* Free cluster count. -1 if unknown */ - __u32 next_cluster; /* Most recently allocated cluster. - * Unused under Linux. */ + __u32 next_cluster; /* Most recently allocated cluster */ __u32 reserved2[4]; }; -- cgit v1.2.3 From c47b79715dba151cfe016f3c138269df86a69e21 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:11:15 -0700 Subject: [PATCH] Quota write transaction size fix From: Jan Kara I'm sending a patch which changes numbers of blocks reserved for quota writes to more appropriate values (with current values ext3 asserts can be triggered). --- fs/ext3/super.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 532c501e7396..8c72318360b7 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1988,8 +1988,10 @@ int ext3_statfs (struct super_block * sb, struct statfs * buf) #ifdef CONFIG_QUOTA -#define EXT3_OLD_QFMT_BLOCKS 2 -#define EXT3_V0_QFMT_BLOCKS 6 +/* Blocks: (2 data blocks) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */ +#define EXT3_OLD_QFMT_BLOCKS 11 +/* Blocks: quota info + (4 pointer blocks + 1 entry block) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */ +#define EXT3_V0_QFMT_BLOCKS 27 static int (*old_sync_dquot)(struct dquot *dquot); -- cgit v1.2.3 From ed0994daf813d8d3bbef70ab7fb231294c17469e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:11:23 -0700 Subject: [PATCH] dquot_transfer() fix From: Jan Kara I'm sending a fix which fixes potential problems (dropping references which were not acquired) when dquot_transfer() fails. --- fs/dquot.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/dquot.c b/fs/dquot.c index f3c0f63265c3..edda8c2009d6 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1011,9 +1011,12 @@ warn_put_all: spin_unlock(&dq_data_lock); flush_warnings(transfer_to, warntype); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (transfer_from[cnt] != NODQUOT) + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (ret == QUOTA_OK && transfer_from[cnt] != NODQUOT) dqput(transfer_from[cnt]); + if (ret == NO_QUOTA && transfer_to[cnt] != NODQUOT) + dqput(transfer_to[cnt]); + } up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); return ret; } -- cgit v1.2.3 From 7a2a76556858202cbaf61ccab47adf97e96ce870 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:12:17 -0700 Subject: [PATCH] provide user feedback for emergency sync and remount People like to see when the emergency sync and emergency remount operations have completed. --- fs/buffer.c | 2 ++ fs/super.c | 1 + 2 files changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/buffer.c b/fs/buffer.c index f380aa531352..abb476e7679e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -253,6 +253,8 @@ static void do_sync(unsigned long wait) sync_filesystems(0); /* Start syncing the filesystems */ sync_filesystems(wait); /* Waitingly sync the filesystems */ sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ + if (!wait) + printk("Emergency Sync complete\n"); } asmlinkage long sys_sync(void) diff --git a/fs/super.c b/fs/super.c index 58f90ef3a2b9..eba1a860a141 100644 --- a/fs/super.c +++ b/fs/super.c @@ -497,6 +497,7 @@ static void do_emergency_remount(unsigned long foo) spin_lock(&sb_lock); } spin_unlock(&sb_lock); + printk("Emergency Remount complete\n"); } void emergency_remount(void) -- cgit v1.2.3 From 2c227ffa7357467c36e163eba9d51d25093dc65b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:12:52 -0700 Subject: [PATCH] Reserve the ext2/ext3 EAs for the Lustre filesystem From: Andreas Dilger Below are the patches which reserve the Lustre EA index. The rest of the code is part of the Lustre tree, which isn't working with 2.5 yet. --- fs/ext2/xattr.h | 1 + fs/ext3/xattr.h | 1 + 2 files changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index a57b9da2306d..a113ead4adf9 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -22,6 +22,7 @@ #define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 #define EXT2_XATTR_INDEX_TRUSTED 4 +#define EXT2_XATTR_INDEX_LUSTRE 5 #define EXT2_XATTR_INDEX_SECURITY 6 struct ext2_xattr_header { diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index 8de7046ed175..9c71433c6a90 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -21,6 +21,7 @@ #define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 #define EXT3_XATTR_INDEX_TRUSTED 4 +#define EXT3_XATTR_INDEX_LUSTRE 5 #define EXT3_XATTR_INDEX_SECURITY 6 struct ext3_xattr_header { -- cgit v1.2.3 From 7c6d1fb921222a0f1d10b9305d6d09546c76fe8e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:13:10 -0700 Subject: [PATCH] Fix ext3 htree / NFS compatibility problems Patch from "Theodore Ts'o" The following patch should (in theory) fix the htree/NFS readdir problems that people have reported. Specifically, it should fix the NFS looping on EOF problem with readdir, as well as the problems caused by coverting a directory to HTREE while an NFS readdir is in progress problem. I'd appreciate it if people who can easily replicate these NFS/htree problems could give this patch (against BK-recent / 2.5.63) a whirl. Thanks!! --- fs/ext3/dir.c | 18 ++++++++- fs/ext3/namei.c | 118 +++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 98 insertions(+), 38 deletions(-) (limited to 'fs') diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 1b5fae0032f2..4e73022d7637 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -103,7 +103,11 @@ static int ext3_readdir(struct file * filp, sb = inode->i_sb; - if (is_dx(inode)) { +#ifdef CONFIG_EXT3_INDEX + if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb, + EXT3_FEATURE_COMPAT_DIR_INDEX) && + ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) || + ((inode->i_size >> sb->s_blocksize_bits) == 1))) { err = ext3_dx_readdir(filp, dirent, filldir); if (err != ERR_BAD_DX_DIR) { ret = err; @@ -115,6 +119,7 @@ static int ext3_readdir(struct file * filp, */ EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; } +#endif stored = 0; bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); @@ -434,6 +439,9 @@ static int ext3_dx_readdir(struct file * filp, filp->private_data = info; } + if (filp->f_pos == -1) + return 0; /* EOF */ + /* Some one has messed with f_pos; reset the world */ if (info->last_pos != filp->f_pos) { free_rb_tree_fname(&info->root); @@ -470,8 +478,10 @@ static int ext3_dx_readdir(struct file * filp, &info->next_hash); if (ret < 0) return ret; - if (ret == 0) + if (ret == 0) { + filp->f_pos = -1; break; + } info->curr_node = rb_first(&info->root); } @@ -483,6 +493,10 @@ static int ext3_dx_readdir(struct file * filp, info->curr_node = rb_next(info->curr_node); if (!info->curr_node) { + if (info->next_hash == ~0) { + filp->f_pos = -1; + break; + } info->curr_hash = info->next_hash; info->curr_minor_hash = 0; } diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 34218818c69d..ea83d3cb7bec 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -170,7 +170,7 @@ static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size); static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block); static int ext3_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, - struct dx_frame *frames, int *err, + struct dx_frame *frames, __u32 *start_hash); static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, struct ext3_dir_entry_2 **res_dir, int *err); @@ -239,6 +239,17 @@ static inline unsigned dx_node_limit (struct inode *dir) * Debug */ #ifdef DX_DEBUG +static void dx_show_index (char * label, struct dx_entry *entries) +{ + int i, n = dx_get_count (entries); + printk("%s index ", label); + for (i = 0; i < n; i++) + { + printk("%x->%u ", i? dx_get_hash(entries + i): 0, dx_get_block(entries + i)); + } + printk("\n"); +} + struct stats { unsigned names; @@ -447,22 +458,21 @@ static void dx_release (struct dx_frame *frames) * * This function returns 1 if the caller should continue to search, * or 0 if it should not. If there is an error reading one of the - * index blocks, it will return -1. + * index blocks, it will a negative error code. * * If start_hash is non-null, it will be filled in with the starting * hash of the next page. */ static int ext3_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, - struct dx_frame *frames, int *err, + struct dx_frame *frames, __u32 *start_hash) { struct dx_frame *p; struct buffer_head *bh; - int num_frames = 0; + int err, num_frames = 0; __u32 bhash; - *err = ENOENT; p = frame; /* * Find the next leaf page by incrementing the frame pointer. @@ -500,8 +510,8 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash, */ while (num_frames--) { if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at), - 0, err))) - return -1; /* Failure */ + 0, &err))) + return err; /* Failure */ p++; brelse (p->bh); p->bh = bh; @@ -519,6 +529,46 @@ static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 * return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len)); } +/* + * This function fills a red-black tree with information from a + * directory block. It returns the number directory entries loaded + * into the tree. If there is an error it is returned in err. + */ +static int htree_dirblock_to_tree(struct file *dir_file, + struct inode *dir, int block, + struct dx_hash_info *hinfo, + __u32 start_hash, __u32 start_minor_hash) +{ + struct buffer_head *bh; + struct ext3_dir_entry_2 *de, *top; + int err, count = 0; + + dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); + if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) + return err; + + de = (struct ext3_dir_entry_2 *) bh->b_data; + top = (struct ext3_dir_entry_2 *) ((char *) de + + dir->i_sb->s_blocksize - + EXT3_DIR_REC_LEN(0)); + for (; de < top; de = ext3_next_entry(de)) { + ext3fs_dirhash(de->name, de->name_len, hinfo); + if ((hinfo->hash < start_hash) || + ((hinfo->hash == start_hash) && + (hinfo->minor_hash < start_minor_hash))) + continue; + if ((err = ext3_htree_store_dirent(dir_file, + hinfo->hash, hinfo->minor_hash, de)) != 0) { + brelse(bh); + return err; + } + count++; + } + brelse(bh); + return count; +} + + /* * This function fills a red-black tree with information from a * directory. We start scanning the directory in hash order, starting @@ -531,8 +581,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash, __u32 *next_hash) { struct dx_hash_info hinfo; - struct buffer_head *bh; - struct ext3_dir_entry_2 *de, *top; + struct ext3_dir_entry_2 *de; struct dx_frame frames[2], *frame; struct inode *dir; int block, err; @@ -543,6 +592,14 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, start_minor_hash)); dir = dir_file->f_dentry->d_inode; + if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { + hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; + hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; + count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, + start_hash, start_minor_hash); + *next_hash = ~0; + return count; + } hinfo.hash = start_hash; hinfo.minor_hash = 0; frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err); @@ -562,34 +619,21 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, while (1) { block = dx_get_block(frame->at); - dxtrace(printk("Reading block %d\n", block)); - if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) + ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo, + start_hash, start_minor_hash); + if (ret < 0) { + err = ret; goto errout; - - de = (struct ext3_dir_entry_2 *) bh->b_data; - top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize - - EXT3_DIR_REC_LEN(0)); - for (; de < top; de = ext3_next_entry(de)) { - ext3fs_dirhash(de->name, de->name_len, &hinfo); - if ((hinfo.hash < start_hash) || - ((hinfo.hash == start_hash) && - (hinfo.minor_hash < start_minor_hash))) - continue; - if ((err = ext3_htree_store_dirent(dir_file, - hinfo.hash, hinfo.minor_hash, de)) != 0) { - brelse(bh); - goto errout; - } - count++; } - brelse (bh); - hashval = ~1; + count += ret; + hashval = ~0; ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, - frame, frames, &err, &hashval); - if (next_hash) - *next_hash = hashval; - if (ret == -1) + frame, frames, &hashval); + *next_hash = hashval; + if (ret < 0) { + err = ret; goto errout; + } /* * Stop if: (a) there are no more entries, or * (b) we have inserted at least one entry and the @@ -600,7 +644,8 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, break; } dx_release(frames); - dxtrace(printk("Fill tree: returned %d entries\n", count)); + dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", + count, *next_hash)); return count; errout: dx_release(frames); @@ -909,11 +954,12 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, brelse (bh); /* Check to see if we should continue to search */ retval = ext3_htree_next_block(dir, hash, frame, - frames, err, 0); - if (retval == -1) { + frames, 0); + if (retval < 0) { ext3_warning(sb, __FUNCTION__, "error reading index page in directory #%lu", dir->i_ino); + *err = retval; goto errout; } } while (retval == 1); -- cgit v1.2.3 From 699155e3a63c395c1769769a06ad0284db7a95dd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:13:18 -0700 Subject: [PATCH] htree nfs fix Patch from "Theodore Ts'o" We now use 0x7ffffff as the EOF cookie, because Linux NFS stupidly interprets the cookie (which is supposed to be a bag of bits without necessarily any semantic value) as a signed 64 bit integer, and then converts it to a unsigned integer, and then blows up if it cannot be expressed be expressed as a 32-bit value!! In order to do this, we have to fold the hash value 0x7ffffff into the hash value 0x7ffffffe. This is relatively safe; the only time we will lose if the directory contains filenames that hash to both 0x7ffffffe and 0x7fffffff (under the original hash), and the last directory entry which hashes to 0x7ffffffe is at the end of a leaf block, and the first directory entry which hashes to 0x7fffffff is at the beginning of a leaf block. --- fs/ext3/dir.c | 6 +++--- fs/ext3/hash.c | 5 ++++- include/linux/ext3_fs.h | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 4e73022d7637..2b387b5649e1 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -439,7 +439,7 @@ static int ext3_dx_readdir(struct file * filp, filp->private_data = info; } - if (filp->f_pos == -1) + if (filp->f_pos == EXT3_HTREE_EOF) return 0; /* EOF */ /* Some one has messed with f_pos; reset the world */ @@ -479,7 +479,7 @@ static int ext3_dx_readdir(struct file * filp, if (ret < 0) return ret; if (ret == 0) { - filp->f_pos = -1; + filp->f_pos = EXT3_HTREE_EOF; break; } info->curr_node = rb_first(&info->root); @@ -494,7 +494,7 @@ static int ext3_dx_readdir(struct file * filp, info->curr_node = rb_next(info->curr_node); if (!info->curr_node) { if (info->next_hash == ~0) { - filp->f_pos = -1; + filp->f_pos = EXT3_HTREE_EOF; break; } info->curr_hash = info->next_hash; diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index 2025354b85de..d00d658b1cfb 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -209,7 +209,10 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) hinfo->hash = 0; return -1; } - hinfo->hash = hash & ~1; + hash = hash & ~1; + if (hash == (EXT3_HTREE_EOF << 1)) + hash = (EXT3_HTREE_EOF-1) << 1; + hinfo->hash = hash; hinfo->minor_hash = minor_hash; return 0; } diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index b3da32479e13..c2f36c9d8022 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -625,6 +625,8 @@ struct dx_hash_info u32 *seed; }; +#define EXT3_HTREE_EOF 0x7fffffff + #ifdef __KERNEL__ /* * Control parameters used by ext3_htree_next_block -- cgit v1.2.3 From 2d10c0bb22040afab5bb81792fb890823d02cab7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 12 May 2003 09:13:27 -0700 Subject: [PATCH] ext3: htree memory leak fix From Alex Tomas We started using ext3_dx_readdir() for all dir_index filesystems, because we want to return entries in hash order always, so that readdir with a partial read + new entry added before next readdir won't be crazy. So we now need to free the structure at filp->pricate_data even against non-indexed directories. --- fs/ext3/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 2b387b5649e1..b00bec6fe0ce 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -509,7 +509,7 @@ finished: static int ext3_release_dir (struct inode * inode, struct file * filp) { - if (is_dx(inode) && filp->private_data) + if (filp->private_data) ext3_htree_free_dir_info(filp->private_data); return 0; -- cgit v1.2.3