diff options
| author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:40:59 -0400 |
|---|---|---|
| committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:39 -0400 |
| commit | a9063ab9a3827483007124bdb6f9877f0ab4c3f5 (patch) | |
| tree | 78afcc391daf9d66df5bf34b207aa8e9c53ca7d6 /fs | |
| parent | 110a045aca62f6f564e3b68f89af2a3a5a6ecff2 (diff) | |
ocfs2: handle file attributes issue for reflink.
A reflink creates a snapshot of a file, that means the attributes
must be identical except for three exceptions - nlink, ino, and ctime.
As for time changes, Here is a brief description:
1. Source file:
1) atime: Ignore. Let the lazy atime code handle that.
2) mtime: don't touch.
3) ctime: If we change the tree (adding REFCOUNTED to at least one
extent), update it.
2. Destination file:
1) atime: ignore.
2) mtime: we want it to appear identical to the source.
3) ctime: update.
The idea here is that an ls -l will show the same time for the
src and target - it shows mtime. Backup software like rsync and tar
will treat the new file correctly too.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ocfs2/refcounttree.c | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index e3171c483685..62d21c6ce1d9 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
| @@ -3350,10 +3350,44 @@ out: | |||
| 3350 | return ret; | 3350 | return ret; |
| 3351 | } | 3351 | } |
| 3352 | 3352 | ||
| 3353 | static int ocfs2_change_ctime(struct inode *inode, | ||
| 3354 | struct buffer_head *di_bh) | ||
| 3355 | { | ||
| 3356 | int ret; | ||
| 3357 | handle_t *handle; | ||
| 3358 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
| 3359 | |||
| 3360 | handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), | ||
| 3361 | OCFS2_INODE_UPDATE_CREDITS); | ||
| 3362 | if (IS_ERR(handle)) { | ||
| 3363 | ret = PTR_ERR(handle); | ||
| 3364 | mlog_errno(ret); | ||
| 3365 | goto out; | ||
| 3366 | } | ||
| 3367 | |||
| 3368 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, | ||
| 3369 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
| 3370 | if (ret) { | ||
| 3371 | mlog_errno(ret); | ||
| 3372 | goto out_commit; | ||
| 3373 | } | ||
| 3374 | |||
| 3375 | inode->i_ctime = CURRENT_TIME; | ||
| 3376 | di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); | ||
| 3377 | di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); | ||
| 3378 | |||
| 3379 | ocfs2_journal_dirty(handle, di_bh); | ||
| 3380 | |||
| 3381 | out_commit: | ||
| 3382 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); | ||
| 3383 | out: | ||
| 3384 | return ret; | ||
| 3385 | } | ||
| 3386 | |||
| 3353 | static int ocfs2_attach_refcount_tree(struct inode *inode, | 3387 | static int ocfs2_attach_refcount_tree(struct inode *inode, |
| 3354 | struct buffer_head *di_bh) | 3388 | struct buffer_head *di_bh) |
| 3355 | { | 3389 | { |
| 3356 | int ret; | 3390 | int ret, data_changed = 0; |
| 3357 | struct buffer_head *ref_root_bh = NULL; | 3391 | struct buffer_head *ref_root_bh = NULL; |
| 3358 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 3392 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
| 3359 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 3393 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
| @@ -3402,12 +3436,21 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, | |||
| 3402 | &dealloc); | 3436 | &dealloc); |
| 3403 | if (ret) { | 3437 | if (ret) { |
| 3404 | mlog_errno(ret); | 3438 | mlog_errno(ret); |
| 3405 | break; | 3439 | goto unlock; |
| 3406 | } | 3440 | } |
| 3441 | |||
| 3442 | data_changed = 1; | ||
| 3407 | } | 3443 | } |
| 3408 | cpos += num_clusters; | 3444 | cpos += num_clusters; |
| 3409 | } | 3445 | } |
| 3410 | 3446 | ||
| 3447 | if (data_changed) { | ||
| 3448 | ret = ocfs2_change_ctime(inode, di_bh); | ||
| 3449 | if (ret) | ||
| 3450 | mlog_errno(ret); | ||
| 3451 | } | ||
| 3452 | |||
| 3453 | unlock: | ||
| 3411 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | 3454 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); |
| 3412 | brelse(ref_root_bh); | 3455 | brelse(ref_root_bh); |
| 3413 | 3456 | ||
| @@ -3522,6 +3565,74 @@ out: | |||
| 3522 | return ret; | 3565 | return ret; |
| 3523 | } | 3566 | } |
| 3524 | 3567 | ||
| 3568 | /* | ||
| 3569 | * change the new file's attributes to the src. | ||
| 3570 | * | ||
| 3571 | * reflink creates a snapshot of a file, that means the attributes | ||
| 3572 | * must be identical except for three exceptions - nlink, ino, and ctime. | ||
| 3573 | */ | ||
| 3574 | static int ocfs2_complete_reflink(struct inode *s_inode, | ||
| 3575 | struct buffer_head *s_bh, | ||
| 3576 | struct inode *t_inode, | ||
| 3577 | struct buffer_head *t_bh) | ||
| 3578 | { | ||
| 3579 | int ret; | ||
| 3580 | handle_t *handle; | ||
| 3581 | struct ocfs2_dinode *s_di = (struct ocfs2_dinode *)s_bh->b_data; | ||
| 3582 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)t_bh->b_data; | ||
| 3583 | loff_t size = i_size_read(s_inode); | ||
| 3584 | |||
| 3585 | handle = ocfs2_start_trans(OCFS2_SB(t_inode->i_sb), | ||
| 3586 | OCFS2_INODE_UPDATE_CREDITS); | ||
| 3587 | if (IS_ERR(handle)) { | ||
| 3588 | ret = PTR_ERR(handle); | ||
| 3589 | mlog_errno(ret); | ||
| 3590 | return ret; | ||
| 3591 | } | ||
| 3592 | |||
| 3593 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(t_inode), t_bh, | ||
| 3594 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
| 3595 | if (ret) { | ||
| 3596 | mlog_errno(ret); | ||
| 3597 | goto out_commit; | ||
| 3598 | } | ||
| 3599 | |||
| 3600 | spin_lock(&OCFS2_I(t_inode)->ip_lock); | ||
| 3601 | OCFS2_I(t_inode)->ip_clusters = OCFS2_I(s_inode)->ip_clusters; | ||
| 3602 | OCFS2_I(t_inode)->ip_attr = OCFS2_I(s_inode)->ip_attr; | ||
| 3603 | OCFS2_I(t_inode)->ip_dyn_features = OCFS2_I(s_inode)->ip_dyn_features; | ||
| 3604 | spin_unlock(&OCFS2_I(t_inode)->ip_lock); | ||
| 3605 | i_size_write(t_inode, size); | ||
| 3606 | |||
| 3607 | di->i_xattr_inline_size = s_di->i_xattr_inline_size; | ||
| 3608 | di->i_clusters = s_di->i_clusters; | ||
| 3609 | di->i_size = s_di->i_size; | ||
| 3610 | di->i_dyn_features = s_di->i_dyn_features; | ||
| 3611 | di->i_attr = s_di->i_attr; | ||
| 3612 | di->i_uid = s_di->i_uid; | ||
| 3613 | di->i_gid = s_di->i_gid; | ||
| 3614 | di->i_mode = s_di->i_mode; | ||
| 3615 | |||
| 3616 | /* | ||
| 3617 | * update time. | ||
| 3618 | * we want mtime to appear identical to the source and update ctime. | ||
| 3619 | */ | ||
| 3620 | t_inode->i_ctime = CURRENT_TIME; | ||
| 3621 | |||
| 3622 | di->i_ctime = cpu_to_le64(t_inode->i_ctime.tv_sec); | ||
| 3623 | di->i_ctime_nsec = cpu_to_le32(t_inode->i_ctime.tv_nsec); | ||
| 3624 | |||
| 3625 | t_inode->i_mtime = s_inode->i_mtime; | ||
| 3626 | di->i_mtime = s_di->i_mtime; | ||
| 3627 | di->i_mtime_nsec = s_di->i_mtime_nsec; | ||
| 3628 | |||
| 3629 | ocfs2_journal_dirty(handle, t_bh); | ||
| 3630 | |||
| 3631 | out_commit: | ||
| 3632 | ocfs2_commit_trans(OCFS2_SB(t_inode->i_sb), handle); | ||
| 3633 | return ret; | ||
| 3634 | } | ||
| 3635 | |||
| 3525 | static int ocfs2_create_reflink_node(struct inode *s_inode, | 3636 | static int ocfs2_create_reflink_node(struct inode *s_inode, |
| 3526 | struct buffer_head *s_bh, | 3637 | struct buffer_head *s_bh, |
| 3527 | struct inode *t_inode, | 3638 | struct inode *t_inode, |
| @@ -3555,9 +3666,16 @@ static int ocfs2_create_reflink_node(struct inode *s_inode, | |||
| 3555 | ret = ocfs2_duplicate_extent_list(s_inode, t_inode, t_bh, | 3666 | ret = ocfs2_duplicate_extent_list(s_inode, t_inode, t_bh, |
| 3556 | &ref_tree->rf_ci, ref_root_bh, | 3667 | &ref_tree->rf_ci, ref_root_bh, |
| 3557 | &dealloc); | 3668 | &dealloc); |
| 3669 | if (ret) { | ||
| 3670 | mlog_errno(ret); | ||
| 3671 | goto out_unlock_refcount; | ||
| 3672 | } | ||
| 3673 | |||
| 3674 | ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh); | ||
| 3558 | if (ret) | 3675 | if (ret) |
| 3559 | mlog_errno(ret); | 3676 | mlog_errno(ret); |
| 3560 | 3677 | ||
| 3678 | out_unlock_refcount: | ||
| 3561 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | 3679 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); |
| 3562 | brelse(ref_root_bh); | 3680 | brelse(ref_root_bh); |
| 3563 | out: | 3681 | out: |
