aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/root-tree.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2009-09-21 15:56:00 -0400
committerChris Mason <chris.mason@oracle.com>2009-09-21 15:56:00 -0400
commit4df27c4d5cc1dda54ed7d0a8389347f2df359cf9 (patch)
tree2008f348d28c6c19e31924ae4fb414ca929a01f1 /fs/btrfs/root-tree.c
parent13a8a7c8c47e542b3cdb45bec3f431f96af79361 (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.c69
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 */
282int btrfs_del_root_ref(struct btrfs_trans_handle *trans, 281int 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 302again:
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
307int btrfs_find_root_ref(struct btrfs_root *tree_root, 333int 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 */
336int btrfs_add_root_ref(struct btrfs_trans_handle *trans, 361int 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 380again:
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}