diff options
author | Tomohiro Misono <misono.tomohiro@jp.fujitsu.com> | 2018-05-20 21:09:42 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-05-31 05:35:23 -0400 |
commit | b64ec075bded2b30bcd90af5aa5256d2237c885d (patch) | |
tree | 6871372a89687f1f2fb9d63c920cb1fa922cb935 | |
parent | ad7e1a740d940cf7da1beb332a1095bcda40c747 (diff) |
btrfs: Add unprivileged ioctl which returns subvolume information
Add new unprivileged ioctl BTRFS_IOC_GET_SUBVOL_INFO which returns
the information of subvolume containing this inode.
(i.e. returns the information in ROOT_ITEM and ROOT_BACKREF.)
Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com>
[ minor style fixes, update struct comments ]
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/ioctl.c | 121 | ||||
-rw-r--r-- | include/uapi/linux/btrfs.h | 62 |
2 files changed, 183 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4db2446c7015..42ed752288e6 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -2383,6 +2383,125 @@ out: | |||
2383 | return ret; | 2383 | return ret; |
2384 | } | 2384 | } |
2385 | 2385 | ||
2386 | /* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */ | ||
2387 | static int btrfs_ioctl_get_subvol_info(struct file *file, void __user *argp) | ||
2388 | { | ||
2389 | struct btrfs_ioctl_get_subvol_info_args *subvol_info; | ||
2390 | struct btrfs_fs_info *fs_info; | ||
2391 | struct btrfs_root *root; | ||
2392 | struct btrfs_path *path; | ||
2393 | struct btrfs_key key; | ||
2394 | struct btrfs_root_item *root_item; | ||
2395 | struct btrfs_root_ref *rref; | ||
2396 | struct extent_buffer *leaf; | ||
2397 | unsigned long item_off; | ||
2398 | unsigned long item_len; | ||
2399 | struct inode *inode; | ||
2400 | int slot; | ||
2401 | int ret = 0; | ||
2402 | |||
2403 | path = btrfs_alloc_path(); | ||
2404 | if (!path) | ||
2405 | return -ENOMEM; | ||
2406 | |||
2407 | subvol_info = kzalloc(sizeof(*subvol_info), GFP_KERNEL); | ||
2408 | if (!subvol_info) { | ||
2409 | btrfs_free_path(path); | ||
2410 | return -ENOMEM; | ||
2411 | } | ||
2412 | |||
2413 | inode = file_inode(file); | ||
2414 | fs_info = BTRFS_I(inode)->root->fs_info; | ||
2415 | |||
2416 | /* Get root_item of inode's subvolume */ | ||
2417 | key.objectid = BTRFS_I(inode)->root->root_key.objectid; | ||
2418 | key.type = BTRFS_ROOT_ITEM_KEY; | ||
2419 | key.offset = (u64)-1; | ||
2420 | root = btrfs_read_fs_root_no_name(fs_info, &key); | ||
2421 | if (IS_ERR(root)) { | ||
2422 | ret = PTR_ERR(root); | ||
2423 | goto out; | ||
2424 | } | ||
2425 | root_item = &root->root_item; | ||
2426 | |||
2427 | subvol_info->treeid = key.objectid; | ||
2428 | |||
2429 | subvol_info->generation = btrfs_root_generation(root_item); | ||
2430 | subvol_info->flags = btrfs_root_flags(root_item); | ||
2431 | |||
2432 | memcpy(subvol_info->uuid, root_item->uuid, BTRFS_UUID_SIZE); | ||
2433 | memcpy(subvol_info->parent_uuid, root_item->parent_uuid, | ||
2434 | BTRFS_UUID_SIZE); | ||
2435 | memcpy(subvol_info->received_uuid, root_item->received_uuid, | ||
2436 | BTRFS_UUID_SIZE); | ||
2437 | |||
2438 | subvol_info->ctransid = btrfs_root_ctransid(root_item); | ||
2439 | subvol_info->ctime.sec = btrfs_stack_timespec_sec(&root_item->ctime); | ||
2440 | subvol_info->ctime.nsec = btrfs_stack_timespec_nsec(&root_item->ctime); | ||
2441 | |||
2442 | subvol_info->otransid = btrfs_root_otransid(root_item); | ||
2443 | subvol_info->otime.sec = btrfs_stack_timespec_sec(&root_item->otime); | ||
2444 | subvol_info->otime.nsec = btrfs_stack_timespec_nsec(&root_item->otime); | ||
2445 | |||
2446 | subvol_info->stransid = btrfs_root_stransid(root_item); | ||
2447 | subvol_info->stime.sec = btrfs_stack_timespec_sec(&root_item->stime); | ||
2448 | subvol_info->stime.nsec = btrfs_stack_timespec_nsec(&root_item->stime); | ||
2449 | |||
2450 | subvol_info->rtransid = btrfs_root_rtransid(root_item); | ||
2451 | subvol_info->rtime.sec = btrfs_stack_timespec_sec(&root_item->rtime); | ||
2452 | subvol_info->rtime.nsec = btrfs_stack_timespec_nsec(&root_item->rtime); | ||
2453 | |||
2454 | if (key.objectid != BTRFS_FS_TREE_OBJECTID) { | ||
2455 | /* Search root tree for ROOT_BACKREF of this subvolume */ | ||
2456 | root = fs_info->tree_root; | ||
2457 | |||
2458 | key.type = BTRFS_ROOT_BACKREF_KEY; | ||
2459 | key.offset = 0; | ||
2460 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
2461 | if (ret < 0) { | ||
2462 | goto out; | ||
2463 | } else if (path->slots[0] >= | ||
2464 | btrfs_header_nritems(path->nodes[0])) { | ||
2465 | ret = btrfs_next_leaf(root, path); | ||
2466 | if (ret < 0) { | ||
2467 | goto out; | ||
2468 | } else if (ret > 0) { | ||
2469 | ret = -EUCLEAN; | ||
2470 | goto out; | ||
2471 | } | ||
2472 | } | ||
2473 | |||
2474 | leaf = path->nodes[0]; | ||
2475 | slot = path->slots[0]; | ||
2476 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
2477 | if (key.objectid == subvol_info->treeid && | ||
2478 | key.type == BTRFS_ROOT_BACKREF_KEY) { | ||
2479 | subvol_info->parent_id = key.offset; | ||
2480 | |||
2481 | rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref); | ||
2482 | subvol_info->dirid = btrfs_root_ref_dirid(leaf, rref); | ||
2483 | |||
2484 | item_off = btrfs_item_ptr_offset(leaf, slot) | ||
2485 | + sizeof(struct btrfs_root_ref); | ||
2486 | item_len = btrfs_item_size_nr(leaf, slot) | ||
2487 | - sizeof(struct btrfs_root_ref); | ||
2488 | read_extent_buffer(leaf, subvol_info->name, | ||
2489 | item_off, item_len); | ||
2490 | } else { | ||
2491 | ret = -ENOENT; | ||
2492 | goto out; | ||
2493 | } | ||
2494 | } | ||
2495 | |||
2496 | if (copy_to_user(argp, subvol_info, sizeof(*subvol_info))) | ||
2497 | ret = -EFAULT; | ||
2498 | |||
2499 | out: | ||
2500 | btrfs_free_path(path); | ||
2501 | kzfree(subvol_info); | ||
2502 | return ret; | ||
2503 | } | ||
2504 | |||
2386 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, | 2505 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, |
2387 | void __user *arg) | 2506 | void __user *arg) |
2388 | { | 2507 | { |
@@ -5545,6 +5664,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
5545 | return btrfs_ioctl_fsgetxattr(file, argp); | 5664 | return btrfs_ioctl_fsgetxattr(file, argp); |
5546 | case FS_IOC_FSSETXATTR: | 5665 | case FS_IOC_FSSETXATTR: |
5547 | return btrfs_ioctl_fssetxattr(file, argp); | 5666 | return btrfs_ioctl_fssetxattr(file, argp); |
5667 | case BTRFS_IOC_GET_SUBVOL_INFO: | ||
5668 | return btrfs_ioctl_get_subvol_info(file, argp); | ||
5548 | } | 5669 | } |
5549 | 5670 | ||
5550 | return -ENOTTY; | 5671 | return -ENOTTY; |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index c8d99b9ca550..f8f20d72b852 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
@@ -725,6 +725,66 @@ struct btrfs_ioctl_send_args { | |||
725 | __u64 reserved[4]; /* in */ | 725 | __u64 reserved[4]; /* in */ |
726 | }; | 726 | }; |
727 | 727 | ||
728 | /* | ||
729 | * Information about a fs tree root. | ||
730 | * | ||
731 | * All items are filled by the ioctl | ||
732 | */ | ||
733 | struct btrfs_ioctl_get_subvol_info_args { | ||
734 | /* Id of this subvolume */ | ||
735 | __u64 treeid; | ||
736 | |||
737 | /* Name of this subvolume, used to get the real name at mount point */ | ||
738 | char name[BTRFS_VOL_NAME_MAX + 1]; | ||
739 | |||
740 | /* | ||
741 | * Id of the subvolume which contains this subvolume. | ||
742 | * Zero for top-level subvolume or a deleted subvolume. | ||
743 | */ | ||
744 | __u64 parent_id; | ||
745 | |||
746 | /* | ||
747 | * Inode number of the directory which contains this subvolume. | ||
748 | * Zero for top-level subvolume or a deleted subvolume | ||
749 | */ | ||
750 | __u64 dirid; | ||
751 | |||
752 | /* Latest transaction id of this subvolume */ | ||
753 | __u64 generation; | ||
754 | |||
755 | /* Flags of this subvolume */ | ||
756 | __u64 flags; | ||
757 | |||
758 | /* UUID of this subvolume */ | ||
759 | __u8 uuid[BTRFS_UUID_SIZE]; | ||
760 | |||
761 | /* | ||
762 | * UUID of the subvolume of which this subvolume is a snapshot. | ||
763 | * All zero for a non-snapshot subvolume. | ||
764 | */ | ||
765 | __u8 parent_uuid[BTRFS_UUID_SIZE]; | ||
766 | |||
767 | /* | ||
768 | * UUID of the subvolume from which this subvolume was received. | ||
769 | * All zero for non-received subvolume. | ||
770 | */ | ||
771 | __u8 received_uuid[BTRFS_UUID_SIZE]; | ||
772 | |||
773 | /* Transaction id indicating when change/create/send/receive happened */ | ||
774 | __u64 ctransid; | ||
775 | __u64 otransid; | ||
776 | __u64 stransid; | ||
777 | __u64 rtransid; | ||
778 | /* Time corresponding to c/o/s/rtransid */ | ||
779 | struct btrfs_ioctl_timespec ctime; | ||
780 | struct btrfs_ioctl_timespec otime; | ||
781 | struct btrfs_ioctl_timespec stime; | ||
782 | struct btrfs_ioctl_timespec rtime; | ||
783 | |||
784 | /* Must be zero */ | ||
785 | __u64 reserved[8]; | ||
786 | }; | ||
787 | |||
728 | /* Error codes as returned by the kernel */ | 788 | /* Error codes as returned by the kernel */ |
729 | enum btrfs_err_code { | 789 | enum btrfs_err_code { |
730 | BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, | 790 | BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, |
@@ -843,5 +903,7 @@ enum btrfs_err_code { | |||
843 | struct btrfs_ioctl_vol_args_v2) | 903 | struct btrfs_ioctl_vol_args_v2) |
844 | #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \ | 904 | #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \ |
845 | struct btrfs_ioctl_logical_ino_args) | 905 | struct btrfs_ioctl_logical_ino_args) |
906 | #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ | ||
907 | struct btrfs_ioctl_get_subvol_info_args) | ||
846 | 908 | ||
847 | #endif /* _UAPI_LINUX_BTRFS_H */ | 909 | #endif /* _UAPI_LINUX_BTRFS_H */ |