diff options
| -rw-r--r-- | fs/btrfs/ioctl.c | 99 | ||||
| -rw-r--r-- | include/uapi/linux/btrfs.h | 18 |
2 files changed, 117 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 42ed752288e6..be9b3f39183c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -2502,6 +2502,103 @@ out: | |||
| 2502 | return ret; | 2502 | return ret; |
| 2503 | } | 2503 | } |
| 2504 | 2504 | ||
| 2505 | /* | ||
| 2506 | * Return ROOT_REF information of the subvolume containing this inode | ||
| 2507 | * except the subvolume name. | ||
| 2508 | */ | ||
| 2509 | static int btrfs_ioctl_get_subvol_rootref(struct file *file, void __user *argp) | ||
| 2510 | { | ||
| 2511 | struct btrfs_ioctl_get_subvol_rootref_args *rootrefs; | ||
| 2512 | struct btrfs_root_ref *rref; | ||
| 2513 | struct btrfs_root *root; | ||
| 2514 | struct btrfs_path *path; | ||
| 2515 | struct btrfs_key key; | ||
| 2516 | struct extent_buffer *leaf; | ||
| 2517 | struct inode *inode; | ||
| 2518 | u64 objectid; | ||
| 2519 | int slot; | ||
| 2520 | int ret; | ||
| 2521 | u8 found; | ||
| 2522 | |||
| 2523 | path = btrfs_alloc_path(); | ||
| 2524 | if (!path) | ||
| 2525 | return -ENOMEM; | ||
| 2526 | |||
| 2527 | rootrefs = memdup_user(argp, sizeof(*rootrefs)); | ||
| 2528 | if (IS_ERR(rootrefs)) { | ||
| 2529 | btrfs_free_path(path); | ||
| 2530 | return PTR_ERR(rootrefs); | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | inode = file_inode(file); | ||
| 2534 | root = BTRFS_I(inode)->root->fs_info->tree_root; | ||
| 2535 | objectid = BTRFS_I(inode)->root->root_key.objectid; | ||
| 2536 | |||
| 2537 | key.objectid = objectid; | ||
| 2538 | key.type = BTRFS_ROOT_REF_KEY; | ||
| 2539 | key.offset = rootrefs->min_treeid; | ||
| 2540 | found = 0; | ||
| 2541 | |||
| 2542 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
| 2543 | if (ret < 0) { | ||
| 2544 | goto out; | ||
| 2545 | } else if (path->slots[0] >= | ||
| 2546 | btrfs_header_nritems(path->nodes[0])) { | ||
| 2547 | ret = btrfs_next_leaf(root, path); | ||
| 2548 | if (ret < 0) { | ||
| 2549 | goto out; | ||
| 2550 | } else if (ret > 0) { | ||
| 2551 | ret = -EUCLEAN; | ||
| 2552 | goto out; | ||
| 2553 | } | ||
| 2554 | } | ||
| 2555 | while (1) { | ||
| 2556 | leaf = path->nodes[0]; | ||
| 2557 | slot = path->slots[0]; | ||
| 2558 | |||
| 2559 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
| 2560 | if (key.objectid != objectid || key.type != BTRFS_ROOT_REF_KEY) { | ||
| 2561 | ret = 0; | ||
| 2562 | goto out; | ||
| 2563 | } | ||
| 2564 | |||
| 2565 | if (found == BTRFS_MAX_ROOTREF_BUFFER_NUM) { | ||
| 2566 | ret = -EOVERFLOW; | ||
| 2567 | goto out; | ||
| 2568 | } | ||
| 2569 | |||
| 2570 | rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref); | ||
| 2571 | rootrefs->rootref[found].treeid = key.offset; | ||
| 2572 | rootrefs->rootref[found].dirid = | ||
| 2573 | btrfs_root_ref_dirid(leaf, rref); | ||
| 2574 | found++; | ||
| 2575 | |||
| 2576 | ret = btrfs_next_item(root, path); | ||
| 2577 | if (ret < 0) { | ||
| 2578 | goto out; | ||
| 2579 | } else if (ret > 0) { | ||
| 2580 | ret = -EUCLEAN; | ||
| 2581 | goto out; | ||
| 2582 | } | ||
| 2583 | } | ||
| 2584 | |||
| 2585 | out: | ||
| 2586 | if (!ret || ret == -EOVERFLOW) { | ||
| 2587 | rootrefs->num_items = found; | ||
| 2588 | /* update min_treeid for next search */ | ||
| 2589 | if (found) | ||
| 2590 | rootrefs->min_treeid = | ||
| 2591 | rootrefs->rootref[found - 1].treeid + 1; | ||
| 2592 | if (copy_to_user(argp, rootrefs, sizeof(*rootrefs))) | ||
| 2593 | ret = -EFAULT; | ||
| 2594 | } | ||
| 2595 | |||
| 2596 | kfree(rootrefs); | ||
| 2597 | btrfs_free_path(path); | ||
| 2598 | |||
| 2599 | return ret; | ||
| 2600 | } | ||
| 2601 | |||
| 2505 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, | 2602 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, |
| 2506 | void __user *arg) | 2603 | void __user *arg) |
| 2507 | { | 2604 | { |
| @@ -5666,6 +5763,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 5666 | return btrfs_ioctl_fssetxattr(file, argp); | 5763 | return btrfs_ioctl_fssetxattr(file, argp); |
| 5667 | case BTRFS_IOC_GET_SUBVOL_INFO: | 5764 | case BTRFS_IOC_GET_SUBVOL_INFO: |
| 5668 | return btrfs_ioctl_get_subvol_info(file, argp); | 5765 | return btrfs_ioctl_get_subvol_info(file, argp); |
| 5766 | case BTRFS_IOC_GET_SUBVOL_ROOTREF: | ||
| 5767 | return btrfs_ioctl_get_subvol_rootref(file, argp); | ||
| 5669 | } | 5768 | } |
| 5670 | 5769 | ||
| 5671 | return -ENOTTY; | 5770 | return -ENOTTY; |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index f8f20d72b852..f90d10478235 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
| @@ -785,6 +785,22 @@ struct btrfs_ioctl_get_subvol_info_args { | |||
| 785 | __u64 reserved[8]; | 785 | __u64 reserved[8]; |
| 786 | }; | 786 | }; |
| 787 | 787 | ||
| 788 | #define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 | ||
| 789 | struct btrfs_ioctl_get_subvol_rootref_args { | ||
| 790 | /* in/out, minimum id of rootref's treeid to be searched */ | ||
| 791 | __u64 min_treeid; | ||
| 792 | |||
| 793 | /* out */ | ||
| 794 | struct { | ||
| 795 | __u64 treeid; | ||
| 796 | __u64 dirid; | ||
| 797 | } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM]; | ||
| 798 | |||
| 799 | /* out, number of found items */ | ||
| 800 | __u8 num_items; | ||
| 801 | __u8 align[7]; | ||
| 802 | }; | ||
| 803 | |||
| 788 | /* Error codes as returned by the kernel */ | 804 | /* Error codes as returned by the kernel */ |
| 789 | enum btrfs_err_code { | 805 | enum btrfs_err_code { |
| 790 | BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, | 806 | BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, |
| @@ -905,5 +921,7 @@ enum btrfs_err_code { | |||
| 905 | struct btrfs_ioctl_logical_ino_args) | 921 | struct btrfs_ioctl_logical_ino_args) |
| 906 | #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ | 922 | #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ |
| 907 | struct btrfs_ioctl_get_subvol_info_args) | 923 | struct btrfs_ioctl_get_subvol_info_args) |
| 924 | #define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ | ||
| 925 | struct btrfs_ioctl_get_subvol_rootref_args) | ||
| 908 | 926 | ||
| 909 | #endif /* _UAPI_LINUX_BTRFS_H */ | 927 | #endif /* _UAPI_LINUX_BTRFS_H */ |
