diff mbox

[v5,8/8] btrfs: new ioctls to do logical->inode and inode->path resolving

Message ID d1e9e9c9695a1291d624ad86abb8648f7d04a848.1311244592.git.list.btrfs@jan-o-sch.net (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Schmidt July 21, 2011, 11:19 a.m. UTC
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: Jan Schmidt <list.btrfs@jan-o-sch.net>
---
 fs/btrfs/ioctl.c |  134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/ioctl.h |   19 ++++++++
 2 files changed, 153 insertions(+), 0 deletions(-)

Comments

Andi Kleen July 21, 2011, 8:14 p.m. UTC | #1
Jan Schmidt <list.btrfs@jan-o-sch.net> writes:
> +
> +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;

This really needs to be root-only for obvious reasons.
The same for the ino_path function

> +
> +	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(loi->size, 4096);

This is likely a root hole. loi->size is signed! Consider the case
of a negative value being passed in.

Same for the earlier function.

-Andi
Jan Schmidt July 22, 2011, 7:09 a.m. UTC | #2
On 21.07.2011 22:14, Andi Kleen wrote:
> Jan Schmidt <list.btrfs@jan-o-sch.net> writes:
>> +
>> +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;
> 
> This really needs to be root-only for obvious reasons.
> The same for the ino_path function
> 
>> +
>> +	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(loi->size, 4096);
> 
> This is likely a root hole. loi->size is signed! Consider the case
> of a negative value being passed in.
> 
> Same for the earlier function.

Sigh. Thanks for pointing these out. Shouldn't release code that was
fine for development without carefully reconsidering such things. I'll
send a v6.

-Jan
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index a3c4751..5299b40 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -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)
@@ -2836,6 +2837,135 @@  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;
+
+	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(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;
+
+	inodes->size -= 3 * sizeof(u64);
+	if (inodes->size > 0) {
+		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->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;
+
+	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(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)
 {
@@ -2893,6 +3023,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:
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 4afb60b..10a0c10 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -203,6 +203,20 @@  struct btrfs_data_container {
 	};
 };
 
+struct btrfs_ioctl_ino_path_args {
+	__u64				inum;		/* in */
+	__s32				size;		/* in */
+	__u64				reserved[4];
+	struct btrfs_data_container	*fspath;	/* out */
+};
+
+struct btrfs_ioctl_logical_ino_args {
+	__u64				logical;	/* in */
+	__s32				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, \
@@ -258,4 +272,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