aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r--fs/gfs2/ops_inode.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 35f6f032a026..534e1e2c65ca 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -589,6 +589,54 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
589 return 0; 589 return 0;
590} 590}
591 591
592/*
593 * gfs2_ok_to_move - check if it's ok to move a directory to another directory
594 * @this: move this
595 * @to: to here
596 *
597 * Follow @to back to the root and make sure we don't encounter @this
598 * Assumes we already hold the rename lock.
599 *
600 * Returns: errno
601 */
602
603static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
604{
605 struct inode *dir = &to->i_inode;
606 struct super_block *sb = dir->i_sb;
607 struct inode *tmp;
608 struct qstr dotdot;
609 int error = 0;
610
611 gfs2_str2qstr(&dotdot, "..");
612
613 igrab(dir);
614
615 for (;;) {
616 if (dir == &this->i_inode) {
617 error = -EINVAL;
618 break;
619 }
620 if (dir == sb->s_root->d_inode) {
621 error = 0;
622 break;
623 }
624
625 tmp = gfs2_lookupi(dir, &dotdot, 1);
626 if (IS_ERR(tmp)) {
627 error = PTR_ERR(tmp);
628 break;
629 }
630
631 iput(dir);
632 dir = tmp;
633 }
634
635 iput(dir);
636
637 return error;
638}
639
592/** 640/**
593 * gfs2_rename - Rename a file 641 * gfs2_rename - Rename a file
594 * @odir: Parent directory of old file name 642 * @odir: Parent directory of old file name
@@ -607,7 +655,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
607 struct gfs2_inode *ip = GFS2_I(odentry->d_inode); 655 struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
608 struct gfs2_inode *nip = NULL; 656 struct gfs2_inode *nip = NULL;
609 struct gfs2_sbd *sdp = GFS2_SB(odir); 657 struct gfs2_sbd *sdp = GFS2_SB(odir);
610 struct gfs2_holder ghs[5], r_gh; 658 struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
611 struct gfs2_rgrpd *nrgd; 659 struct gfs2_rgrpd *nrgd;
612 unsigned int num_gh; 660 unsigned int num_gh;
613 int dir_rename = 0; 661 int dir_rename = 0;
@@ -621,19 +669,20 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
621 return 0; 669 return 0;
622 } 670 }
623 671
624 /* Make sure we aren't trying to move a dirctory into it's subdir */
625 672
626 if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) { 673 if (odip != ndip) {
627 dir_rename = 1; 674 error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
628 675 0, &r_gh);
629 error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0,
630 &r_gh);
631 if (error) 676 if (error)
632 goto out; 677 goto out;
633 678
634 error = gfs2_ok_to_move(ip, ndip); 679 if (S_ISDIR(ip->i_inode.i_mode)) {
635 if (error) 680 dir_rename = 1;
636 goto out_gunlock_r; 681 /* don't move a dirctory into it's subdir */
682 error = gfs2_ok_to_move(ip, ndip);
683 if (error)
684 goto out_gunlock_r;
685 }
637 } 686 }
638 687
639 num_gh = 1; 688 num_gh = 1;
@@ -829,7 +878,7 @@ out_gunlock:
829 gfs2_holder_uninit(ghs + x); 878 gfs2_holder_uninit(ghs + x);
830 } 879 }
831out_gunlock_r: 880out_gunlock_r:
832 if (dir_rename) 881 if (r_gh.gh_gl)
833 gfs2_glock_dq_uninit(&r_gh); 882 gfs2_glock_dq_uninit(&r_gh);
834out: 883out:
835 return error; 884 return error;