diff options
Diffstat (limited to 'fs/gfs2/ops_inode.c')
| -rw-r--r-- | fs/gfs2/ops_inode.c | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index e2c62f73a778..534e1e2c65ca 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -159,9 +159,13 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, | |||
| 159 | gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); | 159 | gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); |
| 160 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); | 160 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); |
| 161 | 161 | ||
| 162 | error = gfs2_glock_nq_m(2, ghs); | 162 | error = gfs2_glock_nq(ghs); /* parent */ |
| 163 | if (error) | 163 | if (error) |
| 164 | goto out; | 164 | goto out_parent; |
| 165 | |||
| 166 | error = gfs2_glock_nq(ghs + 1); /* child */ | ||
| 167 | if (error) | ||
| 168 | goto out_child; | ||
| 165 | 169 | ||
| 166 | error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); | 170 | error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); |
| 167 | if (error) | 171 | if (error) |
| @@ -245,8 +249,10 @@ out_alloc: | |||
| 245 | if (alloc_required) | 249 | if (alloc_required) |
| 246 | gfs2_alloc_put(dip); | 250 | gfs2_alloc_put(dip); |
| 247 | out_gunlock: | 251 | out_gunlock: |
| 248 | gfs2_glock_dq_m(2, ghs); | 252 | gfs2_glock_dq(ghs + 1); |
| 249 | out: | 253 | out_child: |
| 254 | gfs2_glock_dq(ghs); | ||
| 255 | out_parent: | ||
| 250 | gfs2_holder_uninit(ghs); | 256 | gfs2_holder_uninit(ghs); |
| 251 | gfs2_holder_uninit(ghs + 1); | 257 | gfs2_holder_uninit(ghs + 1); |
| 252 | if (!error) { | 258 | if (!error) { |
| @@ -302,7 +308,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) | |||
| 302 | 308 | ||
| 303 | error = gfs2_unlink_ok(dip, &dentry->d_name, ip); | 309 | error = gfs2_unlink_ok(dip, &dentry->d_name, ip); |
| 304 | if (error) | 310 | if (error) |
| 305 | goto out_rgrp; | 311 | goto out_gunlock; |
| 306 | 312 | ||
| 307 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); | 313 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); |
| 308 | if (error) | 314 | if (error) |
| @@ -316,6 +322,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) | |||
| 316 | 322 | ||
| 317 | out_end_trans: | 323 | out_end_trans: |
| 318 | gfs2_trans_end(sdp); | 324 | gfs2_trans_end(sdp); |
| 325 | out_gunlock: | ||
| 319 | gfs2_glock_dq(ghs + 2); | 326 | gfs2_glock_dq(ghs + 2); |
| 320 | out_rgrp: | 327 | out_rgrp: |
| 321 | gfs2_holder_uninit(ghs + 2); | 328 | gfs2_holder_uninit(ghs + 2); |
| @@ -485,7 +492,6 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 485 | struct gfs2_holder ri_gh; | 492 | struct gfs2_holder ri_gh; |
| 486 | int error; | 493 | int error; |
| 487 | 494 | ||
| 488 | |||
| 489 | error = gfs2_rindex_hold(sdp, &ri_gh); | 495 | error = gfs2_rindex_hold(sdp, &ri_gh); |
| 490 | if (error) | 496 | if (error) |
| 491 | return error; | 497 | return error; |
| @@ -495,9 +501,17 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 495 | rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); | 501 | rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); |
| 496 | gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); | 502 | gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); |
| 497 | 503 | ||
| 498 | error = gfs2_glock_nq_m(3, ghs); | 504 | error = gfs2_glock_nq(ghs); /* parent */ |
| 499 | if (error) | 505 | if (error) |
| 500 | goto out; | 506 | goto out_parent; |
| 507 | |||
| 508 | error = gfs2_glock_nq(ghs + 1); /* child */ | ||
| 509 | if (error) | ||
| 510 | goto out_child; | ||
| 511 | |||
| 512 | error = gfs2_glock_nq(ghs + 2); /* rgrp */ | ||
| 513 | if (error) | ||
| 514 | goto out_rgrp; | ||
| 501 | 515 | ||
| 502 | error = gfs2_unlink_ok(dip, &dentry->d_name, ip); | 516 | error = gfs2_unlink_ok(dip, &dentry->d_name, ip); |
| 503 | if (error) | 517 | if (error) |
| @@ -523,11 +537,15 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 523 | gfs2_trans_end(sdp); | 537 | gfs2_trans_end(sdp); |
| 524 | 538 | ||
| 525 | out_gunlock: | 539 | out_gunlock: |
| 526 | gfs2_glock_dq_m(3, ghs); | 540 | gfs2_glock_dq(ghs + 2); |
| 527 | out: | 541 | out_rgrp: |
| 528 | gfs2_holder_uninit(ghs); | ||
| 529 | gfs2_holder_uninit(ghs + 1); | ||
| 530 | gfs2_holder_uninit(ghs + 2); | 542 | gfs2_holder_uninit(ghs + 2); |
| 543 | gfs2_glock_dq(ghs + 1); | ||
| 544 | out_child: | ||
| 545 | gfs2_holder_uninit(ghs + 1); | ||
| 546 | gfs2_glock_dq(ghs); | ||
| 547 | out_parent: | ||
| 548 | gfs2_holder_uninit(ghs); | ||
| 531 | gfs2_glock_dq_uninit(&ri_gh); | 549 | gfs2_glock_dq_uninit(&ri_gh); |
| 532 | return error; | 550 | return error; |
| 533 | } | 551 | } |
| @@ -571,6 +589,54 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, | |||
| 571 | return 0; | 589 | return 0; |
| 572 | } | 590 | } |
| 573 | 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 | |||
| 603 | static 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 | |||
| 574 | /** | 640 | /** |
| 575 | * gfs2_rename - Rename a file | 641 | * gfs2_rename - Rename a file |
| 576 | * @odir: Parent directory of old file name | 642 | * @odir: Parent directory of old file name |
| @@ -589,7 +655,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
| 589 | struct gfs2_inode *ip = GFS2_I(odentry->d_inode); | 655 | struct gfs2_inode *ip = GFS2_I(odentry->d_inode); |
| 590 | struct gfs2_inode *nip = NULL; | 656 | struct gfs2_inode *nip = NULL; |
| 591 | struct gfs2_sbd *sdp = GFS2_SB(odir); | 657 | struct gfs2_sbd *sdp = GFS2_SB(odir); |
| 592 | struct gfs2_holder ghs[5], r_gh; | 658 | struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; |
| 593 | struct gfs2_rgrpd *nrgd; | 659 | struct gfs2_rgrpd *nrgd; |
| 594 | unsigned int num_gh; | 660 | unsigned int num_gh; |
| 595 | int dir_rename = 0; | 661 | int dir_rename = 0; |
| @@ -603,19 +669,20 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
| 603 | return 0; | 669 | return 0; |
| 604 | } | 670 | } |
| 605 | 671 | ||
| 606 | /* Make sure we aren't trying to move a dirctory into it's subdir */ | ||
| 607 | |||
| 608 | if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) { | ||
| 609 | dir_rename = 1; | ||
| 610 | 672 | ||
| 611 | error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0, | 673 | if (odip != ndip) { |
| 612 | &r_gh); | 674 | error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, |
| 675 | 0, &r_gh); | ||
| 613 | if (error) | 676 | if (error) |
| 614 | goto out; | 677 | goto out; |
| 615 | 678 | ||
| 616 | error = gfs2_ok_to_move(ip, ndip); | 679 | if (S_ISDIR(ip->i_inode.i_mode)) { |
| 617 | if (error) | 680 | dir_rename = 1; |
| 618 | 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 | } | ||
| 619 | } | 686 | } |
| 620 | 687 | ||
| 621 | num_gh = 1; | 688 | num_gh = 1; |
| @@ -639,9 +706,11 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
| 639 | gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); | 706 | gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); |
| 640 | } | 707 | } |
| 641 | 708 | ||
| 642 | error = gfs2_glock_nq_m(num_gh, ghs); | 709 | for (x = 0; x < num_gh; x++) { |
| 643 | if (error) | 710 | error = gfs2_glock_nq(ghs + x); |
| 644 | goto out_uninit; | 711 | if (error) |
| 712 | goto out_gunlock; | ||
| 713 | } | ||
| 645 | 714 | ||
| 646 | /* Check out the old directory */ | 715 | /* Check out the old directory */ |
| 647 | 716 | ||
| @@ -804,12 +873,12 @@ out_alloc: | |||
| 804 | if (alloc_required) | 873 | if (alloc_required) |
| 805 | gfs2_alloc_put(ndip); | 874 | gfs2_alloc_put(ndip); |
| 806 | out_gunlock: | 875 | out_gunlock: |
| 807 | gfs2_glock_dq_m(num_gh, ghs); | 876 | while (x--) { |
| 808 | out_uninit: | 877 | gfs2_glock_dq(ghs + x); |
| 809 | for (x = 0; x < num_gh; x++) | ||
| 810 | gfs2_holder_uninit(ghs + x); | 878 | gfs2_holder_uninit(ghs + x); |
| 879 | } | ||
| 811 | out_gunlock_r: | 880 | out_gunlock_r: |
| 812 | if (dir_rename) | 881 | if (r_gh.gh_gl) |
| 813 | gfs2_glock_dq_uninit(&r_gh); | 882 | gfs2_glock_dq_uninit(&r_gh); |
| 814 | out: | 883 | out: |
| 815 | return error; | 884 | return error; |
