diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2009-09-21 15:56:00 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-09-21 15:56:00 -0400 |
commit | 4df27c4d5cc1dda54ed7d0a8389347f2df359cf9 (patch) | |
tree | 2008f348d28c6c19e31924ae4fb414ca929a01f1 /fs/btrfs/root-tree.c | |
parent | 13a8a7c8c47e542b3cdb45bec3f431f96af79361 (diff) |
Btrfs: change how subvolumes are organized
btrfs allows subvolumes and snapshots anywhere in the directory tree.
If we snapshot a subvolume that contains a link to other subvolume
called subvolA, subvolA can be accessed through both the original
subvolume and the snapshot. This is similar to creating hard link to
directory, and has the very similar problems.
The aim of this patch is enforcing there is only one access point to
each subvolume. Only the first directory entry (the one added when
the subvolume/snapshot was created) is treated as valid access point.
The first directory entry is distinguished by checking root forward
reference. If the corresponding root forward reference is missing,
we know the entry is not the first one.
This patch also adds snapshot/subvolume rename support, the code
allows rename subvolume link across subvolumes.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/root-tree.c')
-rw-r--r-- | fs/btrfs/root-tree.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 0ddc6d61c55a..5ef72599a581 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -278,31 +278,57 @@ out: | |||
278 | return ret; | 278 | return ret; |
279 | } | 279 | } |
280 | 280 | ||
281 | #if 0 /* this will get used when snapshot deletion is implemented */ | ||
282 | int btrfs_del_root_ref(struct btrfs_trans_handle *trans, | 281 | int btrfs_del_root_ref(struct btrfs_trans_handle *trans, |
283 | struct btrfs_root *tree_root, | 282 | struct btrfs_root *tree_root, |
284 | u64 root_id, u8 type, u64 ref_id) | 283 | u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, |
284 | const char *name, int name_len) | ||
285 | |||
285 | { | 286 | { |
287 | struct btrfs_path *path; | ||
288 | struct btrfs_root_ref *ref; | ||
289 | struct extent_buffer *leaf; | ||
286 | struct btrfs_key key; | 290 | struct btrfs_key key; |
291 | unsigned long ptr; | ||
292 | int err = 0; | ||
287 | int ret; | 293 | int ret; |
288 | struct btrfs_path *path; | ||
289 | 294 | ||
290 | path = btrfs_alloc_path(); | 295 | path = btrfs_alloc_path(); |
296 | if (!path) | ||
297 | return -ENOMEM; | ||
291 | 298 | ||
292 | key.objectid = root_id; | 299 | key.objectid = root_id; |
293 | key.type = type; | 300 | key.type = BTRFS_ROOT_BACKREF_KEY; |
294 | key.offset = ref_id; | 301 | key.offset = ref_id; |
295 | 302 | again: | |
296 | ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); | 303 | ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); |
297 | BUG_ON(ret); | 304 | BUG_ON(ret < 0); |
298 | 305 | if (ret == 0) { | |
299 | ret = btrfs_del_item(trans, tree_root, path); | 306 | leaf = path->nodes[0]; |
300 | BUG_ON(ret); | 307 | ref = btrfs_item_ptr(leaf, path->slots[0], |
308 | struct btrfs_root_ref); | ||
309 | |||
310 | WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid); | ||
311 | WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len); | ||
312 | ptr = (unsigned long)(ref + 1); | ||
313 | WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len)); | ||
314 | *sequence = btrfs_root_ref_sequence(leaf, ref); | ||
315 | |||
316 | ret = btrfs_del_item(trans, tree_root, path); | ||
317 | BUG_ON(ret); | ||
318 | } else | ||
319 | err = -ENOENT; | ||
320 | |||
321 | if (key.type == BTRFS_ROOT_BACKREF_KEY) { | ||
322 | btrfs_release_path(tree_root, path); | ||
323 | key.objectid = ref_id; | ||
324 | key.type = BTRFS_ROOT_REF_KEY; | ||
325 | key.offset = root_id; | ||
326 | goto again; | ||
327 | } | ||
301 | 328 | ||
302 | btrfs_free_path(path); | 329 | btrfs_free_path(path); |
303 | return ret; | 330 | return err; |
304 | } | 331 | } |
305 | #endif | ||
306 | 332 | ||
307 | int btrfs_find_root_ref(struct btrfs_root *tree_root, | 333 | int btrfs_find_root_ref(struct btrfs_root *tree_root, |
308 | struct btrfs_path *path, | 334 | struct btrfs_path *path, |
@@ -319,7 +345,6 @@ int btrfs_find_root_ref(struct btrfs_root *tree_root, | |||
319 | return ret; | 345 | return ret; |
320 | } | 346 | } |
321 | 347 | ||
322 | |||
323 | /* | 348 | /* |
324 | * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY | 349 | * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY |
325 | * or BTRFS_ROOT_BACKREF_KEY. | 350 | * or BTRFS_ROOT_BACKREF_KEY. |
@@ -335,8 +360,7 @@ int btrfs_find_root_ref(struct btrfs_root *tree_root, | |||
335 | */ | 360 | */ |
336 | int btrfs_add_root_ref(struct btrfs_trans_handle *trans, | 361 | int btrfs_add_root_ref(struct btrfs_trans_handle *trans, |
337 | struct btrfs_root *tree_root, | 362 | struct btrfs_root *tree_root, |
338 | u64 root_id, u8 type, u64 ref_id, | 363 | u64 root_id, u64 ref_id, u64 dirid, u64 sequence, |
339 | u64 dirid, u64 sequence, | ||
340 | const char *name, int name_len) | 364 | const char *name, int name_len) |
341 | { | 365 | { |
342 | struct btrfs_key key; | 366 | struct btrfs_key key; |
@@ -346,13 +370,14 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, | |||
346 | struct extent_buffer *leaf; | 370 | struct extent_buffer *leaf; |
347 | unsigned long ptr; | 371 | unsigned long ptr; |
348 | 372 | ||
349 | |||
350 | path = btrfs_alloc_path(); | 373 | path = btrfs_alloc_path(); |
374 | if (!path) | ||
375 | return -ENOMEM; | ||
351 | 376 | ||
352 | key.objectid = root_id; | 377 | key.objectid = root_id; |
353 | key.type = type; | 378 | key.type = BTRFS_ROOT_BACKREF_KEY; |
354 | key.offset = ref_id; | 379 | key.offset = ref_id; |
355 | 380 | again: | |
356 | ret = btrfs_insert_empty_item(trans, tree_root, path, &key, | 381 | ret = btrfs_insert_empty_item(trans, tree_root, path, &key, |
357 | sizeof(*ref) + name_len); | 382 | sizeof(*ref) + name_len); |
358 | BUG_ON(ret); | 383 | BUG_ON(ret); |
@@ -366,6 +391,14 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, | |||
366 | write_extent_buffer(leaf, name, ptr, name_len); | 391 | write_extent_buffer(leaf, name, ptr, name_len); |
367 | btrfs_mark_buffer_dirty(leaf); | 392 | btrfs_mark_buffer_dirty(leaf); |
368 | 393 | ||
394 | if (key.type == BTRFS_ROOT_BACKREF_KEY) { | ||
395 | btrfs_release_path(tree_root, path); | ||
396 | key.objectid = ref_id; | ||
397 | key.type = BTRFS_ROOT_REF_KEY; | ||
398 | key.offset = root_id; | ||
399 | goto again; | ||
400 | } | ||
401 | |||
369 | btrfs_free_path(path); | 402 | btrfs_free_path(path); |
370 | return ret; | 403 | return 0; |
371 | } | 404 | } |