ext4: add ioctl to force 32-bit hashes from indexed dirs
RFC PATCH 1/1 ext4: add ioctl to force 32-bit hashes from indexed dirs
This adds a new ioctl, EXT4_IOC_32BITHASH, which allows a userspace application to request 32-bit rather than 64-bit hashes from readdir on an indexed / dx / htree directory.
Gluster had been relying on the top bits of the d_off being free; there are some reports that filling all 64 bits breaks Samba as well. The infrastructure to return 32-bit hashes already exists; NFS can turn it on, and it's turned on for 32-bit processes as well. So it's just a matter of flipping on the f_mode flag before readdir starts.
Care needs to be taken that we don't change the FMODE flag after readdir has been started, so we make sure that filp->private_data has not yet been set before we set the flag (Thanks Zach!).
---
fs/ext4/dir.c +1 -1
@@ -39,7 +39,7 @@ static int ext4_dx_readdir(struct file *filp,* * Return 1 if it is a dx dir, 0 if not */ -static int is_dx_dir (struct inode *inode) +int is_dx_dir (struct inode *inode) {struct super_block *sb = inode->i_sb;
fs/ext4/ext4.h +2 -0
@@ -614,6 +614,7 @@ enum {/* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) +#define EXT4_IOC_32BITHASH _IOW('f', 13, long)#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
@@ -1953,6 +1954,7 @@ extern unsigned ext4_num_overhead_clusters(struct super_block *sb,ext4_fsblk_t ext4_inode_to_goal_block (struct inode *);/* dir.c */ +extern int is_dx_dir (struct inode *inode); extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, struct file *, struct ext4_dir_entry_2 *,
fs/ext4/ioctl.c +34 -0
@@ -356,7 +356,41 @@ group_add_out:mnt_drop_write_file (filp);return err; } +case EXT4_IOC_32BITHASH : { +__u32 hash32bits; +int err =0 ; +if (get_user (hash32bits, (int __user *) arg)) +return -EFAULT ; + +/* Serialize with readdir */ +if ((err =mutex_lock_killable (&inode->i_mutex))) +return err; + +/* protect f_mode */ +spin_lock (&filp->f_lock); + +/* Only valid for htree directories */ +if (!S_ISDIR (inode->i_mode) || !is_dx_dir (inode)) { + err = -EINVAL ; + goto out_32bithash; + } + +/* Have we already started readir on this dx dir? */ +if (filp->private_data) { + err = -EINVAL ; + goto out_32bithash; + } + +if (hash32bits) + filp->f_mode |=FMODE_32BITHASH ; +else + filp->f_mode &= ~FMODE_32BITHASH ; +out_32bithash: +spin_unlock (&filp->f_lock); +mutex_unlock (&inode->i_mutex); +return err; + }case EXT4_IOC_RESIZE_FS : {ext4_fsblk_t n_blocks_count;struct super_block *sb = inode->i_sb;
Hello Eric,
thanks, I'm going to review it thouroughly tomorrow again. Just noticed a small typo in a comment.
fs/ext4/ioctl.c group_add_out: · line 379
Quoted 1 line · Eric Sandeen
fs/ext4/ioctl.c +1
-0+/* Have we already started readir on this dx dir? */
^^^^^^
Cheers,
Bernd
Quoted 11 lines · Eric Sandeen
This adds a new ioctl,
EXT4_IOC_32BITHASH, which allows a userspace application to request 32-bit rather than 64-bit hashes from readdir on an indexed / dx / htree directory.Gluster had been relying on the top bits of the
d_offbeing free; there are some reports that filling all 64 bits breaks Samba as well. The infrastructure to return 32-bit hashes already exists; NFS can turn it on, and it's turned on for 32-bit processes as well. So it's just a matter of flipping on thef_modeflag before readdir starts.
Quoted 4 lines
Care needs to be taken that we don't change the FMODE flag after readdir has been started, so we make sure that
filp->private_datahas not yet been set before we set the flag (Thanks Zach!).
Hm, it crosses my mind that the ability to send 0/1 to the ioctl may be pointless, perhaps it should be an _IO not _IOW; since once we have started readdir we will return -EINVAL, I'm not sure we'd ever have occasion to turn 32-bit hashing back "off."
-Eric
Quoted 89 lines
Pre-submission-fixes-by Zach Brown <[email protected]>Signed-off-by Eric Sandeen <[email protected]>---
fs/ext4/dir.c +1
-1@@ -39,7 +39,7 @@ static int ext4_dx_readdir(struct file *filp,* * Return 1 if it is a dx dir, 0 if not */ -static int is_dx_dir (struct inode *inode) +int is_dx_dir (struct inode *inode) {struct super_block *sb = inode->i_sb;fs/ext4/ext4.h +2
-0@@ -614,6 +614,7 @@ enum {/* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) +#define EXT4_IOC_32BITHASH _IOW('f', 13, long)#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)@@ -1953,6 +1954,7 @@ extern unsigned ext4_num_overhead_clusters(struct super_block *sb,ext4_fsblk_t ext4_inode_to_goal_block (struct inode *);/* dir.c */ +extern int is_dx_dir (struct inode *inode); extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, struct file *, struct ext4_dir_entry_2 *,fs/ext4/ioctl.c +34
-1@@ -356,7 +356,41 @@ group_add_out:mnt_drop_write_file (filp);return err; } +case EXT4_IOC_32BITHASH : { +__u32 hash32bits; +int err =0 ; +if (get_user (hash32bits, (int __user *) arg)) +return -EFAULT ; + +/* Serialize with readdir */ +if ((err =mutex_lock_killable (&inode->i_mutex))) +return err; + +/* protect f_mode */ +spin_lock (&filp->f_lock); + +/* Only valid for htree directories */ +if (!S_ISDIR (inode->i_mode) || !is_dx_dir (inode)) { + err = -EINVAL ; + goto out_32bithash; + } + +/* Have we already started readir on this dx dir? */ +if (filp->private_data) { + err = -EINVAL ; + goto out_32bithash; + } + +if (hash32bits) + filp->f_mode |=FMODE_32BITHASH ; +else + filp->f_mode &= ~FMODE_32BITHASH ; +out_32bithash: +spin_unlock (&filp->f_lock); +mutex_unlock (&inode->i_mutex); +return err; + }case EXT4_IOC_RESIZE_FS : {ext4_fsblk_t n_blocks_count;struct super_block *sb = inode->i_sb; --To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
RFC PATCH v2 1/1 ext4: add ioctl to force 32-bit hashes from indexed dirs
In reply to Eric SandeenThis adds a new ioctl, EXT4_IOC_32BITHASH, which allows a userspace application to request 32-bit rather than 64-bit hashes from readdir on an indexed / dx / htree directory.
Gluster had been relying on the top bits of the d_off being free; there are some reports that filling all 64 bits breaks Samba as well. The infrastructure to return 32-bit hashes already exists; NFS can turn it on, and it's turned on for 32-bit processes as well. So it's just a matter of flipping on the f_mode flag before readdir starts.
Care needs to be taken that we don't change the FMODE flag after readdir has been started, so we make sure that filp->private_data has not yet been set before we set the flag. (Thanks Zach!).
---
V2:
fix "readir" typo
rename goto target to *_out like others
remove parameter; we can't really ever turn this back off once it's used. closing and reopening is the only way to get back to 64 bit hashes.
fs/ext4/dir.c +1 -1
@@ -39,7 +39,7 @@ static int ext4_dx_readdir(struct file *filp,* * Return 1 if it is a dx dir, 0 if not */ -static int is_dx_dir (struct inode *inode) +int is_dx_dir (struct inode *inode) {struct super_block *sb = inode->i_sb;
fs/ext4/ext4.h +2 -0
@@ -614,6 +614,7 @@ enum {/* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) +#define EXT4_IOC_32BITHASH _IO('f', 13)#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
@@ -1953,6 +1954,7 @@ extern unsigned ext4_num_overhead_clusters(struct super_block *sb,ext4_fsblk_t ext4_inode_to_goal_block (struct inode *);/* dir.c */ +extern int is_dx_dir (struct inode *inode); extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, struct file *, struct ext4_dir_entry_2 *,
fs/ext4/ioctl.c +27 -0
@@ -356,7 +356,34 @@ group_add_out:mnt_drop_write_file (filp);return err; } +case EXT4_IOC_32BITHASH : { +int err =0 ; +/* Serialize with readdir */ +if ((err =mutex_lock_killable (&inode->i_mutex))) +return err; + +/* protect f_mode */ +spin_lock (&filp->f_lock); + +/* Only valid for htree directories */ +if (!S_ISDIR (inode->i_mode) || !is_dx_dir (inode)) { + err = -EINVAL ; + goto hash32bits_out; + } + +/* Have we already started readdir on this dx dir? */ +if (filp->private_data) { + err = -EINVAL ; + goto hash32bits_out; + } + + filp->f_mode |=FMODE_32BITHASH ; +hash32bits_out: +spin_unlock (&filp->f_lock); +mutex_unlock (&inode->i_mutex); +return err; + }case EXT4_IOC_RESIZE_FS : {ext4_fsblk_t n_blocks_count;struct super_block *sb = inode->i_sb;
RFC PATCH v3 1/1 ext4: add ioctl to force 32-bit hashes from indexed dirs
This adds a new ioctl, EXT4_IOC_32BITHASH, which allows a userspace application to request 32-bit rather than 64-bit hashes from readdir on an indexed / dx / htree directory.
Gluster had been relying on the top bits of the d_off being free; there are some reports that filling all 64 bits breaks Samba as well. The infrastructure to return 32-bit hashes already exists; NFS can turn it on, and it's turned on for 32-bit processes as well. So it's just a matter of flipping on the f_mode flag before readdir starts.
Care needs to be taken that we don't change the FMODE flag after readdir has been started, so we make sure that filp->private_data has not yet been set before we set the flag. (Thanks Zach!).
---
V2:
fix "readir" typo
rename goto target to *_out like others
remove parameter; we can't really ever turn this back off once it's used. closing and reopening is the only way to get back to 64 bit hashes.
V3:
return -ENOTDIR if the target is not a directory
fs/ext4/dir.c +1 -1
@@ -39,7 +39,7 @@ static int ext4_dx_readdir(struct file *filp,* * Return 1 if it is a dx dir, 0 if not */ -static int is_dx_dir (struct inode *inode) +int is_dx_dir (struct inode *inode) {struct super_block *sb = inode->i_sb;
fs/ext4/ext4.h +2 -0
@@ -614,6 +614,7 @@ enum {/* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) +#define EXT4_IOC_32BITHASH _IO('f', 13)#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
@@ -1953,6 +1954,7 @@ extern unsigned ext4_num_overhead_clusters(struct super_block *sb,ext4_fsblk_t ext4_inode_to_goal_block (struct inode *);/* dir.c */ +extern int is_dx_dir (struct inode *inode); extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, struct file *, struct ext4_dir_entry_2 *,
fs/ext4/ioctl.c +32 -0
@@ -356,7 +356,39 @@ group_add_out:mnt_drop_write_file (filp);return err; } +case EXT4_IOC_32BITHASH : { +int err =0 ; +/* Serialize with readdir */ +if ((err =mutex_lock_killable (&inode->i_mutex))) +return err; + +/* protect f_mode */ +spin_lock (&filp->f_lock); + +/* Only valid for htree directories */ +if (!S_ISDIR (inode->i_mode)) { + err = -ENOTDIR ; + goto hash32bits_out; + } + +if (!is_dx_dir (inode)) { + err = -EINVAL ; + goto hash32bits_out; + } + +/* Have we already started readdir on this dx dir? */ +if (filp->private_data) { + err = -EINVAL ; + goto hash32bits_out; + } + + filp->f_mode |=FMODE_32BITHASH ; +hash32bits_out: +spin_unlock (&filp->f_lock); +mutex_unlock (&inode->i_mutex); +return err; + }case EXT4_IOC_RESIZE_FS : {ext4_fsblk_t n_blocks_count;struct super_block *sb = inode->i_sb;