diff options
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 172 |
1 files changed, 147 insertions, 25 deletions
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 | ||
65 | enum { | 65 | enum { |
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 { | |||
74 | static match_table_t tokens = { | 74 | static 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 | */ |
294 | static int btrfs_parse_early_options(const char *options, fmode_t flags, | 296 | static 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 | ||
359 | static 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 | |||
410 | find_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); | ||
419 | setup_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 | |||
350 | static int btrfs_fill_super(struct super_block *sb, | 463 | static 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) | |||
489 | static int btrfs_get_sb(struct file_system_type *fs_type, int flags, | 596 | static 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); |
581 | error_free_subvol_name: | 702 | error_free_subvol_name: |
582 | kfree(subvol_name); | 703 | kfree(subvol_name); |
704 | error: | ||
583 | return error; | 705 | return error; |
584 | } | 706 | } |
585 | 707 | ||