|
@@ -51,6 +51,7 @@
|
|
#include "volumes.h"
|
|
#include "volumes.h"
|
|
#include "locking.h"
|
|
#include "locking.h"
|
|
#include "inode-map.h"
|
|
#include "inode-map.h"
|
|
|
|
+#include "backref.h"
|
|
|
|
|
|
/* Mask out flags that are inappropriate for the given type of inode. */
|
|
/* Mask out flags that are inappropriate for the given type of inode. */
|
|
static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
|
|
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;
|
|
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
|
|
long btrfs_ioctl(struct file *file, unsigned int
|
|
cmd, unsigned long arg)
|
|
cmd, unsigned long arg)
|
|
{
|
|
{
|
|
@@ -2912,6 +3051,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|
return btrfs_ioctl_tree_search(file, argp);
|
|
return btrfs_ioctl_tree_search(file, argp);
|
|
case BTRFS_IOC_INO_LOOKUP:
|
|
case BTRFS_IOC_INO_LOOKUP:
|
|
return btrfs_ioctl_ino_lookup(file, argp);
|
|
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:
|
|
case BTRFS_IOC_SPACE_INFO:
|
|
return btrfs_ioctl_space_info(root, argp);
|
|
return btrfs_ioctl_space_info(root, argp);
|
|
case BTRFS_IOC_SYNC:
|
|
case BTRFS_IOC_SYNC:
|