diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-19 21:01:03 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-19 21:01:03 -0400 |
commit | 8fd17795b2261ecb1bad2a6df09ef14c4957a3fb (patch) | |
tree | baab31275c20f5848f11688678158cf50875834e | |
parent | 7e38180e207c8707691c12395e990a5d583c5e71 (diff) |
Btrfs: early fsync support
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/TODO | 1 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 1 | ||||
-rw-r--r-- | fs/btrfs/super.c | 37 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 25 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 |
7 files changed, 62 insertions, 5 deletions
diff --git a/fs/btrfs/TODO b/fs/btrfs/TODO index 8d7e5a3ed629..5ff2cef9f028 100644 --- a/fs/btrfs/TODO +++ b/fs/btrfs/TODO | |||
@@ -7,6 +7,7 @@ | |||
7 | * Get rid of struct ctree_path, limiting tree levels held at one time | 7 | * Get rid of struct ctree_path, limiting tree levels held at one time |
8 | * Add generation number to key pointer in nodes | 8 | * Add generation number to key pointer in nodes |
9 | * Add parent pointer back to extent map. | 9 | * Add parent pointer back to extent map. |
10 | * Implement real list of pending transactions | ||
10 | * Release | 11 | * Release |
11 | * Do real tree locking | 12 | * Do real tree locking |
12 | * Add extent mirroring (backup copies of blocks) | 13 | * Add extent mirroring (backup copies of blocks) |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d628a3b9441c..047a84762d93 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -256,6 +256,7 @@ struct btrfs_fs_info { | |||
256 | struct inode *btree_inode; | 256 | struct inode *btree_inode; |
257 | struct mutex trans_mutex; | 257 | struct mutex trans_mutex; |
258 | struct mutex fs_mutex; | 258 | struct mutex fs_mutex; |
259 | struct list_head trans_list; | ||
259 | struct crypto_hash *hash_tfm; | 260 | struct crypto_hash *hash_tfm; |
260 | spinlock_t hash_lock; | 261 | spinlock_t hash_lock; |
261 | struct kobject kobj; | 262 | struct kobject kobj; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 11e17a2f736b..b666c3571aee 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -528,6 +528,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
528 | init_bit_radix(&fs_info->pending_del_radix); | 528 | init_bit_radix(&fs_info->pending_del_radix); |
529 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | 529 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); |
530 | INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS); | 530 | INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS); |
531 | INIT_LIST_HEAD(&fs_info->trans_list); | ||
531 | sb_set_blocksize(sb, 4096); | 532 | sb_set_blocksize(sb, 4096); |
532 | fs_info->running_transaction = NULL; | 533 | fs_info->running_transaction = NULL; |
533 | fs_info->tree_root = tree_root; | 534 | fs_info->tree_root = tree_root; |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 72be9836932f..a42943bd9179 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -100,7 +100,6 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
100 | BUG_ON(refs == 0); | 100 | BUG_ON(refs == 0); |
101 | if (refs == 1) { | 101 | if (refs == 1) { |
102 | ret = btrfs_del_item(trans, root, path); | 102 | ret = btrfs_del_item(trans, root, path); |
103 | printk("deleting root %Lu %Lu %u\n", key->objectid, key->offset, key->flags); | ||
104 | } else { | 103 | } else { |
105 | btrfs_set_root_refs(ri, refs - 1); | 104 | btrfs_set_root_refs(ri, refs - 1); |
106 | printk("ref now %u root %Lu %Lu %u\n", refs -1, key->objectid, key->offset, key->flags); | 105 | printk("ref now %u root %Lu %Lu %u\n", refs -1, key->objectid, key->offset, key->flags); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index dff2db0d1dc2..f99c764a59db 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/mpage.h> | 11 | #include <linux/mpage.h> |
12 | #include <linux/swap.h> | 12 | #include <linux/swap.h> |
13 | #include <linux/writeback.h> | 13 | #include <linux/writeback.h> |
14 | #include <linux/statfs.h> | ||
14 | #include "ctree.h" | 15 | #include "ctree.h" |
15 | #include "disk-io.h" | 16 | #include "disk-io.h" |
16 | #include "transaction.h" | 17 | #include "transaction.h" |
@@ -932,6 +933,26 @@ out_unlock: | |||
932 | return err; | 933 | return err; |
933 | } | 934 | } |
934 | 935 | ||
936 | static int btrfs_sync_file(struct file *file, | ||
937 | struct dentry *dentry, int datasync) | ||
938 | { | ||
939 | struct inode *inode = dentry->d_inode; | ||
940 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
941 | int ret; | ||
942 | struct btrfs_trans_handle *trans; | ||
943 | |||
944 | mutex_lock(&root->fs_info->fs_mutex); | ||
945 | trans = btrfs_start_transaction(root, 1); | ||
946 | if (!trans) { | ||
947 | ret = -ENOMEM; | ||
948 | goto out; | ||
949 | } | ||
950 | ret = btrfs_commit_transaction(trans, root); | ||
951 | mutex_unlock(&root->fs_info->fs_mutex); | ||
952 | out: | ||
953 | return ret > 0 ? EIO : ret; | ||
954 | } | ||
955 | |||
935 | static int btrfs_sync_fs(struct super_block *sb, int wait) | 956 | static int btrfs_sync_fs(struct super_block *sb, int wait) |
936 | { | 957 | { |
937 | struct btrfs_trans_handle *trans; | 958 | struct btrfs_trans_handle *trans; |
@@ -2353,6 +2374,19 @@ static int btrfs_getattr(struct vfsmount *mnt, | |||
2353 | return 0; | 2374 | return 0; |
2354 | } | 2375 | } |
2355 | 2376 | ||
2377 | static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
2378 | { | ||
2379 | struct btrfs_root *root = btrfs_sb(dentry->d_sb); | ||
2380 | struct btrfs_super_block *disk_super = root->fs_info->disk_super; | ||
2381 | |||
2382 | buf->f_namelen = BTRFS_NAME_LEN; | ||
2383 | buf->f_blocks = btrfs_super_total_blocks(disk_super); | ||
2384 | buf->f_bfree = buf->f_blocks - btrfs_super_blocks_used(disk_super); | ||
2385 | buf->f_bavail = buf->f_bfree; | ||
2386 | buf->f_bsize = dentry->d_sb->s_blocksize; | ||
2387 | buf->f_type = BTRFS_SUPER_MAGIC; | ||
2388 | return 0; | ||
2389 | } | ||
2356 | static struct file_system_type btrfs_fs_type = { | 2390 | static struct file_system_type btrfs_fs_type = { |
2357 | .owner = THIS_MODULE, | 2391 | .owner = THIS_MODULE, |
2358 | .name = "btrfs", | 2392 | .name = "btrfs", |
@@ -2362,7 +2396,6 @@ static struct file_system_type btrfs_fs_type = { | |||
2362 | }; | 2396 | }; |
2363 | 2397 | ||
2364 | static struct super_operations btrfs_super_ops = { | 2398 | static struct super_operations btrfs_super_ops = { |
2365 | .statfs = simple_statfs, | ||
2366 | .delete_inode = btrfs_delete_inode, | 2399 | .delete_inode = btrfs_delete_inode, |
2367 | .put_super = btrfs_put_super, | 2400 | .put_super = btrfs_put_super, |
2368 | .read_inode = btrfs_read_locked_inode, | 2401 | .read_inode = btrfs_read_locked_inode, |
@@ -2371,6 +2404,7 @@ static struct super_operations btrfs_super_ops = { | |||
2371 | .write_inode = btrfs_write_inode, | 2404 | .write_inode = btrfs_write_inode, |
2372 | .alloc_inode = btrfs_alloc_inode, | 2405 | .alloc_inode = btrfs_alloc_inode, |
2373 | .destroy_inode = btrfs_destroy_inode, | 2406 | .destroy_inode = btrfs_destroy_inode, |
2407 | .statfs = btrfs_statfs, | ||
2374 | }; | 2408 | }; |
2375 | 2409 | ||
2376 | static struct inode_operations btrfs_dir_inode_operations = { | 2410 | static struct inode_operations btrfs_dir_inode_operations = { |
@@ -2413,6 +2447,7 @@ static struct file_operations btrfs_file_operations = { | |||
2413 | .mmap = generic_file_mmap, | 2447 | .mmap = generic_file_mmap, |
2414 | .open = generic_file_open, | 2448 | .open = generic_file_open, |
2415 | .ioctl = btrfs_ioctl, | 2449 | .ioctl = btrfs_ioctl, |
2450 | .fsync = btrfs_sync_file, | ||
2416 | }; | 2451 | }; |
2417 | 2452 | ||
2418 | static int __init init_btrfs_fs(void) | 2453 | static int __init init_btrfs_fs(void) |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8740752f3845..078cb9cbf9dd 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -19,6 +19,7 @@ static void put_transaction(struct btrfs_transaction *transaction) | |||
19 | if (transaction->use_count == 0) { | 19 | if (transaction->use_count == 0) { |
20 | WARN_ON(total_trans == 0); | 20 | WARN_ON(total_trans == 0); |
21 | total_trans--; | 21 | total_trans--; |
22 | list_del_init(&transaction->list); | ||
22 | memset(transaction, 0, sizeof(*transaction)); | 23 | memset(transaction, 0, sizeof(*transaction)); |
23 | kmem_cache_free(btrfs_transaction_cachep, transaction); | 24 | kmem_cache_free(btrfs_transaction_cachep, transaction); |
24 | } | 25 | } |
@@ -43,6 +44,7 @@ static int join_transaction(struct btrfs_root *root) | |||
43 | cur_trans->in_commit = 0; | 44 | cur_trans->in_commit = 0; |
44 | cur_trans->use_count = 1; | 45 | cur_trans->use_count = 1; |
45 | cur_trans->commit_done = 0; | 46 | cur_trans->commit_done = 0; |
47 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); | ||
46 | } | 48 | } |
47 | cur_trans->num_writers++; | 49 | cur_trans->num_writers++; |
48 | return 0; | 50 | return 0; |
@@ -236,6 +238,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
236 | { | 238 | { |
237 | int ret = 0; | 239 | int ret = 0; |
238 | struct btrfs_transaction *cur_trans; | 240 | struct btrfs_transaction *cur_trans; |
241 | struct btrfs_transaction *prev_trans = NULL; | ||
239 | struct list_head dirty_fs_roots; | 242 | struct list_head dirty_fs_roots; |
240 | DEFINE_WAIT(wait); | 243 | DEFINE_WAIT(wait); |
241 | 244 | ||
@@ -272,13 +275,29 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
272 | BUG_ON(ret); | 275 | BUG_ON(ret); |
273 | cur_trans = root->fs_info->running_transaction; | 276 | cur_trans = root->fs_info->running_transaction; |
274 | root->fs_info->running_transaction = NULL; | 277 | root->fs_info->running_transaction = NULL; |
275 | btrfs_set_super_generation(root->fs_info->disk_super, | 278 | if (cur_trans->list.prev != &root->fs_info->trans_list) { |
276 | root->fs_info->generation + 1); | 279 | prev_trans = list_entry(cur_trans->list.prev, |
280 | struct btrfs_transaction, list); | ||
281 | if (prev_trans->commit_done) | ||
282 | prev_trans = NULL; | ||
283 | else | ||
284 | prev_trans->use_count++; | ||
285 | } | ||
277 | mutex_unlock(&root->fs_info->trans_mutex); | 286 | mutex_unlock(&root->fs_info->trans_mutex); |
287 | mutex_unlock(&root->fs_info->fs_mutex); | ||
278 | ret = btrfs_write_and_wait_transaction(trans, root); | 288 | ret = btrfs_write_and_wait_transaction(trans, root); |
289 | if (prev_trans) { | ||
290 | mutex_lock(&root->fs_info->trans_mutex); | ||
291 | wait_for_commit(root, prev_trans); | ||
292 | put_transaction(prev_trans); | ||
293 | mutex_unlock(&root->fs_info->trans_mutex); | ||
294 | } | ||
295 | btrfs_set_super_generation(root->fs_info->disk_super, | ||
296 | cur_trans->transid); | ||
279 | BUG_ON(ret); | 297 | BUG_ON(ret); |
280 | |||
281 | write_ctree_super(trans, root); | 298 | write_ctree_super(trans, root); |
299 | |||
300 | mutex_lock(&root->fs_info->fs_mutex); | ||
282 | btrfs_finish_extent_commit(trans, root); | 301 | btrfs_finish_extent_commit(trans, root); |
283 | mutex_lock(&root->fs_info->trans_mutex); | 302 | mutex_lock(&root->fs_info->trans_mutex); |
284 | cur_trans->commit_done = 1; | 303 | cur_trans->commit_done = 1; |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 4f1496ae6f24..3cc29900a074 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -8,6 +8,7 @@ struct btrfs_transaction { | |||
8 | int use_count; | 8 | int use_count; |
9 | int commit_done; | 9 | int commit_done; |
10 | int magic; | 10 | int magic; |
11 | struct list_head list; | ||
11 | wait_queue_head_t writer_wait; | 12 | wait_queue_head_t writer_wait; |
12 | wait_queue_head_t commit_wait; | 13 | wait_queue_head_t commit_wait; |
13 | }; | 14 | }; |