aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/btrfs_inode.h1
-rw-r--r--fs/btrfs/ctree.c6
-rw-r--r--fs/btrfs/ctree.h7
-rw-r--r--fs/btrfs/disk-io.c16
-rw-r--r--fs/btrfs/disk-io.h2
-rw-r--r--fs/btrfs/extent-tree.c4
-rw-r--r--fs/btrfs/file.c5
-rw-r--r--fs/btrfs/inode.c46
-rw-r--r--fs/btrfs/ordered-data.c221
-rw-r--r--fs/btrfs/ordered-data.h39
-rw-r--r--fs/btrfs/transaction.c58
-rw-r--r--fs/btrfs/transaction.h8
13 files changed, 387 insertions, 28 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index d5804c5ca075..ab9a9f8edbf8 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -5,7 +5,7 @@ obj-m := btrfs.o
5btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ 5btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
6 hash.o file-item.o inode-item.o inode-map.o disk-io.o \ 6 hash.o file-item.o inode-item.o inode-map.o disk-io.o \
7 transaction.o bit-radix.o inode.o file.o tree-defrag.o \ 7 transaction.o bit-radix.o inode.o file.o tree-defrag.o \
8 extent_map.o sysfs.o struct-funcs.o xattr.o acl.o 8 extent_map.o sysfs.o struct-funcs.o xattr.o acl.o ordered-data.o
9 9
10#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ 10#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
11# root-tree.o dir-item.o hash.o file-item.o inode-item.o \ 11# root-tree.o dir-item.o hash.o file-item.o inode-item.o \
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index d1d5af471c3c..f27e633f1742 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -29,6 +29,7 @@ struct btrfs_inode {
29 struct extent_map_tree extent_tree; 29 struct extent_map_tree extent_tree;
30 struct inode vfs_inode; 30 struct inode vfs_inode;
31 31
32 u64 ordered_trans;
32 /* 33 /*
33 * transid of the trans_handle that last modified this inode 34 * transid of the trans_handle that last modified this inode
34 */ 35 */
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 35c57074a376..43d23148a4fe 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -221,7 +221,9 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
221 struct extent_buffer **cow_ret) 221 struct extent_buffer **cow_ret)
222{ 222{
223 u64 search_start; 223 u64 search_start;
224 u64 header_trans;
224 int ret; 225 int ret;
226
225 if (trans->transaction != root->fs_info->running_transaction) { 227 if (trans->transaction != root->fs_info->running_transaction) {
226 printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, 228 printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
227 root->fs_info->running_transaction->transid); 229 root->fs_info->running_transaction->transid);
@@ -232,7 +234,9 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
232 root->fs_info->generation); 234 root->fs_info->generation);
233 WARN_ON(1); 235 WARN_ON(1);
234 } 236 }
235 if (btrfs_header_generation(buf) == trans->transid) { 237
238 header_trans = btrfs_header_generation(buf);
239 if (header_trans == trans->transid) {
236 *cow_ret = buf; 240 *cow_ret = buf;
237 return 0; 241 return 0;
238 } 242 }
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 9873975ce0ee..b55dba58dfaa 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -16,8 +16,8 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#ifndef __BTRFS__ 19#ifndef __BTRFS_CTREE__
20#define __BTRFS__ 20#define __BTRFS_CTREE__
21 21
22#include <linux/version.h> 22#include <linux/version.h>
23#include <linux/mm.h> 23#include <linux/mm.h>
@@ -363,7 +363,6 @@ struct btrfs_root {
363 struct inode *inode; 363 struct inode *inode;
364 struct kobject root_kobj; 364 struct kobject root_kobj;
365 struct completion kobj_unregister; 365 struct completion kobj_unregister;
366 struct rw_semaphore snap_sem;
367 u64 objectid; 366 u64 objectid;
368 u64 last_trans; 367 u64 last_trans;
369 368
@@ -1142,6 +1141,8 @@ void btrfs_destroy_cachep(void);
1142long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 1141long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
1143struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, 1142struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
1144 struct btrfs_root *root); 1143 struct btrfs_root *root);
1144struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
1145 u64 root_objectid);
1145int btrfs_commit_write(struct file *file, struct page *page, 1146int btrfs_commit_write(struct file *file, struct page *page,
1146 unsigned from, unsigned to); 1147 unsigned from, unsigned to);
1147struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, 1148struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a6170ff19e7f..34cf1f1f47be 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -406,7 +406,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
406 memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); 406 memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
407 memset(&root->root_kobj, 0, sizeof(root->root_kobj)); 407 memset(&root->root_kobj, 0, sizeof(root->root_kobj));
408 init_completion(&root->kobj_unregister); 408 init_completion(&root->kobj_unregister);
409 init_rwsem(&root->snap_sem);
410 root->defrag_running = 0; 409 root->defrag_running = 0;
411 root->defrag_level = 0; 410 root->defrag_level = 0;
412 root->root_key.objectid = objectid; 411 root->root_key.objectid = objectid;
@@ -498,6 +497,21 @@ insert:
498 return root; 497 return root;
499} 498}
500 499
500struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
501 u64 root_objectid)
502{
503 struct btrfs_root *root;
504
505 if (root_objectid == BTRFS_ROOT_TREE_OBJECTID)
506 return fs_info->tree_root;
507 if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID)
508 return fs_info->extent_root;
509
510 root = radix_tree_lookup(&fs_info->fs_roots_radix,
511 (unsigned long)root_objectid);
512 return root;
513}
514
501struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, 515struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
502 struct btrfs_key *location) 516 struct btrfs_key *location)
503{ 517{
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 8c3cfd02901f..dae9fba8efcd 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -34,6 +34,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
34 struct btrfs_root *root); 34 struct btrfs_root *root);
35struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, 35struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
36 u64 bytenr, u32 blocksize); 36 u64 bytenr, u32 blocksize);
37struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
38 u64 root_objectid);
37struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 39struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
38 struct btrfs_key *location, 40 struct btrfs_key *location,
39 const char *name, int namelen); 41 const char *name, int namelen);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c906bb19b211..68137cd8506a 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1195,7 +1195,9 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
1195 if (btrfs_buffer_uptodate(buf)) { 1195 if (btrfs_buffer_uptodate(buf)) {
1196 u64 transid = 1196 u64 transid =
1197 root->fs_info->running_transaction->transid; 1197 root->fs_info->running_transaction->transid;
1198 if (btrfs_header_generation(buf) == transid) { 1198 u64 header_transid =
1199 btrfs_header_generation(buf);
1200 if (header_transid == transid) {
1199 free_extent_buffer(buf); 1201 free_extent_buffer(buf);
1200 return 1; 1202 return 1;
1201 } 1203 }
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 94c93373cb7d..0a5f4defe59b 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -34,6 +34,7 @@
34#include "disk-io.h" 34#include "disk-io.h"
35#include "transaction.h" 35#include "transaction.h"
36#include "btrfs_inode.h" 36#include "btrfs_inode.h"
37#include "ordered-data.h"
37#include "ioctl.h" 38#include "ioctl.h"
38#include "print-tree.h" 39#include "print-tree.h"
39 40
@@ -329,6 +330,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
329 root->fs_info->delalloc_bytes += (end_of_last_block + 1 - 330 root->fs_info->delalloc_bytes += (end_of_last_block + 1 -
330 start_pos) - existing_delalloc; 331 start_pos) - existing_delalloc;
331 spin_unlock(&root->fs_info->delalloc_lock); 332 spin_unlock(&root->fs_info->delalloc_lock);
333 btrfs_add_ordered_inode(inode);
332 } else { 334 } else {
333 u64 aligned_end; 335 u64 aligned_end;
334 /* step one, delete the existing extents in this range */ 336 /* step one, delete the existing extents in this range */
@@ -724,8 +726,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
724 726
725 pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL); 727 pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
726 728
727 down_read(&BTRFS_I(inode)->root->snap_sem);
728
729 mutex_lock(&inode->i_mutex); 729 mutex_lock(&inode->i_mutex);
730 first_index = pos >> PAGE_CACHE_SHIFT; 730 first_index = pos >> PAGE_CACHE_SHIFT;
731 last_index = (pos + count) >> PAGE_CACHE_SHIFT; 731 last_index = (pos + count) >> PAGE_CACHE_SHIFT;
@@ -804,7 +804,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
804 } 804 }
805out: 805out:
806 mutex_unlock(&inode->i_mutex); 806 mutex_unlock(&inode->i_mutex);
807 up_read(&BTRFS_I(inode)->root->snap_sem);
808 807
809out_nolock: 808out_nolock:
810 kfree(pages); 809 kfree(pages);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6d0cd9a7a615..6d6e1ac0a9a0 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -135,6 +135,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
135 alloc_hint = ins.objectid + ins.offset; 135 alloc_hint = ins.objectid + ins.offset;
136 start += cur_alloc_size; 136 start += cur_alloc_size;
137 } 137 }
138 btrfs_add_ordered_inode(inode);
138out: 139out:
139 btrfs_end_transaction(trans, root); 140 btrfs_end_transaction(trans, root);
140 return ret; 141 return ret;
@@ -367,8 +368,8 @@ void btrfs_read_locked_inode(struct inode *inode)
367 path = btrfs_alloc_path(); 368 path = btrfs_alloc_path();
368 BUG_ON(!path); 369 BUG_ON(!path);
369 mutex_lock(&root->fs_info->fs_mutex); 370 mutex_lock(&root->fs_info->fs_mutex);
370
371 memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); 371 memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
372
372 ret = btrfs_lookup_inode(NULL, root, path, &location, 0); 373 ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
373 if (ret) 374 if (ret)
374 goto make_bad; 375 goto make_bad;
@@ -898,7 +899,6 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
898 if ((offset & (blocksize - 1)) == 0) 899 if ((offset & (blocksize - 1)) == 0)
899 goto out; 900 goto out;
900 901
901 down_read(&root->snap_sem);
902 ret = -ENOMEM; 902 ret = -ENOMEM;
903 page = grab_cache_page(mapping, index); 903 page = grab_cache_page(mapping, index);
904 if (!page) 904 if (!page)
@@ -917,7 +917,6 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
917 917
918 unlock_page(page); 918 unlock_page(page);
919 page_cache_release(page); 919 page_cache_release(page);
920 up_read(&BTRFS_I(inode)->root->snap_sem);
921out: 920out:
922 return ret; 921 return ret;
923} 922}
@@ -1146,6 +1145,19 @@ static int btrfs_find_actor(struct inode *inode, void *opaque)
1146 args->root == BTRFS_I(inode)->root); 1145 args->root == BTRFS_I(inode)->root);
1147} 1146}
1148 1147
1148struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
1149 u64 root_objectid)
1150{
1151 struct btrfs_iget_args args;
1152 args.ino = objectid;
1153 args.root = btrfs_lookup_fs_root(btrfs_sb(s)->fs_info, root_objectid);
1154
1155 if (!args.root)
1156 return NULL;
1157
1158 return ilookup5(s, objectid, btrfs_find_actor, (void *)&args);
1159}
1160
1149struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, 1161struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
1150 struct btrfs_root *root) 1162 struct btrfs_root *root)
1151{ 1163{
@@ -1336,7 +1348,6 @@ read_dir_items:
1336 1348
1337 d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; 1349 d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
1338 btrfs_dir_item_key_to_cpu(leaf, di, &location); 1350 btrfs_dir_item_key_to_cpu(leaf, di, &location);
1339
1340 over = filldir(dirent, name_ptr, name_len, 1351 over = filldir(dirent, name_ptr, name_len,
1341 found_key.offset, 1352 found_key.offset,
1342 location.objectid, 1353 location.objectid,
@@ -2054,7 +2065,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
2054 2065
2055 ret = -EINVAL; 2066 ret = -EINVAL;
2056 2067
2057 down_read(&BTRFS_I(inode)->root->snap_sem);
2058 lock_page(page); 2068 lock_page(page);
2059 wait_on_page_writeback(page); 2069 wait_on_page_writeback(page);
2060 size = i_size_read(inode); 2070 size = i_size_read(inode);
@@ -2075,7 +2085,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
2075 ret = btrfs_cow_one_page(inode, page, end); 2085 ret = btrfs_cow_one_page(inode, page, end);
2076 2086
2077out_unlock: 2087out_unlock:
2078 up_read(&BTRFS_I(inode)->root->snap_sem);
2079 unlock_page(page); 2088 unlock_page(page);
2080out: 2089out:
2081 return ret; 2090 return ret;
@@ -2118,7 +2127,7 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
2118 struct btrfs_root_item root_item; 2127 struct btrfs_root_item root_item;
2119 struct btrfs_inode_item *inode_item; 2128 struct btrfs_inode_item *inode_item;
2120 struct extent_buffer *leaf; 2129 struct extent_buffer *leaf;
2121 struct btrfs_root *new_root; 2130 struct btrfs_root *new_root = root;
2122 struct inode *inode; 2131 struct inode *inode;
2123 struct inode *dir; 2132 struct inode *dir;
2124 int ret; 2133 int ret;
@@ -2230,7 +2239,7 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
2230 goto fail; 2239 goto fail;
2231fail: 2240fail:
2232 nr = trans->blocks_used; 2241 nr = trans->blocks_used;
2233 err = btrfs_commit_transaction(trans, root); 2242 err = btrfs_commit_transaction(trans, new_root);
2234 if (err && !ret) 2243 if (err && !ret)
2235 ret = err; 2244 ret = err;
2236fail_commit: 2245fail_commit:
@@ -2253,10 +2262,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2253 if (!root->ref_cows) 2262 if (!root->ref_cows)
2254 return -EINVAL; 2263 return -EINVAL;
2255 2264
2256 down_write(&root->snap_sem);
2257 freeze_bdev(root->fs_info->sb->s_bdev);
2258 thaw_bdev(root->fs_info->sb->s_bdev, root->fs_info->sb);
2259
2260 mutex_lock(&root->fs_info->fs_mutex); 2265 mutex_lock(&root->fs_info->fs_mutex);
2261 ret = btrfs_check_free_space(root, 1, 0); 2266 ret = btrfs_check_free_space(root, 1, 0);
2262 if (ret) 2267 if (ret)
@@ -2264,6 +2269,9 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2264 2269
2265 trans = btrfs_start_transaction(root, 1); 2270 trans = btrfs_start_transaction(root, 1);
2266 BUG_ON(!trans); 2271 BUG_ON(!trans);
2272 err = btrfs_commit_transaction(trans, root);
2273
2274 trans = btrfs_start_transaction(root, 1);
2267 2275
2268 ret = btrfs_update_inode(trans, root, root->inode); 2276 ret = btrfs_update_inode(trans, root, root->inode);
2269 if (ret) 2277 if (ret)
@@ -2272,9 +2280,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2272 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, 2280 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2273 0, &objectid); 2281 0, &objectid);
2274 if (ret) 2282 if (ret)
2275 goto fail; 2283 goto fail; memcpy(&new_root_item, &root->root_item,
2276
2277 memcpy(&new_root_item, &root->root_item,
2278 sizeof(new_root_item)); 2284 sizeof(new_root_item));
2279 2285
2280 key.objectid = objectid; 2286 key.objectid = objectid;
@@ -2285,12 +2291,20 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2285 btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); 2291 btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
2286 free_extent_buffer(tmp); 2292 free_extent_buffer(tmp);
2287 2293
2294 /* write the ordered inodes to force all delayed allocations to
2295 * be filled. Once this is done, we can copy the root
2296 */
2297 mutex_lock(&root->fs_info->trans_mutex);
2298 btrfs_write_ordered_inodes(trans, root);
2299 mutex_unlock(&root->fs_info->trans_mutex);
2300
2288 btrfs_copy_root(trans, root, root->node, &tmp, objectid); 2301 btrfs_copy_root(trans, root, root->node, &tmp, objectid);
2289 2302
2290 btrfs_set_root_bytenr(&new_root_item, tmp->start); 2303 btrfs_set_root_bytenr(&new_root_item, tmp->start);
2291 btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp)); 2304 btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp));
2292 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, 2305 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2293 &new_root_item); 2306 &new_root_item);
2307printk("new root %Lu node %Lu\n", objectid, tmp->start);
2294 free_extent_buffer(tmp); 2308 free_extent_buffer(tmp);
2295 if (ret) 2309 if (ret)
2296 goto fail; 2310 goto fail;
@@ -2321,7 +2335,6 @@ fail:
2321 ret = err; 2335 ret = err;
2322fail_unlock: 2336fail_unlock:
2323 mutex_unlock(&root->fs_info->fs_mutex); 2337 mutex_unlock(&root->fs_info->fs_mutex);
2324 up_write(&root->snap_sem);
2325 btrfs_btree_balance_dirty(root, nr); 2338 btrfs_btree_balance_dirty(root, nr);
2326 return ret; 2339 return ret;
2327} 2340}
@@ -2608,6 +2621,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
2608 if (!ei) 2621 if (!ei)
2609 return NULL; 2622 return NULL;
2610 ei->last_trans = 0; 2623 ei->last_trans = 0;
2624 ei->ordered_trans = 0;
2611 return &ei->vfs_inode; 2625 return &ei->vfs_inode;
2612} 2626}
2613 2627
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
new file mode 100644
index 000000000000..411aba84d305
--- /dev/null
+++ b/fs/btrfs/ordered-data.c
@@ -0,0 +1,221 @@
1/*
2 * Copyright (C) 2007 Oracle. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19#include <linux/gfp.h>
20#include <linux/slab.h>
21#include "ctree.h"
22#include "transaction.h"
23#include "btrfs_inode.h"
24
25struct tree_entry {
26 u64 root_objectid;
27 u64 objectid;
28 struct rb_node rb_node;
29};
30
31/*
32 * returns > 0 if entry passed (root, objectid) is > entry,
33 * < 0 if (root, objectid) < entry and zero if they are equal
34 */
35static int comp_entry(struct tree_entry *entry, u64 root_objectid,
36 u64 objectid)
37{
38 if (root_objectid < entry->root_objectid)
39 return -1;
40 if (root_objectid > entry->root_objectid)
41 return 1;
42 if (objectid < entry->objectid)
43 return -1;
44 if (objectid > entry->objectid)
45 return 1;
46 return 0;
47}
48
49static struct rb_node *tree_insert(struct rb_root *root, u64 root_objectid,
50 u64 objectid, struct rb_node *node)
51{
52 struct rb_node ** p = &root->rb_node;
53 struct rb_node * parent = NULL;
54 struct tree_entry *entry;
55 int comp;
56
57 while(*p) {
58 parent = *p;
59 entry = rb_entry(parent, struct tree_entry, rb_node);
60
61 comp = comp_entry(entry, root_objectid, objectid);
62 if (comp < 0)
63 p = &(*p)->rb_left;
64 else if (comp > 0)
65 p = &(*p)->rb_right;
66 else
67 return parent;
68 }
69
70 rb_link_node(node, parent, p);
71 rb_insert_color(node, root);
72 return NULL;
73}
74
75static struct rb_node *__tree_search(struct rb_root *root, u64 root_objectid,
76 u64 objectid, struct rb_node **prev_ret)
77{
78 struct rb_node * n = root->rb_node;
79 struct rb_node *prev = NULL;
80 struct tree_entry *entry;
81 struct tree_entry *prev_entry = NULL;
82 int comp;
83
84 while(n) {
85 entry = rb_entry(n, struct tree_entry, rb_node);
86 prev = n;
87 prev_entry = entry;
88 comp = comp_entry(entry, root_objectid, objectid);
89
90 if (comp < 0)
91 n = n->rb_left;
92 else if (comp > 0)
93 n = n->rb_right;
94 else
95 return n;
96 }
97 if (!prev_ret)
98 return NULL;
99
100 while(prev && comp_entry(prev_entry, root_objectid, objectid) >= 0) {
101 prev = rb_next(prev);
102 prev_entry = rb_entry(prev, struct tree_entry, rb_node);
103 }
104 *prev_ret = prev;
105 return NULL;
106}
107
108static inline struct rb_node *tree_search(struct rb_root *root,
109 u64 root_objectid, u64 objectid)
110{
111 struct rb_node *prev;
112 struct rb_node *ret;
113 ret = __tree_search(root, root_objectid, objectid, &prev);
114 if (!ret)
115 return prev;
116 return ret;
117}
118
119int btrfs_add_ordered_inode(struct inode *inode)
120{
121 struct btrfs_root *root = BTRFS_I(inode)->root;
122 u64 root_objectid = root->root_key.objectid;
123 u64 transid = root->fs_info->running_transaction->transid;
124 struct tree_entry *entry;
125 struct rb_node *node;
126 struct btrfs_ordered_inode_tree *tree;
127
128 if (transid <= BTRFS_I(inode)->ordered_trans)
129 return 0;
130
131 tree = &root->fs_info->running_transaction->ordered_inode_tree;
132
133 read_lock(&tree->lock);
134 node = __tree_search(&tree->tree, root_objectid, inode->i_ino, NULL);
135 read_unlock(&tree->lock);
136 if (node) {
137 return 0;
138 }
139
140 entry = kmalloc(sizeof(*entry), GFP_NOFS);
141 if (!entry)
142 return -ENOMEM;
143
144 write_lock(&tree->lock);
145 entry->objectid = inode->i_ino;
146 entry->root_objectid = root_objectid;
147
148 node = tree_insert(&tree->tree, root_objectid,
149 inode->i_ino, &entry->rb_node);
150
151 BTRFS_I(inode)->ordered_trans = transid;
152
153 write_unlock(&tree->lock);
154 if (node)
155 kfree(entry);
156 return 0;
157}
158
159int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
160 u64 *root_objectid, u64 *objectid)
161{
162 struct tree_entry *entry;
163 struct rb_node *node;
164
165 write_lock(&tree->lock);
166 node = tree_search(&tree->tree, *root_objectid, *objectid);
167 if (!node) {
168 write_unlock(&tree->lock);
169 return 0;
170 }
171 entry = rb_entry(node, struct tree_entry, rb_node);
172
173 while(comp_entry(entry, *root_objectid, *objectid) >= 0) {
174 node = rb_next(node);
175 if (!node)
176 break;
177 entry = rb_entry(node, struct tree_entry, rb_node);
178 }
179 if (!node) {
180 write_unlock(&tree->lock);
181 return 0;
182 }
183
184 *root_objectid = entry->root_objectid;
185 *objectid = entry->objectid;
186 write_unlock(&tree->lock);
187 return 1;
188}
189
190int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
191 u64 *root_objectid, u64 *objectid)
192{
193 struct tree_entry *entry;
194 struct rb_node *node;
195
196 write_lock(&tree->lock);
197 node = tree_search(&tree->tree, *root_objectid, *objectid);
198 if (!node) {
199 write_unlock(&tree->lock);
200 return 0;
201 }
202
203 entry = rb_entry(node, struct tree_entry, rb_node);
204 while(comp_entry(entry, *root_objectid, *objectid) >= 0) {
205 node = rb_next(node);
206 if (!node)
207 break;
208 entry = rb_entry(node, struct tree_entry, rb_node);
209 }
210 if (!node) {
211 write_unlock(&tree->lock);
212 return 0;
213 }
214
215 *root_objectid = entry->root_objectid;
216 *objectid = entry->objectid;
217 rb_erase(node, &tree->tree);
218 write_unlock(&tree->lock);
219 kfree(entry);
220 return 1;
221}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
new file mode 100644
index 000000000000..aaf9eb142719
--- /dev/null
+++ b/fs/btrfs/ordered-data.h
@@ -0,0 +1,39 @@
1/*
2 * Copyright (C) 2007 Oracle. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19#ifndef __BTRFS_ORDERED_DATA__
20#define __BTRFS_ORDERED_DATA__
21
22struct btrfs_ordered_inode_tree {
23 rwlock_t lock;
24 struct rb_root tree;
25};
26
27static inline void
28btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t)
29{
30 rwlock_init(&t->lock);
31 t->tree.rb_node = NULL;
32}
33
34int btrfs_add_ordered_inode(struct inode *inode);
35int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
36 u64 *root_objectid, u64 *objectid);
37int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
38 u64 *root_objectid, u64 *objectid);
39#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 02721eea9a7a..3ed5868e7c0f 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -67,6 +67,7 @@ static int join_transaction(struct btrfs_root *root)
67 cur_trans->commit_done = 0; 67 cur_trans->commit_done = 0;
68 cur_trans->start_time = get_seconds(); 68 cur_trans->start_time = get_seconds();
69 list_add_tail(&cur_trans->list, &root->fs_info->trans_list); 69 list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
70 btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree);
70 extent_map_tree_init(&cur_trans->dirty_pages, 71 extent_map_tree_init(&cur_trans->dirty_pages,
71 root->fs_info->btree_inode->i_mapping, 72 root->fs_info->btree_inode->i_mapping,
72 GFP_NOFS); 73 GFP_NOFS);
@@ -473,6 +474,60 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
473 return ret; 474 return ret;
474} 475}
475 476
477int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
478 struct btrfs_root *root)
479{
480 struct btrfs_transaction *cur_trans = trans->transaction;
481 struct inode *inode;
482 u64 root_objectid = 0;
483 u64 objectid = 0;
484 u64 transid = trans->transid;
485 int ret;
486
487printk("write ordered trans %Lu\n", transid);
488 while(1) {
489 ret = btrfs_find_first_ordered_inode(
490 &cur_trans->ordered_inode_tree,
491 &root_objectid, &objectid);
492 if (!ret)
493 break;
494
495 mutex_unlock(&root->fs_info->trans_mutex);
496 mutex_unlock(&root->fs_info->fs_mutex);
497 inode = btrfs_ilookup(root->fs_info->sb, objectid,
498 root_objectid);
499 if (inode) {
500 if (S_ISREG(inode->i_mode))
501 filemap_fdatawrite(inode->i_mapping);
502 iput(inode);
503 }
504 mutex_lock(&root->fs_info->fs_mutex);
505 mutex_lock(&root->fs_info->trans_mutex);
506 }
507 while(1) {
508 root_objectid = 0;
509 objectid = 0;
510 ret = btrfs_find_del_first_ordered_inode(
511 &cur_trans->ordered_inode_tree,
512 &root_objectid, &objectid);
513 if (!ret)
514 break;
515 mutex_unlock(&root->fs_info->trans_mutex);
516 mutex_unlock(&root->fs_info->fs_mutex);
517 inode = btrfs_ilookup(root->fs_info->sb, objectid,
518 root_objectid);
519 if (inode) {
520 if (S_ISREG(inode->i_mode))
521 filemap_write_and_wait(inode->i_mapping);
522 iput(inode);
523 }
524 mutex_lock(&root->fs_info->fs_mutex);
525 mutex_lock(&root->fs_info->trans_mutex);
526 }
527printk("done write ordered trans %Lu\n", transid);
528 return 0;
529}
530
476int btrfs_commit_transaction(struct btrfs_trans_handle *trans, 531int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
477 struct btrfs_root *root) 532 struct btrfs_root *root)
478{ 533{
@@ -550,10 +605,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
550 mutex_lock(&root->fs_info->fs_mutex); 605 mutex_lock(&root->fs_info->fs_mutex);
551 mutex_lock(&root->fs_info->trans_mutex); 606 mutex_lock(&root->fs_info->trans_mutex);
552 finish_wait(&cur_trans->writer_wait, &wait); 607 finish_wait(&cur_trans->writer_wait, &wait);
608 ret = btrfs_write_ordered_inodes(trans, root);
609
553 } while (cur_trans->num_writers > 1 || 610 } while (cur_trans->num_writers > 1 ||
554 (cur_trans->num_joined != joined)); 611 (cur_trans->num_joined != joined));
555 612
556 WARN_ON(cur_trans != trans->transaction); 613 WARN_ON(cur_trans != trans->transaction);
614
557 ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, 615 ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix,
558 &dirty_fs_roots); 616 &dirty_fs_roots);
559 BUG_ON(ret); 617 BUG_ON(ret);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index eef840bca91e..c157ddbe9d1e 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -16,9 +16,10 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#ifndef __TRANSACTION__ 19#ifndef __BTRFS_TRANSACTION__
20#define __TRANSACTION__ 20#define __BTRFS_TRANSACTION__
21#include "btrfs_inode.h" 21#include "btrfs_inode.h"
22#include "ordered-data.h"
22 23
23struct btrfs_transaction { 24struct btrfs_transaction {
24 u64 transid; 25 u64 transid;
@@ -30,6 +31,7 @@ struct btrfs_transaction {
30 struct list_head list; 31 struct list_head list;
31 struct extent_map_tree dirty_pages; 32 struct extent_map_tree dirty_pages;
32 unsigned long start_time; 33 unsigned long start_time;
34 struct btrfs_ordered_inode_tree ordered_inode_tree;
33 wait_queue_head_t writer_wait; 35 wait_queue_head_t writer_wait;
34 wait_queue_head_t commit_wait; 36 wait_queue_head_t commit_wait;
35}; 37};
@@ -90,4 +92,6 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly);
90int btrfs_clean_old_snapshots(struct btrfs_root *root); 92int btrfs_clean_old_snapshots(struct btrfs_root *root);
91int btrfs_commit_transaction(struct btrfs_trans_handle *trans, 93int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
92 struct btrfs_root *root); 94 struct btrfs_root *root);
95int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
96 struct btrfs_root *root);
93#endif 97#endif