aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-01-08 15:46:30 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:59 -0400
commit3063d29f2a4d4a4e9fa1ec77c124514f287c6da7 (patch)
tree61aa53d18c6684a327b6166764eecbea9d0e6b5b /fs/btrfs/inode.c
parentdc17ff8f11d129db9e83ab7244769e4eae05e14d (diff)
Btrfs: Move snapshot creation to commit time
It is very difficult to create a consistent snapshot of the btree when other writers may update the btree before the commit is done. This changes the snapshot creation to happen during the commit, while no other updates are possible. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c79
1 files changed, 15 insertions, 64 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6d6e1ac0a9a0..10cece11dbd8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2250,13 +2250,10 @@ fail_commit:
2250 2250
2251static int create_snapshot(struct btrfs_root *root, char *name, int namelen) 2251static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2252{ 2252{
2253 struct btrfs_pending_snapshot *pending_snapshot;
2253 struct btrfs_trans_handle *trans; 2254 struct btrfs_trans_handle *trans;
2254 struct btrfs_key key;
2255 struct btrfs_root_item new_root_item;
2256 struct extent_buffer *tmp;
2257 int ret; 2255 int ret;
2258 int err; 2256 int err;
2259 u64 objectid;
2260 unsigned long nr = 0; 2257 unsigned long nr = 0;
2261 2258
2262 if (!root->ref_cows) 2259 if (!root->ref_cows)
@@ -2267,72 +2264,26 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2267 if (ret) 2264 if (ret)
2268 goto fail_unlock; 2265 goto fail_unlock;
2269 2266
2267 pending_snapshot = kmalloc(sizeof(*pending_snapshot), GFP_NOFS);
2268 if (!pending_snapshot) {
2269 ret = -ENOMEM;
2270 goto fail_unlock;
2271 }
2272 pending_snapshot->name = kstrndup(name, namelen, GFP_NOFS);
2273 if (!pending_snapshot->name) {
2274 ret = -ENOMEM;
2275 kfree(pending_snapshot);
2276 goto fail_unlock;
2277 }
2270 trans = btrfs_start_transaction(root, 1); 2278 trans = btrfs_start_transaction(root, 1);
2271 BUG_ON(!trans); 2279 BUG_ON(!trans);
2272 err = btrfs_commit_transaction(trans, root);
2273
2274 trans = btrfs_start_transaction(root, 1);
2275 2280
2281 pending_snapshot->root = root;
2282 list_add(&pending_snapshot->list,
2283 &trans->transaction->pending_snapshots);
2276 ret = btrfs_update_inode(trans, root, root->inode); 2284 ret = btrfs_update_inode(trans, root, root->inode);
2277 if (ret)
2278 goto fail;
2279
2280 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2281 0, &objectid);
2282 if (ret)
2283 goto fail; memcpy(&new_root_item, &root->root_item,
2284 sizeof(new_root_item));
2285
2286 key.objectid = objectid;
2287 key.offset = 1;
2288 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
2289
2290 extent_buffer_get(root->node);
2291 btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
2292 free_extent_buffer(tmp);
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
2301 btrfs_copy_root(trans, root, root->node, &tmp, objectid);
2302
2303 btrfs_set_root_bytenr(&new_root_item, tmp->start);
2304 btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp));
2305 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2306 &new_root_item);
2307printk("new root %Lu node %Lu\n", objectid, tmp->start);
2308 free_extent_buffer(tmp);
2309 if (ret)
2310 goto fail;
2311
2312 /*
2313 * insert the directory item
2314 */
2315 key.offset = (u64)-1;
2316 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
2317 name, namelen,
2318 root->fs_info->sb->s_root->d_inode->i_ino,
2319 &key, BTRFS_FT_DIR);
2320
2321 if (ret)
2322 goto fail;
2323
2324 ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
2325 name, namelen, objectid,
2326 root->fs_info->sb->s_root->d_inode->i_ino);
2327
2328 if (ret)
2329 goto fail;
2330fail:
2331 nr = trans->blocks_used;
2332 err = btrfs_commit_transaction(trans, root); 2285 err = btrfs_commit_transaction(trans, root);
2333 2286
2334 if (err && !ret)
2335 ret = err;
2336fail_unlock: 2287fail_unlock:
2337 mutex_unlock(&root->fs_info->fs_mutex); 2288 mutex_unlock(&root->fs_info->fs_mutex);
2338 btrfs_btree_balance_dirty(root, nr); 2289 btrfs_btree_balance_dirty(root, nr);