Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7728c96 authored by Jan Schmidt's avatar Jan Schmidt
Browse files

btrfs: new ioctls to do logical->inode and inode->path resolving



these ioctls make use of the new functions initially added for scrub. they
return all inodes belonging to a logical address (BTRFS_IOC_LOGICAL_INO) and
all paths belonging to an inode (BTRFS_IOC_INO_PATHS).

Signed-off-by: default avatarJan Schmidt <list.btrfs@jan-o-sch.net>
parent 0ef8e451
Loading
Loading
Loading
Loading
+143 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include "volumes.h"
#include "locking.h"
#include "inode-map.h"
#include "backref.h"

/* Mask out flags that are inappropriate for the given type of inode. */
static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -2855,6 +2856,144 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
	return ret;
}

static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
{
	int ret = 0;
	int i;
	unsigned long rel_ptr;
	int size;
	struct btrfs_ioctl_ino_path_args *ipa;
	struct inode_fs_paths *ipath = NULL;
	struct btrfs_path *path;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	ipa = memdup_user(arg, sizeof(*ipa));
	if (IS_ERR(ipa)) {
		ret = PTR_ERR(ipa);
		ipa = NULL;
		goto out;
	}

	size = min_t(u32, ipa->size, 4096);
	ipath = init_ipath(size, root, path);
	if (IS_ERR(ipath)) {
		ret = PTR_ERR(ipath);
		ipath = NULL;
		goto out;
	}

	ret = paths_from_inode(ipa->inum, ipath);
	if (ret < 0)
		goto out;

	for (i = 0; i < ipath->fspath->elem_cnt; ++i) {
		rel_ptr = ipath->fspath->str[i] - (char *)ipath->fspath->str;
		ipath->fspath->str[i] = (void *)rel_ptr;
	}

	ret = copy_to_user(ipa->fspath, ipath->fspath, size);
	if (ret) {
		ret = -EFAULT;
		goto out;
	}

out:
	btrfs_free_path(path);
	free_ipath(ipath);
	kfree(ipa);

	return ret;
}

static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
{
	struct btrfs_data_container *inodes = ctx;
	const size_t c = 3 * sizeof(u64);

	if (inodes->bytes_left >= c) {
		inodes->bytes_left -= c;
		inodes->val[inodes->elem_cnt] = inum;
		inodes->val[inodes->elem_cnt + 1] = offset;
		inodes->val[inodes->elem_cnt + 2] = root;
		inodes->elem_cnt += 3;
	} else {
		inodes->bytes_missing += c - inodes->bytes_left;
		inodes->bytes_left = 0;
		inodes->elem_missed += 3;
	}

	return 0;
}

static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
					void __user *arg)
{
	int ret = 0;
	int size;
	u64 extent_offset;
	struct btrfs_ioctl_logical_ino_args *loi;
	struct btrfs_data_container *inodes = NULL;
	struct btrfs_path *path = NULL;
	struct btrfs_key key;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	loi = memdup_user(arg, sizeof(*loi));
	if (IS_ERR(loi)) {
		ret = PTR_ERR(loi);
		loi = NULL;
		goto out;
	}

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	size = min_t(u32, loi->size, 4096);
	inodes = init_data_container(size);
	if (IS_ERR(inodes)) {
		ret = PTR_ERR(inodes);
		inodes = NULL;
		goto out;
	}

	ret = extent_from_logical(root->fs_info, loi->logical, path, &key);

	if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
		ret = -ENOENT;
	if (ret < 0)
		goto out;

	extent_offset = loi->logical - key.objectid;
	ret = iterate_extent_inodes(root->fs_info, path, key.objectid,
					extent_offset, build_ino_list, inodes);

	if (ret < 0)
		goto out;

	ret = copy_to_user(loi->inodes, inodes, size);
	if (ret)
		ret = -EFAULT;

out:
	btrfs_free_path(path);
	kfree(inodes);
	kfree(loi);

	return ret;
}

long btrfs_ioctl(struct file *file, unsigned int
		cmd, unsigned long arg)
{
@@ -2912,6 +3051,10 @@ long btrfs_ioctl(struct file *file, unsigned int
		return btrfs_ioctl_tree_search(file, argp);
	case BTRFS_IOC_INO_LOOKUP:
		return btrfs_ioctl_ino_lookup(file, argp);
	case BTRFS_IOC_INO_PATHS:
		return btrfs_ioctl_ino_to_path(root, argp);
	case BTRFS_IOC_LOGICAL_INO:
		return btrfs_ioctl_logical_to_ino(root, argp);
	case BTRFS_IOC_SPACE_INFO:
		return btrfs_ioctl_space_info(root, argp);
	case BTRFS_IOC_SYNC:
+19 −0
Original line number Diff line number Diff line
@@ -204,6 +204,20 @@ struct btrfs_data_container {
	};
};

struct btrfs_ioctl_ino_path_args {
	__u64				inum;		/* in */
	__u32				size;		/* in */
	__u64				reserved[4];
	struct btrfs_data_container	*fspath;	/* out */
};

struct btrfs_ioctl_logical_ino_args {
	__u64				logical;	/* in */
	__u32				size;		/* in */
	__u64				reserved[4];
	struct btrfs_data_container	*inodes;	/* out */
};

#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
				   struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -259,4 +273,9 @@ struct btrfs_data_container {
				 struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
			       struct btrfs_ioctl_fs_info_args)
#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
					struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
					struct btrfs_ioctl_ino_path_args)

#endif