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>
This commit is contained in:
parent
ad7e1a740d
commit
b64ec075bd
121
fs/btrfs/ioctl.c
121
fs/btrfs/ioctl.c
|
@ -2383,6 +2383,125 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */
|
||||||
|
static int btrfs_ioctl_get_subvol_info(struct file *file, void __user *argp)
|
||||||
|
{
|
||||||
|
struct btrfs_ioctl_get_subvol_info_args *subvol_info;
|
||||||
|
struct btrfs_fs_info *fs_info;
|
||||||
|
struct btrfs_root *root;
|
||||||
|
struct btrfs_path *path;
|
||||||
|
struct btrfs_key key;
|
||||||
|
struct btrfs_root_item *root_item;
|
||||||
|
struct btrfs_root_ref *rref;
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
unsigned long item_off;
|
||||||
|
unsigned long item_len;
|
||||||
|
struct inode *inode;
|
||||||
|
int slot;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
path = btrfs_alloc_path();
|
||||||
|
if (!path)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
subvol_info = kzalloc(sizeof(*subvol_info), GFP_KERNEL);
|
||||||
|
if (!subvol_info) {
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
inode = file_inode(file);
|
||||||
|
fs_info = BTRFS_I(inode)->root->fs_info;
|
||||||
|
|
||||||
|
/* Get root_item of inode's subvolume */
|
||||||
|
key.objectid = BTRFS_I(inode)->root->root_key.objectid;
|
||||||
|
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
root = btrfs_read_fs_root_no_name(fs_info, &key);
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
ret = PTR_ERR(root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
root_item = &root->root_item;
|
||||||
|
|
||||||
|
subvol_info->treeid = key.objectid;
|
||||||
|
|
||||||
|
subvol_info->generation = btrfs_root_generation(root_item);
|
||||||
|
subvol_info->flags = btrfs_root_flags(root_item);
|
||||||
|
|
||||||
|
memcpy(subvol_info->uuid, root_item->uuid, BTRFS_UUID_SIZE);
|
||||||
|
memcpy(subvol_info->parent_uuid, root_item->parent_uuid,
|
||||||
|
BTRFS_UUID_SIZE);
|
||||||
|
memcpy(subvol_info->received_uuid, root_item->received_uuid,
|
||||||
|
BTRFS_UUID_SIZE);
|
||||||
|
|
||||||
|
subvol_info->ctransid = btrfs_root_ctransid(root_item);
|
||||||
|
subvol_info->ctime.sec = btrfs_stack_timespec_sec(&root_item->ctime);
|
||||||
|
subvol_info->ctime.nsec = btrfs_stack_timespec_nsec(&root_item->ctime);
|
||||||
|
|
||||||
|
subvol_info->otransid = btrfs_root_otransid(root_item);
|
||||||
|
subvol_info->otime.sec = btrfs_stack_timespec_sec(&root_item->otime);
|
||||||
|
subvol_info->otime.nsec = btrfs_stack_timespec_nsec(&root_item->otime);
|
||||||
|
|
||||||
|
subvol_info->stransid = btrfs_root_stransid(root_item);
|
||||||
|
subvol_info->stime.sec = btrfs_stack_timespec_sec(&root_item->stime);
|
||||||
|
subvol_info->stime.nsec = btrfs_stack_timespec_nsec(&root_item->stime);
|
||||||
|
|
||||||
|
subvol_info->rtransid = btrfs_root_rtransid(root_item);
|
||||||
|
subvol_info->rtime.sec = btrfs_stack_timespec_sec(&root_item->rtime);
|
||||||
|
subvol_info->rtime.nsec = btrfs_stack_timespec_nsec(&root_item->rtime);
|
||||||
|
|
||||||
|
if (key.objectid != BTRFS_FS_TREE_OBJECTID) {
|
||||||
|
/* Search root tree for ROOT_BACKREF of this subvolume */
|
||||||
|
root = fs_info->tree_root;
|
||||||
|
|
||||||
|
key.type = BTRFS_ROOT_BACKREF_KEY;
|
||||||
|
key.offset = 0;
|
||||||
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (path->slots[0] >=
|
||||||
|
btrfs_header_nritems(path->nodes[0])) {
|
||||||
|
ret = btrfs_next_leaf(root, path);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (ret > 0) {
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
slot = path->slots[0];
|
||||||
|
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||||
|
if (key.objectid == subvol_info->treeid &&
|
||||||
|
key.type == BTRFS_ROOT_BACKREF_KEY) {
|
||||||
|
subvol_info->parent_id = key.offset;
|
||||||
|
|
||||||
|
rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref);
|
||||||
|
subvol_info->dirid = btrfs_root_ref_dirid(leaf, rref);
|
||||||
|
|
||||||
|
item_off = btrfs_item_ptr_offset(leaf, slot)
|
||||||
|
+ sizeof(struct btrfs_root_ref);
|
||||||
|
item_len = btrfs_item_size_nr(leaf, slot)
|
||||||
|
- sizeof(struct btrfs_root_ref);
|
||||||
|
read_extent_buffer(leaf, subvol_info->name,
|
||||||
|
item_off, item_len);
|
||||||
|
} else {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_to_user(argp, subvol_info, sizeof(*subvol_info)))
|
||||||
|
ret = -EFAULT;
|
||||||
|
|
||||||
|
out:
|
||||||
|
btrfs_free_path(path);
|
||||||
|
kzfree(subvol_info);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
|
@ -5545,6 +5664,8 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||||
return btrfs_ioctl_fsgetxattr(file, argp);
|
return btrfs_ioctl_fsgetxattr(file, argp);
|
||||||
case FS_IOC_FSSETXATTR:
|
case FS_IOC_FSSETXATTR:
|
||||||
return btrfs_ioctl_fssetxattr(file, argp);
|
return btrfs_ioctl_fssetxattr(file, argp);
|
||||||
|
case BTRFS_IOC_GET_SUBVOL_INFO:
|
||||||
|
return btrfs_ioctl_get_subvol_info(file, argp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
|
@ -725,6 +725,66 @@ struct btrfs_ioctl_send_args {
|
||||||
__u64 reserved[4]; /* in */
|
__u64 reserved[4]; /* in */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Information about a fs tree root.
|
||||||
|
*
|
||||||
|
* All items are filled by the ioctl
|
||||||
|
*/
|
||||||
|
struct btrfs_ioctl_get_subvol_info_args {
|
||||||
|
/* Id of this subvolume */
|
||||||
|
__u64 treeid;
|
||||||
|
|
||||||
|
/* Name of this subvolume, used to get the real name at mount point */
|
||||||
|
char name[BTRFS_VOL_NAME_MAX + 1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Id of the subvolume which contains this subvolume.
|
||||||
|
* Zero for top-level subvolume or a deleted subvolume.
|
||||||
|
*/
|
||||||
|
__u64 parent_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inode number of the directory which contains this subvolume.
|
||||||
|
* Zero for top-level subvolume or a deleted subvolume
|
||||||
|
*/
|
||||||
|
__u64 dirid;
|
||||||
|
|
||||||
|
/* Latest transaction id of this subvolume */
|
||||||
|
__u64 generation;
|
||||||
|
|
||||||
|
/* Flags of this subvolume */
|
||||||
|
__u64 flags;
|
||||||
|
|
||||||
|
/* UUID of this subvolume */
|
||||||
|
__u8 uuid[BTRFS_UUID_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UUID of the subvolume of which this subvolume is a snapshot.
|
||||||
|
* All zero for a non-snapshot subvolume.
|
||||||
|
*/
|
||||||
|
__u8 parent_uuid[BTRFS_UUID_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UUID of the subvolume from which this subvolume was received.
|
||||||
|
* All zero for non-received subvolume.
|
||||||
|
*/
|
||||||
|
__u8 received_uuid[BTRFS_UUID_SIZE];
|
||||||
|
|
||||||
|
/* Transaction id indicating when change/create/send/receive happened */
|
||||||
|
__u64 ctransid;
|
||||||
|
__u64 otransid;
|
||||||
|
__u64 stransid;
|
||||||
|
__u64 rtransid;
|
||||||
|
/* Time corresponding to c/o/s/rtransid */
|
||||||
|
struct btrfs_ioctl_timespec ctime;
|
||||||
|
struct btrfs_ioctl_timespec otime;
|
||||||
|
struct btrfs_ioctl_timespec stime;
|
||||||
|
struct btrfs_ioctl_timespec rtime;
|
||||||
|
|
||||||
|
/* Must be zero */
|
||||||
|
__u64 reserved[8];
|
||||||
|
};
|
||||||
|
|
||||||
/* Error codes as returned by the kernel */
|
/* Error codes as returned by the kernel */
|
||||||
enum btrfs_err_code {
|
enum btrfs_err_code {
|
||||||
BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1,
|
BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1,
|
||||||
|
@ -843,5 +903,7 @@ enum btrfs_err_code {
|
||||||
struct btrfs_ioctl_vol_args_v2)
|
struct btrfs_ioctl_vol_args_v2)
|
||||||
#define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \
|
#define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \
|
||||||
struct btrfs_ioctl_logical_ino_args)
|
struct btrfs_ioctl_logical_ino_args)
|
||||||
|
#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \
|
||||||
|
struct btrfs_ioctl_get_subvol_info_args)
|
||||||
|
|
||||||
#endif /* _UAPI_LINUX_BTRFS_H */
|
#endif /* _UAPI_LINUX_BTRFS_H */
|
||||||
|
|
Loading…
Reference in New Issue