diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-01-08 15:46:30 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:59 -0400 |
commit | 3063d29f2a4d4a4e9fa1ec77c124514f287c6da7 (patch) | |
tree | 61aa53d18c6684a327b6166764eecbea9d0e6b5b /fs/btrfs/inode.c | |
parent | dc17ff8f11d129db9e83ab7244769e4eae05e14d (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.c | 79 |
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 | ||
2251 | static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | 2251 | static 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); | ||
2307 | printk("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; | ||
2330 | fail: | ||
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; | ||
2336 | fail_unlock: | 2287 | fail_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); |