aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ioctl.c99
-rw-r--r--include/uapi/linux/btrfs.h18
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 */
2509static 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
2585out:
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
2505static noinline int btrfs_ioctl_snap_destroy(struct file *file, 2602static 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
789struct 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 */
789enum btrfs_err_code { 805enum 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 */