|
51 | 51 | #include "volumes.h"
|
52 | 52 | #include "locking.h"
|
53 | 53 | #include "inode-map.h"
|
| 54 | +#include "backref.h" |
54 | 55 |
|
55 | 56 | /* Mask out flags that are inappropriate for the given type of inode. */
|
56 | 57 | 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,
|
2855 | 2856 | return ret;
|
2856 | 2857 | }
|
2857 | 2858 |
|
| 2859 | +static 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 | + |
| 2908 | +out: |
| 2909 | + btrfs_free_path(path); |
| 2910 | + free_ipath(ipath); |
| 2911 | + kfree(ipa); |
| 2912 | + |
| 2913 | + return ret; |
| 2914 | +} |
| 2915 | + |
| 2916 | +static 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 | + |
| 2936 | +static 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 | + |
| 2989 | +out: |
| 2990 | + btrfs_free_path(path); |
| 2991 | + kfree(inodes); |
| 2992 | + kfree(loi); |
| 2993 | + |
| 2994 | + return ret; |
| 2995 | +} |
| 2996 | + |
2858 | 2997 | long btrfs_ioctl(struct file *file, unsigned int
|
2859 | 2998 | cmd, unsigned long arg)
|
2860 | 2999 | {
|
@@ -2912,6 +3051,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
2912 | 3051 | return btrfs_ioctl_tree_search(file, argp);
|
2913 | 3052 | case BTRFS_IOC_INO_LOOKUP:
|
2914 | 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 | 3058 | case BTRFS_IOC_SPACE_INFO:
|
2916 | 3059 | return btrfs_ioctl_space_info(root, argp);
|
2917 | 3060 | case BTRFS_IOC_SYNC:
|
|
0 commit comments