diff options
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 171 |
1 files changed, 43 insertions, 128 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index c22f4e0ecac1..f9a515776a9c 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -282,23 +282,15 @@ xfs_inactive_symlink_rmt( | |||
| 282 | * free them all in one bunmapi call. | 282 | * free them all in one bunmapi call. |
| 283 | */ | 283 | */ |
| 284 | ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); | 284 | ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); |
| 285 | if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, | 285 | |
| 286 | XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { | ||
| 287 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | ||
| 288 | xfs_trans_cancel(tp, 0); | ||
| 289 | *tpp = NULL; | ||
| 290 | return error; | ||
| 291 | } | ||
| 292 | /* | 286 | /* |
| 293 | * Lock the inode, fix the size, and join it to the transaction. | 287 | * Lock the inode, fix the size, and join it to the transaction. |
| 294 | * Hold it so in the normal path, we still have it locked for | 288 | * Hold it so in the normal path, we still have it locked for |
| 295 | * the second transaction. In the error paths we need it | 289 | * the second transaction. In the error paths we need it |
| 296 | * held so the cancel won't rele it, see below. | 290 | * held so the cancel won't rele it, see below. |
| 297 | */ | 291 | */ |
| 298 | xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | ||
| 299 | size = (int)ip->i_d.di_size; | 292 | size = (int)ip->i_d.di_size; |
| 300 | ip->i_d.di_size = 0; | 293 | ip->i_d.di_size = 0; |
| 301 | xfs_trans_ijoin(tp, ip, 0); | ||
| 302 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 294 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 303 | /* | 295 | /* |
| 304 | * Find the block(s) so we can inval and unmap them. | 296 | * Find the block(s) so we can inval and unmap them. |
| @@ -385,67 +377,15 @@ xfs_inactive_symlink_rmt( | |||
| 385 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 377 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
| 386 | goto error0; | 378 | goto error0; |
| 387 | } | 379 | } |
| 388 | /* | 380 | |
| 389 | * Return with the inode locked but not joined to the transaction. | 381 | xfs_trans_ijoin(tp, ip, 0); |
| 390 | */ | ||
| 391 | *tpp = tp; | 382 | *tpp = tp; |
| 392 | return 0; | 383 | return 0; |
| 393 | 384 | ||
| 394 | error1: | 385 | error1: |
| 395 | xfs_bmap_cancel(&free_list); | 386 | xfs_bmap_cancel(&free_list); |
| 396 | error0: | 387 | error0: |
| 397 | /* | ||
| 398 | * Have to come here with the inode locked and either | ||
| 399 | * (held and in the transaction) or (not in the transaction). | ||
| 400 | * If the inode isn't held then cancel would iput it, but | ||
| 401 | * that's wrong since this is inactive and the vnode ref | ||
| 402 | * count is 0 already. | ||
| 403 | * Cancel won't do anything to the inode if held, but it still | ||
| 404 | * needs to be locked until the cancel is done, if it was | ||
| 405 | * joined to the transaction. | ||
| 406 | */ | ||
| 407 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | ||
| 408 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | ||
| 409 | *tpp = NULL; | ||
| 410 | return error; | 388 | return error; |
| 411 | |||
| 412 | } | ||
| 413 | |||
| 414 | STATIC int | ||
| 415 | xfs_inactive_symlink_local( | ||
| 416 | xfs_inode_t *ip, | ||
| 417 | xfs_trans_t **tpp) | ||
| 418 | { | ||
| 419 | int error; | ||
| 420 | |||
| 421 | ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip)); | ||
| 422 | /* | ||
| 423 | * We're freeing a symlink which fit into | ||
| 424 | * the inode. Just free the memory used | ||
| 425 | * to hold the old symlink. | ||
| 426 | */ | ||
| 427 | error = xfs_trans_reserve(*tpp, 0, | ||
| 428 | XFS_ITRUNCATE_LOG_RES(ip->i_mount), | ||
| 429 | 0, XFS_TRANS_PERM_LOG_RES, | ||
| 430 | XFS_ITRUNCATE_LOG_COUNT); | ||
| 431 | |||
| 432 | if (error) { | ||
| 433 | xfs_trans_cancel(*tpp, 0); | ||
| 434 | *tpp = NULL; | ||
| 435 | return error; | ||
| 436 | } | ||
| 437 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
| 438 | |||
| 439 | /* | ||
| 440 | * Zero length symlinks _can_ exist. | ||
| 441 | */ | ||
| 442 | if (ip->i_df.if_bytes > 0) { | ||
| 443 | xfs_idata_realloc(ip, | ||
| 444 | -(ip->i_df.if_bytes), | ||
| 445 | XFS_DATA_FORK); | ||
| 446 | ASSERT(ip->i_df.if_bytes == 0); | ||
| 447 | } | ||
| 448 | return 0; | ||
| 449 | } | 389 | } |
| 450 | 390 | ||
| 451 | STATIC int | 391 | STATIC int |
| @@ -604,7 +544,7 @@ xfs_inactive( | |||
| 604 | xfs_trans_t *tp; | 544 | xfs_trans_t *tp; |
| 605 | xfs_mount_t *mp; | 545 | xfs_mount_t *mp; |
| 606 | int error; | 546 | int error; |
| 607 | int truncate; | 547 | int truncate = 0; |
| 608 | 548 | ||
| 609 | /* | 549 | /* |
| 610 | * If the inode is already free, then there can be nothing | 550 | * If the inode is already free, then there can be nothing |
| @@ -616,17 +556,6 @@ xfs_inactive( | |||
| 616 | return VN_INACTIVE_CACHE; | 556 | return VN_INACTIVE_CACHE; |
| 617 | } | 557 | } |
| 618 | 558 | ||
| 619 | /* | ||
| 620 | * Only do a truncate if it's a regular file with | ||
| 621 | * some actual space in it. It's OK to look at the | ||
| 622 | * inode's fields without the lock because we're the | ||
| 623 | * only one with a reference to the inode. | ||
| 624 | */ | ||
| 625 | truncate = ((ip->i_d.di_nlink == 0) && | ||
| 626 | ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 || | ||
| 627 | (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && | ||
| 628 | S_ISREG(ip->i_d.di_mode)); | ||
| 629 | |||
| 630 | mp = ip->i_mount; | 559 | mp = ip->i_mount; |
| 631 | 560 | ||
| 632 | error = 0; | 561 | error = 0; |
| @@ -650,72 +579,54 @@ xfs_inactive( | |||
| 650 | goto out; | 579 | goto out; |
| 651 | } | 580 | } |
| 652 | 581 | ||
| 653 | ASSERT(ip->i_d.di_nlink == 0); | 582 | if (S_ISREG(ip->i_d.di_mode) && |
| 583 | (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 || | ||
| 584 | ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0)) | ||
| 585 | truncate = 1; | ||
| 654 | 586 | ||
| 655 | error = xfs_qm_dqattach(ip, 0); | 587 | error = xfs_qm_dqattach(ip, 0); |
| 656 | if (error) | 588 | if (error) |
| 657 | return VN_INACTIVE_CACHE; | 589 | return VN_INACTIVE_CACHE; |
| 658 | 590 | ||
| 659 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 591 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
| 660 | if (truncate) { | 592 | error = xfs_trans_reserve(tp, 0, |
| 661 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 593 | (truncate || S_ISLNK(ip->i_d.di_mode)) ? |
| 662 | 594 | XFS_ITRUNCATE_LOG_RES(mp) : | |
| 663 | error = xfs_trans_reserve(tp, 0, | 595 | XFS_IFREE_LOG_RES(mp), |
| 664 | XFS_ITRUNCATE_LOG_RES(mp), | 596 | 0, |
| 665 | 0, XFS_TRANS_PERM_LOG_RES, | 597 | XFS_TRANS_PERM_LOG_RES, |
| 666 | XFS_ITRUNCATE_LOG_COUNT); | 598 | XFS_ITRUNCATE_LOG_COUNT); |
| 667 | if (error) { | 599 | if (error) { |
| 668 | /* Don't call itruncate_cleanup */ | 600 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
| 669 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 601 | xfs_trans_cancel(tp, 0); |
| 670 | xfs_trans_cancel(tp, 0); | 602 | return VN_INACTIVE_CACHE; |
| 671 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 603 | } |
| 672 | return VN_INACTIVE_CACHE; | ||
| 673 | } | ||
| 674 | 604 | ||
| 675 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 605 | xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
| 676 | xfs_trans_ijoin(tp, ip, 0); | 606 | xfs_trans_ijoin(tp, ip, 0); |
| 677 | 607 | ||
| 608 | if (S_ISLNK(ip->i_d.di_mode)) { | ||
| 609 | /* | ||
| 610 | * Zero length symlinks _can_ exist. | ||
| 611 | */ | ||
| 612 | if (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) { | ||
| 613 | error = xfs_inactive_symlink_rmt(ip, &tp); | ||
| 614 | if (error) | ||
| 615 | goto out_cancel; | ||
| 616 | } else if (ip->i_df.if_bytes > 0) { | ||
| 617 | xfs_idata_realloc(ip, -(ip->i_df.if_bytes), | ||
| 618 | XFS_DATA_FORK); | ||
| 619 | ASSERT(ip->i_df.if_bytes == 0); | ||
| 620 | } | ||
| 621 | } else if (truncate) { | ||
| 678 | ip->i_d.di_size = 0; | 622 | ip->i_d.di_size = 0; |
| 679 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 623 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 680 | 624 | ||
| 681 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); | 625 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); |
| 682 | if (error) { | 626 | if (error) |
| 683 | xfs_trans_cancel(tp, | 627 | goto out_cancel; |
| 684 | XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | ||
| 685 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | ||
| 686 | return VN_INACTIVE_CACHE; | ||
| 687 | } | ||
| 688 | 628 | ||
| 689 | ASSERT(ip->i_d.di_nextents == 0); | 629 | ASSERT(ip->i_d.di_nextents == 0); |
| 690 | } else if (S_ISLNK(ip->i_d.di_mode)) { | ||
| 691 | |||
| 692 | /* | ||
| 693 | * If we get an error while cleaning up a | ||
| 694 | * symlink we bail out. | ||
| 695 | */ | ||
| 696 | error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? | ||
| 697 | xfs_inactive_symlink_rmt(ip, &tp) : | ||
| 698 | xfs_inactive_symlink_local(ip, &tp); | ||
| 699 | |||
| 700 | if (error) { | ||
| 701 | ASSERT(tp == NULL); | ||
| 702 | return VN_INACTIVE_CACHE; | ||
| 703 | } | ||
| 704 | |||
| 705 | xfs_trans_ijoin(tp, ip, 0); | ||
| 706 | } else { | ||
| 707 | error = xfs_trans_reserve(tp, 0, | ||
| 708 | XFS_IFREE_LOG_RES(mp), | ||
| 709 | 0, XFS_TRANS_PERM_LOG_RES, | ||
| 710 | XFS_INACTIVE_LOG_COUNT); | ||
| 711 | if (error) { | ||
| 712 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | ||
| 713 | xfs_trans_cancel(tp, 0); | ||
| 714 | return VN_INACTIVE_CACHE; | ||
| 715 | } | ||
| 716 | |||
| 717 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
| 718 | xfs_trans_ijoin(tp, ip, 0); | ||
| 719 | } | 630 | } |
| 720 | 631 | ||
| 721 | /* | 632 | /* |
| @@ -781,7 +692,11 @@ xfs_inactive( | |||
| 781 | xfs_qm_dqdetach(ip); | 692 | xfs_qm_dqdetach(ip); |
| 782 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 693 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
| 783 | 694 | ||
| 784 | out: | 695 | out: |
| 696 | return VN_INACTIVE_CACHE; | ||
| 697 | out_cancel: | ||
| 698 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | ||
| 699 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | ||
| 785 | return VN_INACTIVE_CACHE; | 700 | return VN_INACTIVE_CACHE; |
| 786 | } | 701 | } |
| 787 | 702 | ||
