aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-17 23:40:59 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:39 -0400
commita9063ab9a3827483007124bdb6f9877f0ab4c3f5 (patch)
tree78afcc391daf9d66df5bf34b207aa8e9c53ca7d6 /fs
parent110a045aca62f6f564e3b68f89af2a3a5a6ecff2 (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.c122
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
3353static 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
3381out_commit:
3382 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
3383out:
3384 return ret;
3385}
3386
3353static int ocfs2_attach_refcount_tree(struct inode *inode, 3387static 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
3453unlock:
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 */
3574static 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
3631out_commit:
3632 ocfs2_commit_trans(OCFS2_SB(t_inode->i_sb), handle);
3633 return ret;
3634}
3635
3525static int ocfs2_create_reflink_node(struct inode *s_inode, 3636static 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
3678out_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);
3563out: 3681out: