aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2011-07-07 10:48:38 -0400
committerJan Schmidt <list.btrfs@jan-o-sch.net>2011-09-29 06:54:28 -0400
commitd7728c960dccf775b92f2c4139f1216275a45c44 (patch)
tree76d8ea34fe47a1557f0cf5e558aa3cb525f39c70 /fs/btrfs/ioctl.c
parent0ef8e45158f97dde4801b535e25f70f7caf01a27 (diff)
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: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 538f65a79ec5..7f57efa76d11 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -51,6 +51,7 @@
51#include "volumes.h" 51#include "volumes.h"
52#include "locking.h" 52#include "locking.h"
53#include "inode-map.h" 53#include "inode-map.h"
54#include "backref.h"
54 55
55/* Mask out flags that are inappropriate for the given type of inode. */ 56/* Mask out flags that are inappropriate for the given type of inode. */
56static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) 57static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -2855,6 +2856,144 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
2855 return ret; 2856 return ret;
2856} 2857}
2857 2858
2859static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
2860{
2861 int ret = 0;
2862 int i;
2863 unsigned long rel_ptr;
2864 int size;
2865 struct btrfs_ioctl_ino_path_args *ipa;
2866 struct inode_fs_paths *ipath = NULL;
2867 struct btrfs_path *path;
2868
2869 if (!capable(CAP_SYS_ADMIN))
2870 return -EPERM;
2871
2872 path = btrfs_alloc_path();
2873 if (!path) {
2874 ret = -ENOMEM;
2875 goto out;
2876 }
2877
2878 ipa = memdup_user(arg, sizeof(*ipa));
2879 if (IS_ERR(ipa)) {
2880 ret = PTR_ERR(ipa);
2881 ipa = NULL;
2882 goto out;
2883 }
2884
2885 size = min_t(u32, ipa->size, 4096);
2886 ipath = init_ipath(size, root, path);
2887 if (IS_ERR(ipath)) {
2888 ret = PTR_ERR(ipath);
2889 ipath = NULL;
2890 goto out;
2891 }
2892
2893 ret = paths_from_inode(ipa->inum, ipath);
2894 if (ret < 0)
2895 goto out;
2896
2897 for (i = 0; i < ipath->fspath->elem_cnt; ++i) {
2898 rel_ptr = ipath->fspath->str[i] - (char *)ipath->fspath->str;
2899 ipath->fspath->str[i] = (void *)rel_ptr;
2900 }
2901
2902 ret = copy_to_user(ipa->fspath, ipath->fspath, size);
2903 if (ret) {
2904 ret = -EFAULT;
2905 goto out;
2906 }
2907
2908out:
2909 btrfs_free_path(path);
2910 free_ipath(ipath);
2911 kfree(ipa);
2912
2913 return ret;
2914}
2915
2916static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
2917{
2918 struct btrfs_data_container *inodes = ctx;
2919 const size_t c = 3 * sizeof(u64);
2920
2921 if (inodes->bytes_left >= c) {
2922 inodes->bytes_left -= c;
2923 inodes->val[inodes->elem_cnt] = inum;
2924 inodes->val[inodes->elem_cnt + 1] = offset;
2925 inodes->val[inodes->elem_cnt + 2] = root;
2926 inodes->elem_cnt += 3;
2927 } else {
2928 inodes->bytes_missing += c - inodes->bytes_left;
2929 inodes->bytes_left = 0;
2930 inodes->elem_missed += 3;
2931 }
2932
2933 return 0;
2934}
2935
2936static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
2937 void __user *arg)
2938{
2939 int ret = 0;
2940 int size;
2941 u64 extent_offset;
2942 struct btrfs_ioctl_logical_ino_args *loi;
2943 struct btrfs_data_container *inodes = NULL;
2944 struct btrfs_path *path = NULL;
2945 struct btrfs_key key;
2946
2947 if (!capable(CAP_SYS_ADMIN))
2948 return -EPERM;
2949
2950 loi = memdup_user(arg, sizeof(*loi));
2951 if (IS_ERR(loi)) {
2952 ret = PTR_ERR(loi);
2953 loi = NULL;
2954 goto out;
2955 }
2956
2957 path = btrfs_alloc_path();
2958 if (!path) {
2959 ret = -ENOMEM;
2960 goto out;
2961 }
2962
2963 size = min_t(u32, loi->size, 4096);
2964 inodes = init_data_container(size);
2965 if (IS_ERR(inodes)) {
2966 ret = PTR_ERR(inodes);
2967 inodes = NULL;
2968 goto out;
2969 }
2970
2971 ret = extent_from_logical(root->fs_info, loi->logical, path, &key);
2972
2973 if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
2974 ret = -ENOENT;
2975 if (ret < 0)
2976 goto out;
2977
2978 extent_offset = loi->logical - key.objectid;
2979 ret = iterate_extent_inodes(root->fs_info, path, key.objectid,
2980 extent_offset, build_ino_list, inodes);
2981
2982 if (ret < 0)
2983 goto out;
2984
2985 ret = copy_to_user(loi->inodes, inodes, size);
2986 if (ret)
2987 ret = -EFAULT;
2988
2989out:
2990 btrfs_free_path(path);
2991 kfree(inodes);
2992 kfree(loi);
2993
2994 return ret;
2995}
2996
2858long btrfs_ioctl(struct file *file, unsigned int 2997long btrfs_ioctl(struct file *file, unsigned int
2859 cmd, unsigned long arg) 2998 cmd, unsigned long arg)
2860{ 2999{
@@ -2912,6 +3051,10 @@ long btrfs_ioctl(struct file *file, unsigned int
2912 return btrfs_ioctl_tree_search(file, argp); 3051 return btrfs_ioctl_tree_search(file, argp);
2913 case BTRFS_IOC_INO_LOOKUP: 3052 case BTRFS_IOC_INO_LOOKUP:
2914 return btrfs_ioctl_ino_lookup(file, argp); 3053 return btrfs_ioctl_ino_lookup(file, argp);
3054 case BTRFS_IOC_INO_PATHS:
3055 return btrfs_ioctl_ino_to_path(root, argp);
3056 case BTRFS_IOC_LOGICAL_INO:
3057 return btrfs_ioctl_logical_to_ino(root, argp);
2915 case BTRFS_IOC_SPACE_INFO: 3058 case BTRFS_IOC_SPACE_INFO:
2916 return btrfs_ioctl_space_info(root, argp); 3059 return btrfs_ioctl_space_info(root, argp);
2917 case BTRFS_IOC_SYNC: 3060 case BTRFS_IOC_SYNC: