aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-10-29 15:41:32 -0400
committerChris Mason <chris.mason@oracle.com>2010-10-29 15:41:32 -0400
commit462045928bda777c86919a396a42991fcf235378 (patch)
treec2b12ff8e9ef1951b5960b853034bd4165578f99 /fs
parentbb9c12c945cbd1b0eaa1589546dde772ccabeeba (diff)
Btrfs: add START_SYNC, WAIT_SYNC ioctls
START_SYNC will start a sync/commit, but not wait for it to complete. Any modification started after the ioctl returns is guaranteed not to be included in the commit. If a non-NULL pointer is passed, the transaction id will be returned to userspace. WAIT_SYNC will wait for any in-progress commit to complete. If a transaction id is specified, the ioctl will block and then return (success) when the specified transaction has committed. If it has already committed when we call the ioctl, it returns immediately. If the specified transaction doesn't exist, it returns EINVAL. If no transaction id is specified, WAIT_SYNC will wait for the currently committing transaction to finish it's commit to disk. If there is no currently committing transaction, it returns success. These ioctls are useful for applications which want to impose an ordering on when fs modifications reach disk, but do not want to wait for the full (slow) commit process to do so. Picky callers can take the transid returned by START_SYNC and feed it to WAIT_SYNC, and be certain to wait only as long as necessary for the transaction _they_ started to reach disk. Sloppy callers can START_SYNC and WAIT_SYNC without a transid, and provided they didn't wait too long between the calls, they will get the same result. However, if a second commit starts before they call WAIT_SYNC, they may end up waiting longer for it to commit as well. Even so, a START_SYNC+WAIT_SYNC still guarantees that any operation completed before the START_SYNC reaches disk. Signed-off-by: Sage Weil <sage@newdream.net> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ioctl.c34
-rw-r--r--fs/btrfs/ioctl.h2
-rw-r--r--fs/btrfs/transaction.c52
-rw-r--r--fs/btrfs/transaction.h1
4 files changed, 89 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 93d69b32028e..dc5a19ed07f3 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2028,6 +2028,36 @@ long btrfs_ioctl_trans_end(struct file *file)
2028 return 0; 2028 return 0;
2029} 2029}
2030 2030
2031static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp)
2032{
2033 struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
2034 struct btrfs_trans_handle *trans;
2035 u64 transid;
2036
2037 trans = btrfs_start_transaction(root, 0);
2038 transid = trans->transid;
2039 btrfs_commit_transaction_async(trans, root, 0);
2040
2041 if (argp)
2042 if (copy_to_user(argp, &transid, sizeof(transid)))
2043 return -EFAULT;
2044 return 0;
2045}
2046
2047static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
2048{
2049 struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
2050 u64 transid;
2051
2052 if (argp) {
2053 if (copy_from_user(&transid, argp, sizeof(transid)))
2054 return -EFAULT;
2055 } else {
2056 transid = 0; /* current trans */
2057 }
2058 return btrfs_wait_for_commit(root, transid);
2059}
2060
2031long btrfs_ioctl(struct file *file, unsigned int 2061long btrfs_ioctl(struct file *file, unsigned int
2032 cmd, unsigned long arg) 2062 cmd, unsigned long arg)
2033{ 2063{
@@ -2078,6 +2108,10 @@ long btrfs_ioctl(struct file *file, unsigned int
2078 case BTRFS_IOC_SYNC: 2108 case BTRFS_IOC_SYNC:
2079 btrfs_sync_fs(file->f_dentry->d_sb, 1); 2109 btrfs_sync_fs(file->f_dentry->d_sb, 1);
2080 return 0; 2110 return 0;
2111 case BTRFS_IOC_START_SYNC:
2112 return btrfs_ioctl_start_sync(file, argp);
2113 case BTRFS_IOC_WAIT_SYNC:
2114 return btrfs_ioctl_wait_sync(file, argp);
2081 } 2115 }
2082 2116
2083 return -ENOTTY; 2117 return -ENOTTY;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 424694aa517f..16e1442523b7 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -178,4 +178,6 @@ struct btrfs_ioctl_space_args {
178#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64) 178#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
179#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ 179#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
180 struct btrfs_ioctl_space_args) 180 struct btrfs_ioctl_space_args)
181#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
182#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
181#endif 183#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 9f40bfc9c45c..1fffbc017bdf 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -279,6 +279,58 @@ static noinline int wait_for_commit(struct btrfs_root *root,
279 return 0; 279 return 0;
280} 280}
281 281
282int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
283{
284 struct btrfs_transaction *cur_trans = NULL, *t;
285 int ret;
286
287 mutex_lock(&root->fs_info->trans_mutex);
288
289 ret = 0;
290 if (transid) {
291 if (transid <= root->fs_info->last_trans_committed)
292 goto out_unlock;
293
294 /* find specified transaction */
295 list_for_each_entry(t, &root->fs_info->trans_list, list) {
296 if (t->transid == transid) {
297 cur_trans = t;
298 break;
299 }
300 if (t->transid > transid)
301 break;
302 }
303 ret = -EINVAL;
304 if (!cur_trans)
305 goto out_unlock; /* bad transid */
306 } else {
307 /* find newest transaction that is committing | committed */
308 list_for_each_entry_reverse(t, &root->fs_info->trans_list,
309 list) {
310 if (t->in_commit) {
311 if (t->commit_done)
312 goto out_unlock;
313 cur_trans = t;
314 break;
315 }
316 }
317 if (!cur_trans)
318 goto out_unlock; /* nothing committing|committed */
319 }
320
321 cur_trans->use_count++;
322 mutex_unlock(&root->fs_info->trans_mutex);
323
324 wait_for_commit(root, cur_trans);
325
326 mutex_lock(&root->fs_info->trans_mutex);
327 put_transaction(cur_trans);
328 ret = 0;
329out_unlock:
330 mutex_unlock(&root->fs_info->trans_mutex);
331 return ret;
332}
333
282#if 0 334#if 0
283/* 335/*
284 * rate limit against the drop_snapshot code. This helps to slow down new 336 * rate limit against the drop_snapshot code. This helps to slow down new
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index e1908e6872fe..f104b57ad4ef 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -97,6 +97,7 @@ struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root
97 int num_blocks); 97 int num_blocks);
98struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, 98struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
99 int num_blocks); 99 int num_blocks);
100int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid);
100int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, 101int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
101 struct btrfs_root *root); 102 struct btrfs_root *root);
102int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, 103int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,