GFS2: add support for rename2 and RENAME_EXCHANGE
PATCH 1/1 GFS2: add support for rename2 and RENAME_EXCHANGE
gfs2 now uses the rename2 directory iop, and supports the RENAME_EXCHANGE flag (as well as RENAME_NOREPLACE, which the vfs takes care of).
--- fs/gfs2/inode.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 177 insertions(+), 15 deletions(-)
fs/gfs2/inode.c +177 -15
@@ -1307,6 +1307,35 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) }/** +* update_moved_ino - Update an inode that being moved +* @ip: The inode being moved +* @ndip: The parent directory of the new filename +* @dir_rename: True of ip is a directory +* +* Returns: errno +*/ + +static int update_moved_ino (struct gfs2_inode *ip,struct gfs2_inode *ndip, +int dir_rename) +{ +int error; +struct buffer_head *dibh; + +if (dir_rename) +return gfs2_dir_mvino (ip, &gfs2_qdotdot, ndip,DT_DIR ); + + error =gfs2_meta_inode_buffer (ip, &dibh); +if (error) +return error; + ip->i_inode.i_ctime =CURRENT_TIME ; +gfs2_trans_add_meta (ip->i_gl, dibh); +gfs2_dinode_out (ip, dibh->b_data); +brelse (dibh); +return 0 ; +} + + +/** * gfs2_rename - Rename a file * @odir: Parent directory of old file name * @odentry: The old dentry of the file
@@ -1494,20 +1523,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,if (nip) error =gfs2_unlink_inode (ndip, ndentry); -if (dir_rename) { - error =gfs2_dir_mvino (ip, &gfs2_qdotdot, ndip,DT_DIR ); -if (error) - goto out_end_trans; - }else { -struct buffer_head *dibh; - error =gfs2_meta_inode_buffer (ip, &dibh); -if (error) - goto out_end_trans; - ip->i_inode.i_ctime =CURRENT_TIME ; -gfs2_trans_add_meta (ip->i_gl, dibh); -gfs2_dinode_out (ip, dibh->b_data); -brelse (dibh); - } + error =update_moved_ino (ip, ndip, dir_rename); +if (error) + goto out_end_trans; error =gfs2_dir_del (odip, odentry);if (error)
@@ -1538,6 +1556,150 @@ out:return error; } +static int gfs2_exchange (struct inode *odir,struct dentry *odentry, +struct inode *ndir,struct dentry *ndentry, +unsigned int flags) +{ +struct gfs2_inode *odip =GFS2_I (odir); +struct gfs2_inode *ndip =GFS2_I (ndir); +struct gfs2_inode *oip =GFS2_I (odentry->d_inode); +struct gfs2_inode *nip =GFS2_I (ndentry->d_inode); +struct gfs2_sbd *sdp =GFS2_SB (odir); +struct gfs2_holder ghs[5 ], r_gh = { .gh_gl =NULL , }; +unsigned int num_gh; +unsigned int x; +umode_t old_mode = oip->i_inode.i_mode; +umode_t new_mode = nip->i_inode.i_mode; +int error; + + error =gfs2_rindex_update (sdp); +if (error) +return error; + +if (odip != ndip) { + error =gfs2_glock_nq_init (sdp->sd_rename_gl,LM_ST_EXCLUSIVE , +0 , &r_gh); +if (error) + goto out; + +if (S_ISDIR (old_mode)) { +/* don't move a dirctory into it's subdir */ + error =gfs2_ok_to_move (oip, ndip); +if (error) + goto out_gunlock_r; + } + +if (S_ISDIR (new_mode)) { +/* don't move a dirctory into it's subdir */ + error =gfs2_ok_to_move (nip, odip); +if (error) + goto out_gunlock_r; + } + } + + num_gh =1 ; +gfs2_holder_init (odip->i_gl,LM_ST_EXCLUSIVE ,0 , ghs); +if (odip != ndip) { +gfs2_holder_init (ndip->i_gl,LM_ST_EXCLUSIVE ,0 , ghs + num_gh); + num_gh++; + } +gfs2_holder_init (oip->i_gl,LM_ST_EXCLUSIVE ,0 , ghs + num_gh); + num_gh++; + +gfs2_holder_init (nip->i_gl,LM_ST_EXCLUSIVE ,0 , ghs + num_gh); + num_gh++; + +for (x =0 ; x < num_gh; x++) { + error =gfs2_glock_nq (ghs + x); +if (error) + goto out_gunlock; + } + + error = -ENOENT ; +if (oip->i_inode.i_nlink ==0 || nip->i_inode.i_nlink ==0 ) + goto out_gunlock; + + error =gfs2_unlink_ok (odip, &odentry->d_name, oip); +if (error) + goto out_gunlock; + error =gfs2_unlink_ok (ndip, &ndentry->d_name, nip); +if (error) + goto out_gunlock; + +if (S_ISDIR (old_mode)) { + error =gfs2_permission (odentry->d_inode,MAY_WRITE ); +if (error) + goto out_gunlock; + } +if (S_ISDIR (new_mode)) { + error =gfs2_permission (ndentry->d_inode,MAY_WRITE ); +if (error) + goto out_gunlock; + } + error =gfs2_trans_begin (sdp,4 *RES_DINODE +4 *RES_LEAF ,0 ); +if (error) + goto out_gunlock; + + error =update_moved_ino (oip, ndip,S_ISDIR (old_mode)); +if (error) + goto out_end_trans; + + error =update_moved_ino (nip, odip,S_ISDIR (new_mode)); +if (error) + goto out_end_trans; + + error =gfs2_dir_mvino (ndip, &ndentry->d_name, oip, +IF2DT (old_mode)); +if (error) + goto out_end_trans; + + error =gfs2_dir_mvino (odip, &odentry->d_name, nip, +IF2DT (new_mode)); +if (error) + goto out_end_trans; + +if (odip != ndip) { +if (S_ISDIR (new_mode) && !S_ISDIR (old_mode)) { +inc_nlink (&odip->i_inode); +drop_nlink (&ndip->i_inode); + }else if (S_ISDIR (old_mode) && !S_ISDIR (new_mode)) { +inc_nlink (&ndip->i_inode); +drop_nlink (&odip->i_inode); + } + } +mark_inode_dirty (&ndip->i_inode); +if (odip != ndip) +mark_inode_dirty (&odip->i_inode); + +out_end_trans: +gfs2_trans_end (sdp); +out_gunlock: +while (x--) { +gfs2_glock_dq (ghs + x); +gfs2_holder_uninit (ghs + x); + } +out_gunlock_r: +if (r_gh.gh_gl) +gfs2_glock_dq_uninit (&r_gh); +out: +return error; +} + +static int gfs2_rename2 (struct inode *odir,struct dentry *odentry, +struct inode *ndir,struct dentry *ndentry, +unsigned int flags) +{ + flags &= ~RENAME_NOREPLACE ; + +if (flags & ~RENAME_EXCHANGE ) +return -EINVAL ; + +if (flags &RENAME_EXCHANGE ) +return gfs2_exchange (odir, odentry, ndir, ndentry, flags); + +return gfs2_rename (odir, odentry, ndir, ndentry); +} +/** * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link
@@ -1941,7 +2103,7 @@ const struct inode_operations gfs2_dir_iops = { .mkdir = gfs2_mkdir, .rmdir = gfs2_unlink, .mknod = gfs2_mknod, - .rename = gfs2_rename, + .rename2 = gfs2_rename2, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr,
Signature · 1 line
2.1.0
PATCH 1/1 GFS2: add support for rename2 and RENAME_EXCHANGE
Hi,
Looks good to me except for a few nits:
(snip)
Just a suggestion, but can you add a function comment at the start of this function?
Quoted 25 lines
fs/gfs2/inode.c +25
-0+static int gfs2_exchange (struct inode *odir,struct dentry *odentry, +struct inode *ndir,struct dentry *ndentry, +unsigned int flags) +{ +struct gfs2_inode *odip =GFS2_I (odir); +struct gfs2_inode *ndip =GFS2_I (ndir); +struct gfs2_inode *oip =GFS2_I (odentry->d_inode); +struct gfs2_inode *nip =GFS2_I (ndentry->d_inode); +struct gfs2_sbd *sdp =GFS2_SB (odir); +struct gfs2_holder ghs[5 ], r_gh = { .gh_gl =NULL , }; +unsigned int num_gh; +unsigned int x; +umode_t old_mode = oip->i_inode.i_mode; +umode_t new_mode = nip->i_inode.i_mode; +int error; + + error =gfs2_rindex_update (sdp); +if (error) +return error; + +if (odip != ndip) { + error =gfs2_glock_nq_init (sdp->sd_rename_gl,LM_ST_EXCLUSIVE , +0 , &r_gh); +if (error) + goto out;
fs/gfs2/inode.c out: · line 1593
Quoted 10 lines
fs/gfs2/inode.c +10
-0+ +if (S_ISDIR (old_mode)) { +/* don't move a dirctory into it's subdir */ + error =gfs2_ok_to_move (oip, ndip); +if (error) + goto out_gunlock_r; + } + +if (S_ISDIR (new_mode)) { +/* don't move a dirctory into it's subdir */
Nit: I know this was likely copied from the existing rename code, but can you:
s/dirctory/directory/ and s/it's/its/
Regards,
Bob Peterson
Red Hat File Systems
PATCH v2 1/1 GFS2: add support for rename2 and RENAME_EXCHANGE
In reply to Benjamin Marzinski----- Original Message -----
Quoted 5 lines
gfs2 now uses the rename2 directory iop, and supports the
RENAME_EXCHANGEflag (as well asRENAME_NOREPLACE, which the vfs takes care of).Signed-off-by Benjamin Marzinski <[email protected]>
Hi,
Thanks. V2 patch is now in the upstream tree:
https://git.kernel.org/cgit/linux/kernel/git/gfs2/linux-gfs2.git/commit/fs/gfs2?h=for-next&id=a63b7bbc2175901d79fa36ba734499655c077f0d
Regards,
Bob Peterson
Red Hat File Systems