GFS2: Make rename not save dirent location
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 GFS2: Make rename not save dirent location
Hi,
This patch fixes a regression in the patch "GFS2: Remember directory insert point", commit 2b47dad866d04f14c328f888ba5406057b8c7d33. The problem had to do with the rename function: The function found space for the new dirent, and remembered that location. But then the old dirent was removed, which often moved the eligible location for the renamed dirent. Putting the new dirent at the saved location caused file system corruption.
This patch adds a new "save_loc" variable to struct gfs2_diradd. If 1, the dirent location is saved. If 0, the dirent location is not saved and the buffer_head is released as per previous behavior.
Regards,
Bob Peterson
Red Hat File Systems
---
fs/gfs2/dir.c +7 -2
@@ -2100,8 +2100,13 @@ int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name, }if (IS_ERR (dent))return PTR_ERR (dent); - da->bh = bh; - da->dent = dent; + +if (da->save_loc) { + da->bh = bh; + da->dent = dent; + }else { +brelse (bh); + }return 0 ; }
fs/gfs2/dir.h +1 -0
@@ -23,6 +23,7 @@ struct gfs2_diradd {unsigned nr_blocks;struct gfs2_dirent *dent;struct buffer_head *bh; +int save_loc; }; extern struct inode *gfs2_dir_search(struct inode *dir,
fs/gfs2/inode.c +3 -3
@@ -600,7 +600,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,int error, free_vfs_inode =0 ;u32 aflags =0 ;unsigned blocks =1 ; -struct gfs2_diradd da = { .bh =NULL , }; +struct gfs2_diradd da = { .bh =NULL , .save_loc =1 , };if (!name->len || name->len >GFS2_FNAMESIZE )return -ENAMETOOLONG ;
@@ -900,7 +900,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,struct gfs2_inode *ip =GFS2_I (inode);struct gfs2_holder ghs[2 ];struct buffer_head *dibh; -struct gfs2_diradd da = { .bh =NULL , }; +struct gfs2_diradd da = { .bh =NULL , .save_loc =1 , };int error;if (S_ISDIR (inode->i_mode))
@@ -1338,7 +1338,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,struct gfs2_rgrpd *nrgd;unsigned int num_gh;int dir_rename =0 ; -struct gfs2_diradd da = { .nr_blocks =0 , }; +struct gfs2_diradd da = { .nr_blocks =0 , .save_loc =0 , };unsigned int x;int error;
PATCH 1/1 GFS2: Make rename not save dirent location
Hi,
Quoted 10 lines · Bob Peterson
Hi,
This patch fixes a regression in the patch "GFS2: Remember directory insert point", commit
2b47dad866d04f14c328f888ba5406057b8c7d33. The problem had to do with the rename function: The function found space for the new dirent, and remembered that location. But then the old dirent was removed, which often moved the eligible location for the renamed dirent. Putting the new dirent at the saved location caused file system corruption.
Quoted 8 lines
This patch adds a new "
save_loc" variable to structgfs2_diradd. If 1, the dirent location is saved. If 0, the dirent location is not saved and thebuffer_headis released as per previous behavior.Regards,
Bob Peterson
Red Hat File Systems
Now in the -nmw git tree. Thanks,
Steve.
Quoted 65 lines
Signed-off-by Bob Peterson <[email protected]>---
fs/gfs2/dir.c +7
-2@@ -2100,8 +2100,13 @@ int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name, }if (IS_ERR (dent))return PTR_ERR (dent); - da->bh = bh; - da->dent = dent; + +if (da->save_loc) { + da->bh = bh; + da->dent = dent; + }else { +brelse (bh); + }return 0 ; }fs/gfs2/dir.h +1
-0@@ -23,6 +23,7 @@ struct gfs2_diradd {unsigned nr_blocks;struct gfs2_dirent *dent;struct buffer_head *bh; +int save_loc; }; extern struct inode *gfs2_dir_search(struct inode *dir,fs/gfs2/inode.c +3
-3@@ -600,7 +600,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,int error, free_vfs_inode =0 ;u32 aflags =0 ;unsigned blocks =1 ; -struct gfs2_diradd da = { .bh =NULL , }; +struct gfs2_diradd da = { .bh =NULL , .save_loc =1 , };if (!name->len || name->len >GFS2_FNAMESIZE )return -ENAMETOOLONG ;@@ -900,7 +900,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,struct gfs2_inode *ip =GFS2_I (inode);struct gfs2_holder ghs[2 ];struct buffer_head *dibh; -struct gfs2_diradd da = { .bh =NULL , }; +struct gfs2_diradd da = { .bh =NULL , .save_loc =1 , };int error;if (S_ISDIR (inode->i_mode))@@ -1338,7 +1338,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,struct gfs2_rgrpd *nrgd;unsigned int num_gh;int dir_rename =0 ; -struct gfs2_diradd da = { .nr_blocks =0 , }; +struct gfs2_diradd da = { .nr_blocks =0 , .save_loc =0 , };unsigned int x;int error;