diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-09-05 16:13:11 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:07 -0400 |
commit | e02119d5a7b4396c5a872582fddc8bd6d305a70a (patch) | |
tree | 825efe2a79dbca8d61256183f3526a5b5dc40dc6 /fs/btrfs/file.c | |
parent | a1b32a5932cfac7c38b442582285f3da2a09dfd8 (diff) |
Btrfs: Add a write ahead tree log to optimize synchronous operations
File syncs and directory syncs are optimized by copying their
items into a special (copy-on-write) log tree. There is one log tree per
subvolume and the btrfs super block points to a tree of log tree roots.
After a crash, items are copied out of the log tree and back into the
subvolume. See tree-log.c for all the details.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e9e86fbaa243..84ecf3ab8511 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include "btrfs_inode.h" | 36 | #include "btrfs_inode.h" |
37 | #include "ioctl.h" | 37 | #include "ioctl.h" |
38 | #include "print-tree.h" | 38 | #include "print-tree.h" |
39 | #include "tree-log.h" | ||
40 | #include "locking.h" | ||
39 | #include "compat.h" | 41 | #include "compat.h" |
40 | 42 | ||
41 | 43 | ||
@@ -988,10 +990,27 @@ out_nolock: | |||
988 | *ppos = pos; | 990 | *ppos = pos; |
989 | 991 | ||
990 | if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | 992 | if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { |
991 | err = sync_page_range(inode, inode->i_mapping, | 993 | struct btrfs_trans_handle *trans; |
992 | start_pos, num_written); | 994 | |
995 | err = btrfs_fdatawrite_range(inode->i_mapping, start_pos, | ||
996 | start_pos + num_written -1, | ||
997 | WB_SYNC_NONE); | ||
998 | if (err < 0) | ||
999 | num_written = err; | ||
1000 | |||
1001 | err = btrfs_wait_on_page_writeback_range(inode->i_mapping, | ||
1002 | start_pos, start_pos + num_written - 1); | ||
993 | if (err < 0) | 1003 | if (err < 0) |
994 | num_written = err; | 1004 | num_written = err; |
1005 | |||
1006 | trans = btrfs_start_transaction(root, 1); | ||
1007 | ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); | ||
1008 | if (ret == 0) { | ||
1009 | btrfs_sync_log(trans, root); | ||
1010 | btrfs_end_transaction(trans, root); | ||
1011 | } else { | ||
1012 | btrfs_commit_transaction(trans, root); | ||
1013 | } | ||
995 | } else if (num_written > 0 && (file->f_flags & O_DIRECT)) { | 1014 | } else if (num_written > 0 && (file->f_flags & O_DIRECT)) { |
996 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) | 1015 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) |
997 | do_sync_file_range(file, start_pos, | 1016 | do_sync_file_range(file, start_pos, |
@@ -1019,8 +1038,7 @@ int btrfs_release_file(struct inode * inode, struct file * filp) | |||
1019 | return 0; | 1038 | return 0; |
1020 | } | 1039 | } |
1021 | 1040 | ||
1022 | static int btrfs_sync_file(struct file *file, | 1041 | int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) |
1023 | struct dentry *dentry, int datasync) | ||
1024 | { | 1042 | { |
1025 | struct inode *inode = dentry->d_inode; | 1043 | struct inode *inode = dentry->d_inode; |
1026 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1044 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -1043,6 +1061,8 @@ static int btrfs_sync_file(struct file *file, | |||
1043 | } | 1061 | } |
1044 | mutex_unlock(&root->fs_info->trans_mutex); | 1062 | mutex_unlock(&root->fs_info->trans_mutex); |
1045 | 1063 | ||
1064 | filemap_fdatawait(inode->i_mapping); | ||
1065 | |||
1046 | /* | 1066 | /* |
1047 | * ok we haven't committed the transaction yet, lets do a commit | 1067 | * ok we haven't committed the transaction yet, lets do a commit |
1048 | */ | 1068 | */ |
@@ -1054,7 +1074,16 @@ static int btrfs_sync_file(struct file *file, | |||
1054 | ret = -ENOMEM; | 1074 | ret = -ENOMEM; |
1055 | goto out; | 1075 | goto out; |
1056 | } | 1076 | } |
1057 | ret = btrfs_commit_transaction(trans, root); | 1077 | |
1078 | ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); | ||
1079 | if (ret < 0) | ||
1080 | goto out; | ||
1081 | if (ret > 0) { | ||
1082 | ret = btrfs_commit_transaction(trans, root); | ||
1083 | } else { | ||
1084 | btrfs_sync_log(trans, root); | ||
1085 | ret = btrfs_end_transaction(trans, root); | ||
1086 | } | ||
1058 | out: | 1087 | out: |
1059 | return ret > 0 ? EIO : ret; | 1088 | return ret > 0 ? EIO : ret; |
1060 | } | 1089 | } |