aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2009-12-04 12:38:27 -0500
committerChris Mason <chris.mason@oracle.com>2010-03-15 10:58:13 -0400
commit73f73415caddbc01d9f10c03e0a677d5b3d11569 (patch)
tree249ef103a73e8d99efe409b7988b694537b3d6ad /fs
parent12534832cb7b0abc7369298246e8b7af03b863ca (diff)
Btrfs: change how we mount subvolumes
This work is in preperation for being able to set a different root as the default mounting root. There is currently a problem with how we mount subvolumes. We cannot currently mount a subvolume of a subvolume, you can only mount subvolumes/snapshots of the default subvolume. So say you take a snapshot of the default subvolume and call it snap1, and then take a snapshot of snap1 and call it snap2, so now you have / /snap1 /snap1/snap2 as your available volumes. Currently you can only mount / and /snap1, you cannot mount /snap1/snap2. To fix this problem instead of passing subvolid=<name> you must pass in subvolid=<treeid>, where <treeid> is the tree id that gets spit out via the subvolume listing you get from the subvolume listing patches (btrfs filesystem list). This allows us to mount /, /snap1 and /snap1/snap2 as the root volume. In addition to the above, we also now read the default dir item in the tree root to get the root key that it points to. For now this just points at what has always been the default subvolme, but later on I plan to change it to point at whatever root you want to be the new default root, so you can just set the default mount and not have to mount with -o subvolid=<treeid>. I tested this out with the above scenario and it worked perfectly. Thanks, mount -o subvol operates inside the selected subvolid. For example: mount -o subvol=snap1,subvolid=256 /dev/xxx /mnt /mnt will have the snap1 directory for the subvolume with id 256. mount -o subvol=snap /dev/xxx /mnt /mnt will be the snap directory of whatever the default subvolume is. Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/export.c4
-rw-r--r--fs/btrfs/inode.c10
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/super.c172
-rw-r--r--fs/btrfs/tree-log.c2
6 files changed, 158 insertions, 34 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index abbce4d90c1b..07d956977a07 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2335,7 +2335,7 @@ int btrfs_init_cachep(void);
2335void btrfs_destroy_cachep(void); 2335void btrfs_destroy_cachep(void);
2336long btrfs_ioctl_trans_end(struct file *file); 2336long btrfs_ioctl_trans_end(struct file *file);
2337struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, 2337struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
2338 struct btrfs_root *root); 2338 struct btrfs_root *root, int *was_new);
2339int btrfs_commit_write(struct file *file, struct page *page, 2339int btrfs_commit_write(struct file *file, struct page *page,
2340 unsigned from, unsigned to); 2340 unsigned from, unsigned to);
2341struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, 2341struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index ba5c3fd5ab8c..951ef09b82f4 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -95,7 +95,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
95 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 95 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
96 key.offset = 0; 96 key.offset = 0;
97 97
98 inode = btrfs_iget(sb, &key, root); 98 inode = btrfs_iget(sb, &key, root, NULL);
99 if (IS_ERR(inode)) { 99 if (IS_ERR(inode)) {
100 err = PTR_ERR(inode); 100 err = PTR_ERR(inode);
101 goto fail; 101 goto fail;
@@ -223,7 +223,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
223 223
224 key.type = BTRFS_INODE_ITEM_KEY; 224 key.type = BTRFS_INODE_ITEM_KEY;
225 key.offset = 0; 225 key.offset = 0;
226 dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root)); 226 dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
227 if (!IS_ERR(dentry)) 227 if (!IS_ERR(dentry))
228 dentry->d_op = &btrfs_dentry_operations; 228 dentry->d_op = &btrfs_dentry_operations;
229 return dentry; 229 return dentry;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 4deb280f8969..7d10d1ccb0fe 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2153,7 +2153,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
2153 found_key.objectid = found_key.offset; 2153 found_key.objectid = found_key.offset;
2154 found_key.type = BTRFS_INODE_ITEM_KEY; 2154 found_key.type = BTRFS_INODE_ITEM_KEY;
2155 found_key.offset = 0; 2155 found_key.offset = 0;
2156 inode = btrfs_iget(root->fs_info->sb, &found_key, root); 2156 inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
2157 if (IS_ERR(inode)) 2157 if (IS_ERR(inode))
2158 break; 2158 break;
2159 2159
@@ -3687,7 +3687,7 @@ static struct inode *btrfs_iget_locked(struct super_block *s,
3687 * Returns in *is_new if the inode was read from disk 3687 * Returns in *is_new if the inode was read from disk
3688 */ 3688 */
3689struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, 3689struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
3690 struct btrfs_root *root) 3690 struct btrfs_root *root, int *new)
3691{ 3691{
3692 struct inode *inode; 3692 struct inode *inode;
3693 3693
@@ -3702,6 +3702,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
3702 3702
3703 inode_tree_add(inode); 3703 inode_tree_add(inode);
3704 unlock_new_inode(inode); 3704 unlock_new_inode(inode);
3705 if (new)
3706 *new = 1;
3705 } 3707 }
3706 3708
3707 return inode; 3709 return inode;
@@ -3754,7 +3756,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
3754 return NULL; 3756 return NULL;
3755 3757
3756 if (location.type == BTRFS_INODE_ITEM_KEY) { 3758 if (location.type == BTRFS_INODE_ITEM_KEY) {
3757 inode = btrfs_iget(dir->i_sb, &location, root); 3759 inode = btrfs_iget(dir->i_sb, &location, root, NULL);
3758 return inode; 3760 return inode;
3759 } 3761 }
3760 3762
@@ -3769,7 +3771,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
3769 else 3771 else
3770 inode = new_simple_dir(dir->i_sb, &location, sub_root); 3772 inode = new_simple_dir(dir->i_sb, &location, sub_root);
3771 } else { 3773 } else {
3772 inode = btrfs_iget(dir->i_sb, &location, sub_root); 3774 inode = btrfs_iget(dir->i_sb, &location, sub_root, NULL);
3773 } 3775 }
3774 srcu_read_unlock(&root->fs_info->subvol_srcu, index); 3776 srcu_read_unlock(&root->fs_info->subvol_srcu, index);
3775 3777
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 0109e5606bad..d52759daa53f 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3487,7 +3487,7 @@ static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
3487 key.objectid = objectid; 3487 key.objectid = objectid;
3488 key.type = BTRFS_INODE_ITEM_KEY; 3488 key.type = BTRFS_INODE_ITEM_KEY;
3489 key.offset = 0; 3489 key.offset = 0;
3490 inode = btrfs_iget(root->fs_info->sb, &key, root); 3490 inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
3491 BUG_ON(IS_ERR(inode) || is_bad_inode(inode)); 3491 BUG_ON(IS_ERR(inode) || is_bad_inode(inode));
3492 BTRFS_I(inode)->index_cnt = group->key.objectid; 3492 BTRFS_I(inode)->index_cnt = group->key.objectid;
3493 3493
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index f8b4521de907..f878337cee6f 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -63,10 +63,10 @@ static void btrfs_put_super(struct super_block *sb)
63} 63}
64 64
65enum { 65enum {
66 Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow, 66 Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum,
67 Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, 67 Opt_nodatacow, Opt_max_extent, Opt_max_inline, Opt_alloc_start,
68 Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, 68 Opt_nobarrier, Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool,
69 Opt_compress, Opt_compress_force, Opt_notreelog, Opt_ratio, 69 Opt_noacl, Opt_compress, Opt_compress_force, Opt_notreelog, Opt_ratio,
70 Opt_flushoncommit, 70 Opt_flushoncommit,
71 Opt_discard, Opt_err, 71 Opt_discard, Opt_err,
72}; 72};
@@ -74,6 +74,7 @@ enum {
74static match_table_t tokens = { 74static match_table_t tokens = {
75 {Opt_degraded, "degraded"}, 75 {Opt_degraded, "degraded"},
76 {Opt_subvol, "subvol=%s"}, 76 {Opt_subvol, "subvol=%s"},
77 {Opt_subvolid, "subvolid=%d"},
77 {Opt_device, "device=%s"}, 78 {Opt_device, "device=%s"},
78 {Opt_nodatasum, "nodatasum"}, 79 {Opt_nodatasum, "nodatasum"},
79 {Opt_nodatacow, "nodatacow"}, 80 {Opt_nodatacow, "nodatacow"},
@@ -157,6 +158,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
157 btrfs_set_opt(info->mount_opt, DEGRADED); 158 btrfs_set_opt(info->mount_opt, DEGRADED);
158 break; 159 break;
159 case Opt_subvol: 160 case Opt_subvol:
161 case Opt_subvolid:
160 case Opt_device: 162 case Opt_device:
161 /* 163 /*
162 * These are parsed by btrfs_parse_early_options 164 * These are parsed by btrfs_parse_early_options
@@ -292,12 +294,13 @@ out:
292 * only when we need to allocate a new super block. 294 * only when we need to allocate a new super block.
293 */ 295 */
294static int btrfs_parse_early_options(const char *options, fmode_t flags, 296static int btrfs_parse_early_options(const char *options, fmode_t flags,
295 void *holder, char **subvol_name, 297 void *holder, char **subvol_name, u64 *subvol_objectid,
296 struct btrfs_fs_devices **fs_devices) 298 struct btrfs_fs_devices **fs_devices)
297{ 299{
298 substring_t args[MAX_OPT_ARGS]; 300 substring_t args[MAX_OPT_ARGS];
299 char *opts, *p; 301 char *opts, *p;
300 int error = 0; 302 int error = 0;
303 int intarg;
301 304
302 if (!options) 305 if (!options)
303 goto out; 306 goto out;
@@ -320,6 +323,12 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
320 case Opt_subvol: 323 case Opt_subvol:
321 *subvol_name = match_strdup(&args[0]); 324 *subvol_name = match_strdup(&args[0]);
322 break; 325 break;
326 case Opt_subvolid:
327 intarg = 0;
328 match_int(&args[0], &intarg);
329 if (intarg)
330 *subvol_objectid = intarg;
331 break;
323 case Opt_device: 332 case Opt_device:
324 error = btrfs_scan_one_device(match_strdup(&args[0]), 333 error = btrfs_scan_one_device(match_strdup(&args[0]),
325 flags, holder, fs_devices); 334 flags, holder, fs_devices);
@@ -347,6 +356,110 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
347 return error; 356 return error;
348} 357}
349 358
359static struct dentry *get_default_root(struct super_block *sb,
360 u64 subvol_objectid)
361{
362 struct btrfs_root *root = sb->s_fs_info;
363 struct btrfs_root *new_root;
364 struct btrfs_dir_item *di;
365 struct btrfs_path *path;
366 struct btrfs_key location;
367 struct inode *inode;
368 struct dentry *dentry;
369 u64 dir_id;
370 int new = 0;
371
372 /*
373 * We have a specific subvol we want to mount, just setup location and
374 * go look up the root.
375 */
376 if (subvol_objectid) {
377 location.objectid = subvol_objectid;
378 location.type = BTRFS_ROOT_ITEM_KEY;
379 location.offset = (u64)-1;
380 goto find_root;
381 }
382
383 path = btrfs_alloc_path();
384 if (!path)
385 return ERR_PTR(-ENOMEM);
386 path->leave_spinning = 1;
387
388 /*
389 * Find the "default" dir item which points to the root item that we
390 * will mount by default if we haven't been given a specific subvolume
391 * to mount.
392 */
393 dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
394 di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
395 if (!di) {
396 /*
397 * Ok the default dir item isn't there. This is weird since
398 * it's always been there, but don't freak out, just try and
399 * mount to root most subvolume.
400 */
401 btrfs_free_path(path);
402 dir_id = BTRFS_FIRST_FREE_OBJECTID;
403 new_root = root->fs_info->fs_root;
404 goto setup_root;
405 }
406
407 btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
408 btrfs_free_path(path);
409
410find_root:
411 new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
412 if (IS_ERR(new_root))
413 return ERR_PTR(PTR_ERR(new_root));
414
415 if (btrfs_root_refs(&new_root->root_item) == 0)
416 return ERR_PTR(-ENOENT);
417
418 dir_id = btrfs_root_dirid(&new_root->root_item);
419setup_root:
420 location.objectid = dir_id;
421 location.type = BTRFS_INODE_ITEM_KEY;
422 location.offset = 0;
423
424 inode = btrfs_iget(sb, &location, new_root, &new);
425 if (!inode)
426 return ERR_PTR(-ENOMEM);
427
428 /*
429 * If we're just mounting the root most subvol put the inode and return
430 * a reference to the dentry. We will have already gotten a reference
431 * to the inode in btrfs_fill_super so we're good to go.
432 */
433 if (!new && sb->s_root->d_inode == inode) {
434 iput(inode);
435 return dget(sb->s_root);
436 }
437
438 if (new) {
439 const struct qstr name = { .name = "/", .len = 1 };
440
441 /*
442 * New inode, we need to make the dentry a sibling of s_root so
443 * everything gets cleaned up properly on unmount.
444 */
445 dentry = d_alloc(sb->s_root, &name);
446 if (!dentry) {
447 iput(inode);
448 return ERR_PTR(-ENOMEM);
449 }
450 d_splice_alias(inode, dentry);
451 } else {
452 /*
453 * We found the inode in cache, just find a dentry for it and
454 * put the reference to the inode we just got.
455 */
456 dentry = d_find_alias(inode);
457 iput(inode);
458 }
459
460 return dentry;
461}
462
350static int btrfs_fill_super(struct super_block *sb, 463static int btrfs_fill_super(struct super_block *sb,
351 struct btrfs_fs_devices *fs_devices, 464 struct btrfs_fs_devices *fs_devices,
352 void *data, int silent) 465 void *data, int silent)
@@ -380,7 +493,7 @@ static int btrfs_fill_super(struct super_block *sb,
380 key.objectid = BTRFS_FIRST_FREE_OBJECTID; 493 key.objectid = BTRFS_FIRST_FREE_OBJECTID;
381 key.type = BTRFS_INODE_ITEM_KEY; 494 key.type = BTRFS_INODE_ITEM_KEY;
382 key.offset = 0; 495 key.offset = 0;
383 inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root); 496 inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root, NULL);
384 if (IS_ERR(inode)) { 497 if (IS_ERR(inode)) {
385 err = PTR_ERR(inode); 498 err = PTR_ERR(inode);
386 goto fail_close; 499 goto fail_close;
@@ -392,12 +505,6 @@ static int btrfs_fill_super(struct super_block *sb,
392 err = -ENOMEM; 505 err = -ENOMEM;
393 goto fail_close; 506 goto fail_close;
394 } 507 }
395#if 0
396 /* this does the super kobj at the same time */
397 err = btrfs_sysfs_add_super(tree_root->fs_info);
398 if (err)
399 goto fail_close;
400#endif
401 508
402 sb->s_root = root_dentry; 509 sb->s_root = root_dentry;
403 510
@@ -489,19 +596,22 @@ static int btrfs_test_super(struct super_block *s, void *data)
489static int btrfs_get_sb(struct file_system_type *fs_type, int flags, 596static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
490 const char *dev_name, void *data, struct vfsmount *mnt) 597 const char *dev_name, void *data, struct vfsmount *mnt)
491{ 598{
492 char *subvol_name = NULL;
493 struct block_device *bdev = NULL; 599 struct block_device *bdev = NULL;
494 struct super_block *s; 600 struct super_block *s;
495 struct dentry *root; 601 struct dentry *root;
496 struct btrfs_fs_devices *fs_devices = NULL; 602 struct btrfs_fs_devices *fs_devices = NULL;
497 fmode_t mode = FMODE_READ; 603 fmode_t mode = FMODE_READ;
604 char *subvol_name = NULL;
605 u64 subvol_objectid = 0;
498 int error = 0; 606 int error = 0;
607 int found = 0;
499 608
500 if (!(flags & MS_RDONLY)) 609 if (!(flags & MS_RDONLY))
501 mode |= FMODE_WRITE; 610 mode |= FMODE_WRITE;
502 611
503 error = btrfs_parse_early_options(data, mode, fs_type, 612 error = btrfs_parse_early_options(data, mode, fs_type,
504 &subvol_name, &fs_devices); 613 &subvol_name, &subvol_objectid,
614 &fs_devices);
505 if (error) 615 if (error)
506 return error; 616 return error;
507 617
@@ -530,6 +640,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
530 goto error_close_devices; 640 goto error_close_devices;
531 } 641 }
532 642
643 found = 1;
533 btrfs_close_devices(fs_devices); 644 btrfs_close_devices(fs_devices);
534 } else { 645 } else {
535 char b[BDEVNAME_SIZE]; 646 char b[BDEVNAME_SIZE];
@@ -547,25 +658,35 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
547 s->s_flags |= MS_ACTIVE; 658 s->s_flags |= MS_ACTIVE;
548 } 659 }
549 660
550 if (!strcmp(subvol_name, ".")) 661 root = get_default_root(s, subvol_objectid);
551 root = dget(s->s_root); 662 if (IS_ERR(root)) {
552 else { 663 error = PTR_ERR(root);
553 mutex_lock(&s->s_root->d_inode->i_mutex); 664 deactivate_locked_super(s);
554 root = lookup_one_len(subvol_name, s->s_root, 665 goto error;
666 }
667 /* if they gave us a subvolume name bind mount into that */
668 if (strcmp(subvol_name, ".")) {
669 struct dentry *new_root;
670 mutex_lock(&root->d_inode->i_mutex);
671 new_root = lookup_one_len(subvol_name, root,
555 strlen(subvol_name)); 672 strlen(subvol_name));
556 mutex_unlock(&s->s_root->d_inode->i_mutex); 673 mutex_unlock(&root->d_inode->i_mutex);
557 674
558 if (IS_ERR(root)) { 675 if (IS_ERR(new_root)) {
559 deactivate_locked_super(s); 676 deactivate_locked_super(s);
560 error = PTR_ERR(root); 677 error = PTR_ERR(new_root);
561 goto error_free_subvol_name; 678 dput(root);
679 goto error_close_devices;
562 } 680 }
563 if (!root->d_inode) { 681 if (!new_root->d_inode) {
564 dput(root); 682 dput(root);
683 dput(new_root);
565 deactivate_locked_super(s); 684 deactivate_locked_super(s);
566 error = -ENXIO; 685 error = -ENXIO;
567 goto error_free_subvol_name; 686 goto error_close_devices;
568 } 687 }
688 dput(root);
689 root = new_root;
569 } 690 }
570 691
571 mnt->mnt_sb = s; 692 mnt->mnt_sb = s;
@@ -580,6 +701,7 @@ error_close_devices:
580 btrfs_close_devices(fs_devices); 701 btrfs_close_devices(fs_devices);
581error_free_subvol_name: 702error_free_subvol_name:
582 kfree(subvol_name); 703 kfree(subvol_name);
704error:
583 return error; 705 return error;
584} 706}
585 707
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 4a9434b622ec..1255fcc8ade5 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -445,7 +445,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
445 key.objectid = objectid; 445 key.objectid = objectid;
446 key.type = BTRFS_INODE_ITEM_KEY; 446 key.type = BTRFS_INODE_ITEM_KEY;
447 key.offset = 0; 447 key.offset = 0;
448 inode = btrfs_iget(root->fs_info->sb, &key, root); 448 inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
449 if (IS_ERR(inode)) { 449 if (IS_ERR(inode)) {
450 inode = NULL; 450 inode = NULL;
451 } else if (is_bad_inode(inode)) { 451 } else if (is_bad_inode(inode)) {