Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tomohiro Misono and committed by
David Sterba
b64ec075 ad7e1a74

+183
+121
fs/btrfs/ioctl.c
··· 2383 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 2505 static noinline int btrfs_ioctl_snap_destroy(struct file *file, 2387 2506 void __user *arg) 2388 2507 { ··· 5664 5545 return btrfs_ioctl_fsgetxattr(file, argp); 5665 5546 case FS_IOC_FSSETXATTR: 5666 5547 return btrfs_ioctl_fssetxattr(file, argp); 5548 + case BTRFS_IOC_GET_SUBVOL_INFO: 5549 + return btrfs_ioctl_get_subvol_info(file, argp); 5667 5550 } 5668 5551 5669 5552 return -ENOTTY;
+62
include/uapi/linux/btrfs.h
··· 725 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 788 /* Error codes as returned by the kernel */ 729 789 enum btrfs_err_code { 730 790 BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, ··· 903 843 struct btrfs_ioctl_vol_args_v2) 904 844 #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \ 905 845 struct btrfs_ioctl_logical_ino_args) 846 + #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ 847 + struct btrfs_ioctl_get_subvol_info_args) 906 848 907 849 #endif /* _UAPI_LINUX_BTRFS_H */