diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 213 |
1 files changed, 45 insertions, 168 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 6558ffd8d140..9d376be0ea38 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -70,7 +70,6 @@ xfs_setattr( | |||
| 70 | uint commit_flags=0; | 70 | uint commit_flags=0; |
| 71 | uid_t uid=0, iuid=0; | 71 | uid_t uid=0, iuid=0; |
| 72 | gid_t gid=0, igid=0; | 72 | gid_t gid=0, igid=0; |
| 73 | int timeflags = 0; | ||
| 74 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; | 73 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; |
| 75 | int need_iolock = 1; | 74 | int need_iolock = 1; |
| 76 | 75 | ||
| @@ -135,16 +134,13 @@ xfs_setattr( | |||
| 135 | if (flags & XFS_ATTR_NOLOCK) | 134 | if (flags & XFS_ATTR_NOLOCK) |
| 136 | need_iolock = 0; | 135 | need_iolock = 0; |
| 137 | if (!(mask & ATTR_SIZE)) { | 136 | if (!(mask & ATTR_SIZE)) { |
| 138 | if ((mask != (ATTR_CTIME|ATTR_ATIME|ATTR_MTIME)) || | 137 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); |
| 139 | (mp->m_flags & XFS_MOUNT_WSYNC)) { | 138 | commit_flags = 0; |
| 140 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | 139 | code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), |
| 141 | commit_flags = 0; | 140 | 0, 0, 0); |
| 142 | if ((code = xfs_trans_reserve(tp, 0, | 141 | if (code) { |
| 143 | XFS_ICHANGE_LOG_RES(mp), 0, | 142 | lock_flags = 0; |
| 144 | 0, 0))) { | 143 | goto error_return; |
| 145 | lock_flags = 0; | ||
| 146 | goto error_return; | ||
| 147 | } | ||
| 148 | } | 144 | } |
| 149 | } else { | 145 | } else { |
| 150 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && | 146 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && |
| @@ -260,7 +256,7 @@ xfs_setattr( | |||
| 260 | iattr->ia_size > ip->i_d.di_size) { | 256 | iattr->ia_size > ip->i_d.di_size) { |
| 261 | code = xfs_flush_pages(ip, | 257 | code = xfs_flush_pages(ip, |
| 262 | ip->i_d.di_size, iattr->ia_size, | 258 | ip->i_d.di_size, iattr->ia_size, |
| 263 | XFS_B_ASYNC, FI_NONE); | 259 | XBF_ASYNC, FI_NONE); |
| 264 | } | 260 | } |
| 265 | 261 | ||
| 266 | /* wait for all I/O to complete */ | 262 | /* wait for all I/O to complete */ |
| @@ -295,15 +291,23 @@ xfs_setattr( | |||
| 295 | * or we are explicitly asked to change it. This handles | 291 | * or we are explicitly asked to change it. This handles |
| 296 | * the semantic difference between truncate() and ftruncate() | 292 | * the semantic difference between truncate() and ftruncate() |
| 297 | * as implemented in the VFS. | 293 | * as implemented in the VFS. |
| 294 | * | ||
| 295 | * The regular truncate() case without ATTR_CTIME and ATTR_MTIME | ||
| 296 | * is a special case where we need to update the times despite | ||
| 297 | * not having these flags set. For all other operations the | ||
| 298 | * VFS set these flags explicitly if it wants a timestamp | ||
| 299 | * update. | ||
| 298 | */ | 300 | */ |
| 299 | if (iattr->ia_size != ip->i_size || (mask & ATTR_CTIME)) | 301 | if (iattr->ia_size != ip->i_size && |
| 300 | timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | 302 | (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { |
| 303 | iattr->ia_ctime = iattr->ia_mtime = | ||
| 304 | current_fs_time(inode->i_sb); | ||
| 305 | mask |= ATTR_CTIME | ATTR_MTIME; | ||
| 306 | } | ||
| 301 | 307 | ||
| 302 | if (iattr->ia_size > ip->i_size) { | 308 | if (iattr->ia_size > ip->i_size) { |
| 303 | ip->i_d.di_size = iattr->ia_size; | 309 | ip->i_d.di_size = iattr->ia_size; |
| 304 | ip->i_size = iattr->ia_size; | 310 | ip->i_size = iattr->ia_size; |
| 305 | if (!(flags & XFS_ATTR_DMI)) | ||
| 306 | xfs_ichgtime(ip, XFS_ICHGTIME_CHG); | ||
| 307 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 311 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 308 | } else if (iattr->ia_size <= ip->i_size || | 312 | } else if (iattr->ia_size <= ip->i_size || |
| 309 | (iattr->ia_size == 0 && ip->i_d.di_nextents)) { | 313 | (iattr->ia_size == 0 && ip->i_d.di_nextents)) { |
| @@ -374,9 +378,6 @@ xfs_setattr( | |||
| 374 | ip->i_d.di_gid = gid; | 378 | ip->i_d.di_gid = gid; |
| 375 | inode->i_gid = gid; | 379 | inode->i_gid = gid; |
| 376 | } | 380 | } |
| 377 | |||
| 378 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | ||
| 379 | timeflags |= XFS_ICHGTIME_CHG; | ||
| 380 | } | 381 | } |
| 381 | 382 | ||
| 382 | /* | 383 | /* |
| @@ -393,51 +394,37 @@ xfs_setattr( | |||
| 393 | 394 | ||
| 394 | inode->i_mode &= S_IFMT; | 395 | inode->i_mode &= S_IFMT; |
| 395 | inode->i_mode |= mode & ~S_IFMT; | 396 | inode->i_mode |= mode & ~S_IFMT; |
| 396 | |||
| 397 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 398 | timeflags |= XFS_ICHGTIME_CHG; | ||
| 399 | } | 397 | } |
| 400 | 398 | ||
| 401 | /* | 399 | /* |
| 402 | * Change file access or modified times. | 400 | * Change file access or modified times. |
| 403 | */ | 401 | */ |
| 404 | if (mask & (ATTR_ATIME|ATTR_MTIME)) { | 402 | if (mask & ATTR_ATIME) { |
| 405 | if (mask & ATTR_ATIME) { | 403 | inode->i_atime = iattr->ia_atime; |
| 406 | inode->i_atime = iattr->ia_atime; | 404 | ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec; |
| 407 | ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec; | 405 | ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec; |
| 408 | ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec; | 406 | ip->i_update_core = 1; |
| 409 | ip->i_update_core = 1; | ||
| 410 | } | ||
| 411 | if (mask & ATTR_MTIME) { | ||
| 412 | inode->i_mtime = iattr->ia_mtime; | ||
| 413 | ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec; | ||
| 414 | ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec; | ||
| 415 | timeflags &= ~XFS_ICHGTIME_MOD; | ||
| 416 | timeflags |= XFS_ICHGTIME_CHG; | ||
| 417 | } | ||
| 418 | if (tp && (mask & (ATTR_MTIME_SET|ATTR_ATIME_SET))) | ||
| 419 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | ||
| 420 | } | 407 | } |
| 421 | 408 | if (mask & ATTR_CTIME) { | |
| 422 | /* | ||
| 423 | * Change file inode change time only if ATTR_CTIME set | ||
| 424 | * AND we have been called by a DMI function. | ||
| 425 | */ | ||
| 426 | |||
| 427 | if ((flags & XFS_ATTR_DMI) && (mask & ATTR_CTIME)) { | ||
| 428 | inode->i_ctime = iattr->ia_ctime; | 409 | inode->i_ctime = iattr->ia_ctime; |
| 429 | ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; | 410 | ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; |
| 430 | ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec; | 411 | ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec; |
| 431 | ip->i_update_core = 1; | 412 | ip->i_update_core = 1; |
| 432 | timeflags &= ~XFS_ICHGTIME_CHG; | 413 | } |
| 414 | if (mask & ATTR_MTIME) { | ||
| 415 | inode->i_mtime = iattr->ia_mtime; | ||
| 416 | ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec; | ||
| 417 | ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec; | ||
| 418 | ip->i_update_core = 1; | ||
| 433 | } | 419 | } |
| 434 | 420 | ||
| 435 | /* | 421 | /* |
| 436 | * Send out timestamp changes that need to be set to the | 422 | * And finally, log the inode core if any attribute in it |
| 437 | * current time. Not done when called by a DMI function. | 423 | * has been changed. |
| 438 | */ | 424 | */ |
| 439 | if (timeflags && !(flags & XFS_ATTR_DMI)) | 425 | if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE| |
| 440 | xfs_ichgtime(ip, timeflags); | 426 | ATTR_ATIME|ATTR_CTIME|ATTR_MTIME)) |
| 427 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 441 | 428 | ||
| 442 | XFS_STATS_INC(xs_ig_attrchg); | 429 | XFS_STATS_INC(xs_ig_attrchg); |
| 443 | 430 | ||
| @@ -452,12 +439,10 @@ xfs_setattr( | |||
| 452 | * mix so this probably isn't worth the trouble to optimize. | 439 | * mix so this probably isn't worth the trouble to optimize. |
| 453 | */ | 440 | */ |
| 454 | code = 0; | 441 | code = 0; |
| 455 | if (tp) { | 442 | if (mp->m_flags & XFS_MOUNT_WSYNC) |
| 456 | if (mp->m_flags & XFS_MOUNT_WSYNC) | 443 | xfs_trans_set_sync(tp); |
| 457 | xfs_trans_set_sync(tp); | ||
| 458 | 444 | ||
| 459 | code = xfs_trans_commit(tp, commit_flags); | 445 | code = xfs_trans_commit(tp, commit_flags); |
| 460 | } | ||
| 461 | 446 | ||
| 462 | xfs_iunlock(ip, lock_flags); | 447 | xfs_iunlock(ip, lock_flags); |
| 463 | 448 | ||
| @@ -599,116 +584,6 @@ xfs_readlink( | |||
| 599 | } | 584 | } |
| 600 | 585 | ||
| 601 | /* | 586 | /* |
| 602 | * xfs_fsync | ||
| 603 | * | ||
| 604 | * This is called to sync the inode and its data out to disk. We need to hold | ||
| 605 | * the I/O lock while flushing the data, and the inode lock while flushing the | ||
| 606 | * inode. The inode lock CANNOT be held while flushing the data, so acquire | ||
| 607 | * after we're done with that. | ||
| 608 | */ | ||
| 609 | int | ||
| 610 | xfs_fsync( | ||
| 611 | xfs_inode_t *ip) | ||
| 612 | { | ||
| 613 | xfs_trans_t *tp; | ||
| 614 | int error = 0; | ||
| 615 | int log_flushed = 0, changed = 1; | ||
| 616 | |||
| 617 | xfs_itrace_entry(ip); | ||
| 618 | |||
| 619 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
| 620 | return XFS_ERROR(EIO); | ||
| 621 | |||
| 622 | /* | ||
| 623 | * We always need to make sure that the required inode state is safe on | ||
| 624 | * disk. The inode might be clean but we still might need to force the | ||
| 625 | * log because of committed transactions that haven't hit the disk yet. | ||
| 626 | * Likewise, there could be unflushed non-transactional changes to the | ||
| 627 | * inode core that have to go to disk and this requires us to issue | ||
| 628 | * a synchronous transaction to capture these changes correctly. | ||
| 629 | * | ||
| 630 | * This code relies on the assumption that if the update_* fields | ||
| 631 | * of the inode are clear and the inode is unpinned then it is clean | ||
| 632 | * and no action is required. | ||
| 633 | */ | ||
| 634 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
| 635 | |||
| 636 | if (!ip->i_update_core) { | ||
| 637 | /* | ||
| 638 | * Timestamps/size haven't changed since last inode flush or | ||
| 639 | * inode transaction commit. That means either nothing got | ||
| 640 | * written or a transaction committed which caught the updates. | ||
| 641 | * If the latter happened and the transaction hasn't hit the | ||
| 642 | * disk yet, the inode will be still be pinned. If it is, | ||
| 643 | * force the log. | ||
| 644 | */ | ||
| 645 | |||
| 646 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
| 647 | |||
| 648 | if (xfs_ipincount(ip)) { | ||
| 649 | error = _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, | ||
| 650 | XFS_LOG_FORCE | XFS_LOG_SYNC, | ||
| 651 | &log_flushed); | ||
| 652 | } else { | ||
| 653 | /* | ||
| 654 | * If the inode is not pinned and nothing has changed | ||
| 655 | * we don't need to flush the cache. | ||
| 656 | */ | ||
| 657 | changed = 0; | ||
| 658 | } | ||
| 659 | } else { | ||
| 660 | /* | ||
| 661 | * Kick off a transaction to log the inode core to get the | ||
| 662 | * updates. The sync transaction will also force the log. | ||
| 663 | */ | ||
| 664 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
| 665 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); | ||
| 666 | error = xfs_trans_reserve(tp, 0, | ||
| 667 | XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0); | ||
| 668 | if (error) { | ||
| 669 | xfs_trans_cancel(tp, 0); | ||
| 670 | return error; | ||
| 671 | } | ||
| 672 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
| 673 | |||
| 674 | /* | ||
| 675 | * Note - it's possible that we might have pushed ourselves out | ||
| 676 | * of the way during trans_reserve which would flush the inode. | ||
| 677 | * But there's no guarantee that the inode buffer has actually | ||
| 678 | * gone out yet (it's delwri). Plus the buffer could be pinned | ||
| 679 | * anyway if it's part of an inode in another recent | ||
| 680 | * transaction. So we play it safe and fire off the | ||
| 681 | * transaction anyway. | ||
| 682 | */ | ||
| 683 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
| 684 | xfs_trans_ihold(tp, ip); | ||
| 685 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 686 | xfs_trans_set_sync(tp); | ||
| 687 | error = _xfs_trans_commit(tp, 0, &log_flushed); | ||
| 688 | |||
| 689 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
| 690 | } | ||
| 691 | |||
| 692 | if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) { | ||
| 693 | /* | ||
| 694 | * If the log write didn't issue an ordered tag we need | ||
| 695 | * to flush the disk cache for the data device now. | ||
| 696 | */ | ||
| 697 | if (!log_flushed) | ||
| 698 | xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp); | ||
| 699 | |||
| 700 | /* | ||
| 701 | * If this inode is on the RT dev we need to flush that | ||
| 702 | * cache as well. | ||
| 703 | */ | ||
| 704 | if (XFS_IS_REALTIME_INODE(ip)) | ||
| 705 | xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); | ||
| 706 | } | ||
| 707 | |||
| 708 | return error; | ||
| 709 | } | ||
| 710 | |||
| 711 | /* | ||
| 712 | * Flags for xfs_free_eofblocks | 587 | * Flags for xfs_free_eofblocks |
| 713 | */ | 588 | */ |
| 714 | #define XFS_FREE_EOF_TRYLOCK (1<<0) | 589 | #define XFS_FREE_EOF_TRYLOCK (1<<0) |
| @@ -1111,7 +986,7 @@ xfs_release( | |||
| 1111 | */ | 986 | */ |
| 1112 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); | 987 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); |
| 1113 | if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) | 988 | if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) |
| 1114 | xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); | 989 | xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE); |
| 1115 | } | 990 | } |
| 1116 | 991 | ||
| 1117 | if (ip->i_d.di_nlink != 0) { | 992 | if (ip->i_d.di_nlink != 0) { |
| @@ -2214,7 +2089,8 @@ xfs_symlink( | |||
| 2214 | if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { | 2089 | if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { |
| 2215 | error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, | 2090 | error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, |
| 2216 | DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, | 2091 | DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, |
| 2217 | link_name->name, target_path, 0, 0, 0); | 2092 | link_name->name, |
| 2093 | (unsigned char *)target_path, 0, 0, 0); | ||
| 2218 | if (error) | 2094 | if (error) |
| 2219 | return error; | 2095 | return error; |
| 2220 | } | 2096 | } |
| @@ -2410,7 +2286,8 @@ std_return: | |||
| 2410 | dp, DM_RIGHT_NULL, | 2286 | dp, DM_RIGHT_NULL, |
| 2411 | error ? NULL : ip, | 2287 | error ? NULL : ip, |
| 2412 | DM_RIGHT_NULL, link_name->name, | 2288 | DM_RIGHT_NULL, link_name->name, |
| 2413 | target_path, 0, error, 0); | 2289 | (unsigned char *)target_path, |
| 2290 | 0, error, 0); | ||
| 2414 | } | 2291 | } |
| 2415 | 2292 | ||
| 2416 | if (!error) | 2293 | if (!error) |
