diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 238 |
1 files changed, 205 insertions, 33 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index dae5dfe41ba5..72d461656f60 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. */ |
56 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) | 57 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) |
@@ -117,7 +118,7 @@ void btrfs_update_iflags(struct inode *inode) | |||
117 | /* | 118 | /* |
118 | * Inherit flags from the parent inode. | 119 | * Inherit flags from the parent inode. |
119 | * | 120 | * |
120 | * Unlike extN we don't have any flags we don't want to inherit currently. | 121 | * Currently only the compression flags and the cow flags are inherited. |
121 | */ | 122 | */ |
122 | void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) | 123 | void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) |
123 | { | 124 | { |
@@ -128,12 +129,17 @@ void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) | |||
128 | 129 | ||
129 | flags = BTRFS_I(dir)->flags; | 130 | flags = BTRFS_I(dir)->flags; |
130 | 131 | ||
131 | if (S_ISREG(inode->i_mode)) | 132 | if (flags & BTRFS_INODE_NOCOMPRESS) { |
132 | flags &= ~BTRFS_INODE_DIRSYNC; | 133 | BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; |
133 | else if (!S_ISDIR(inode->i_mode)) | 134 | BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; |
134 | flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME); | 135 | } else if (flags & BTRFS_INODE_COMPRESS) { |
136 | BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; | ||
137 | BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; | ||
138 | } | ||
139 | |||
140 | if (flags & BTRFS_INODE_NODATACOW) | ||
141 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
135 | 142 | ||
136 | BTRFS_I(inode)->flags = flags; | ||
137 | btrfs_update_iflags(inode); | 143 | btrfs_update_iflags(inode); |
138 | } | 144 | } |
139 | 145 | ||
@@ -277,6 +283,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
277 | struct fstrim_range range; | 283 | struct fstrim_range range; |
278 | u64 minlen = ULLONG_MAX; | 284 | u64 minlen = ULLONG_MAX; |
279 | u64 num_devices = 0; | 285 | u64 num_devices = 0; |
286 | u64 total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); | ||
280 | int ret; | 287 | int ret; |
281 | 288 | ||
282 | if (!capable(CAP_SYS_ADMIN)) | 289 | if (!capable(CAP_SYS_ADMIN)) |
@@ -295,12 +302,15 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
295 | } | 302 | } |
296 | } | 303 | } |
297 | rcu_read_unlock(); | 304 | rcu_read_unlock(); |
305 | |||
298 | if (!num_devices) | 306 | if (!num_devices) |
299 | return -EOPNOTSUPP; | 307 | return -EOPNOTSUPP; |
300 | |||
301 | if (copy_from_user(&range, arg, sizeof(range))) | 308 | if (copy_from_user(&range, arg, sizeof(range))) |
302 | return -EFAULT; | 309 | return -EFAULT; |
310 | if (range.start > total_bytes) | ||
311 | return -EINVAL; | ||
303 | 312 | ||
313 | range.len = min(range.len, total_bytes - range.start); | ||
304 | range.minlen = max(range.minlen, minlen); | 314 | range.minlen = max(range.minlen, minlen); |
305 | ret = btrfs_trim_fs(root, &range); | 315 | ret = btrfs_trim_fs(root, &range); |
306 | if (ret < 0) | 316 | if (ret < 0) |
@@ -760,7 +770,7 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
760 | int ret = 1; | 770 | int ret = 1; |
761 | 771 | ||
762 | /* | 772 | /* |
763 | * make sure that once we start defragging and extent, we keep on | 773 | * make sure that once we start defragging an extent, we keep on |
764 | * defragging it | 774 | * defragging it |
765 | */ | 775 | */ |
766 | if (start < *defrag_end) | 776 | if (start < *defrag_end) |
@@ -805,7 +815,6 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
805 | * extent will force at least part of that big extent to be defragged. | 815 | * extent will force at least part of that big extent to be defragged. |
806 | */ | 816 | */ |
807 | if (ret) { | 817 | if (ret) { |
808 | *last_len += len; | ||
809 | *defrag_end = extent_map_end(em); | 818 | *defrag_end = extent_map_end(em); |
810 | } else { | 819 | } else { |
811 | *last_len = 0; | 820 | *last_len = 0; |
@@ -843,6 +852,7 @@ static int cluster_pages_for_defrag(struct inode *inode, | |||
843 | int i_done; | 852 | int i_done; |
844 | struct btrfs_ordered_extent *ordered; | 853 | struct btrfs_ordered_extent *ordered; |
845 | struct extent_state *cached_state = NULL; | 854 | struct extent_state *cached_state = NULL; |
855 | gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); | ||
846 | 856 | ||
847 | if (isize == 0) | 857 | if (isize == 0) |
848 | return 0; | 858 | return 0; |
@@ -860,7 +870,7 @@ again: | |||
860 | for (i = 0; i < num_pages; i++) { | 870 | for (i = 0; i < num_pages; i++) { |
861 | struct page *page; | 871 | struct page *page; |
862 | page = find_or_create_page(inode->i_mapping, | 872 | page = find_or_create_page(inode->i_mapping, |
863 | start_index + i, GFP_NOFS); | 873 | start_index + i, mask); |
864 | if (!page) | 874 | if (!page) |
865 | break; | 875 | break; |
866 | 876 | ||
@@ -972,18 +982,20 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
972 | struct btrfs_super_block *disk_super; | 982 | struct btrfs_super_block *disk_super; |
973 | struct file_ra_state *ra = NULL; | 983 | struct file_ra_state *ra = NULL; |
974 | unsigned long last_index; | 984 | unsigned long last_index; |
985 | u64 isize = i_size_read(inode); | ||
975 | u64 features; | 986 | u64 features; |
976 | u64 last_len = 0; | 987 | u64 last_len = 0; |
977 | u64 skip = 0; | 988 | u64 skip = 0; |
978 | u64 defrag_end = 0; | 989 | u64 defrag_end = 0; |
979 | u64 newer_off = range->start; | 990 | u64 newer_off = range->start; |
980 | int newer_left = 0; | ||
981 | unsigned long i; | 991 | unsigned long i; |
992 | unsigned long ra_index = 0; | ||
982 | int ret; | 993 | int ret; |
983 | int defrag_count = 0; | 994 | int defrag_count = 0; |
984 | int compress_type = BTRFS_COMPRESS_ZLIB; | 995 | int compress_type = BTRFS_COMPRESS_ZLIB; |
985 | int extent_thresh = range->extent_thresh; | 996 | int extent_thresh = range->extent_thresh; |
986 | int newer_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; | 997 | int max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; |
998 | int cluster = max_cluster; | ||
987 | u64 new_align = ~((u64)128 * 1024 - 1); | 999 | u64 new_align = ~((u64)128 * 1024 - 1); |
988 | struct page **pages = NULL; | 1000 | struct page **pages = NULL; |
989 | 1001 | ||
@@ -997,7 +1009,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
997 | compress_type = range->compress_type; | 1009 | compress_type = range->compress_type; |
998 | } | 1010 | } |
999 | 1011 | ||
1000 | if (inode->i_size == 0) | 1012 | if (isize == 0) |
1001 | return 0; | 1013 | return 0; |
1002 | 1014 | ||
1003 | /* | 1015 | /* |
@@ -1013,7 +1025,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1013 | ra = &file->f_ra; | 1025 | ra = &file->f_ra; |
1014 | } | 1026 | } |
1015 | 1027 | ||
1016 | pages = kmalloc(sizeof(struct page *) * newer_cluster, | 1028 | pages = kmalloc(sizeof(struct page *) * max_cluster, |
1017 | GFP_NOFS); | 1029 | GFP_NOFS); |
1018 | if (!pages) { | 1030 | if (!pages) { |
1019 | ret = -ENOMEM; | 1031 | ret = -ENOMEM; |
@@ -1022,10 +1034,10 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1022 | 1034 | ||
1023 | /* find the last page to defrag */ | 1035 | /* find the last page to defrag */ |
1024 | if (range->start + range->len > range->start) { | 1036 | if (range->start + range->len > range->start) { |
1025 | last_index = min_t(u64, inode->i_size - 1, | 1037 | last_index = min_t(u64, isize - 1, |
1026 | range->start + range->len - 1) >> PAGE_CACHE_SHIFT; | 1038 | range->start + range->len - 1) >> PAGE_CACHE_SHIFT; |
1027 | } else { | 1039 | } else { |
1028 | last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; | 1040 | last_index = (isize - 1) >> PAGE_CACHE_SHIFT; |
1029 | } | 1041 | } |
1030 | 1042 | ||
1031 | if (newer_than) { | 1043 | if (newer_than) { |
@@ -1038,14 +1050,13 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1038 | * the extents in the file evenly spaced | 1050 | * the extents in the file evenly spaced |
1039 | */ | 1051 | */ |
1040 | i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; | 1052 | i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; |
1041 | newer_left = newer_cluster; | ||
1042 | } else | 1053 | } else |
1043 | goto out_ra; | 1054 | goto out_ra; |
1044 | } else { | 1055 | } else { |
1045 | i = range->start >> PAGE_CACHE_SHIFT; | 1056 | i = range->start >> PAGE_CACHE_SHIFT; |
1046 | } | 1057 | } |
1047 | if (!max_to_defrag) | 1058 | if (!max_to_defrag) |
1048 | max_to_defrag = last_index - 1; | 1059 | max_to_defrag = last_index; |
1049 | 1060 | ||
1050 | /* | 1061 | /* |
1051 | * make writeback starts from i, so the defrag range can be | 1062 | * make writeback starts from i, so the defrag range can be |
@@ -1079,18 +1090,31 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1079 | i = max(i + 1, next); | 1090 | i = max(i + 1, next); |
1080 | continue; | 1091 | continue; |
1081 | } | 1092 | } |
1093 | |||
1094 | if (!newer_than) { | ||
1095 | cluster = (PAGE_CACHE_ALIGN(defrag_end) >> | ||
1096 | PAGE_CACHE_SHIFT) - i; | ||
1097 | cluster = min(cluster, max_cluster); | ||
1098 | } else { | ||
1099 | cluster = max_cluster; | ||
1100 | } | ||
1101 | |||
1082 | if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) | 1102 | if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) |
1083 | BTRFS_I(inode)->force_compress = compress_type; | 1103 | BTRFS_I(inode)->force_compress = compress_type; |
1084 | 1104 | ||
1085 | btrfs_force_ra(inode->i_mapping, ra, file, i, newer_cluster); | 1105 | if (i + cluster > ra_index) { |
1106 | ra_index = max(i, ra_index); | ||
1107 | btrfs_force_ra(inode->i_mapping, ra, file, ra_index, | ||
1108 | cluster); | ||
1109 | ra_index += max_cluster; | ||
1110 | } | ||
1086 | 1111 | ||
1087 | ret = cluster_pages_for_defrag(inode, pages, i, newer_cluster); | 1112 | ret = cluster_pages_for_defrag(inode, pages, i, cluster); |
1088 | if (ret < 0) | 1113 | if (ret < 0) |
1089 | goto out_ra; | 1114 | goto out_ra; |
1090 | 1115 | ||
1091 | defrag_count += ret; | 1116 | defrag_count += ret; |
1092 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret); | 1117 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret); |
1093 | i += ret; | ||
1094 | 1118 | ||
1095 | if (newer_than) { | 1119 | if (newer_than) { |
1096 | if (newer_off == (u64)-1) | 1120 | if (newer_off == (u64)-1) |
@@ -1105,12 +1129,17 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1105 | if (!ret) { | 1129 | if (!ret) { |
1106 | range->start = newer_off; | 1130 | range->start = newer_off; |
1107 | i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; | 1131 | i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; |
1108 | newer_left = newer_cluster; | ||
1109 | } else { | 1132 | } else { |
1110 | break; | 1133 | break; |
1111 | } | 1134 | } |
1112 | } else { | 1135 | } else { |
1113 | i++; | 1136 | if (ret > 0) { |
1137 | i += ret; | ||
1138 | last_len += ret << PAGE_CACHE_SHIFT; | ||
1139 | } else { | ||
1140 | i++; | ||
1141 | last_len = 0; | ||
1142 | } | ||
1114 | } | 1143 | } |
1115 | } | 1144 | } |
1116 | 1145 | ||
@@ -1136,16 +1165,14 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1136 | mutex_unlock(&inode->i_mutex); | 1165 | mutex_unlock(&inode->i_mutex); |
1137 | } | 1166 | } |
1138 | 1167 | ||
1139 | disk_super = &root->fs_info->super_copy; | 1168 | disk_super = root->fs_info->super_copy; |
1140 | features = btrfs_super_incompat_flags(disk_super); | 1169 | features = btrfs_super_incompat_flags(disk_super); |
1141 | if (range->compress_type == BTRFS_COMPRESS_LZO) { | 1170 | if (range->compress_type == BTRFS_COMPRESS_LZO) { |
1142 | features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; | 1171 | features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; |
1143 | btrfs_set_super_incompat_flags(disk_super, features); | 1172 | btrfs_set_super_incompat_flags(disk_super, features); |
1144 | } | 1173 | } |
1145 | 1174 | ||
1146 | if (!file) | 1175 | ret = defrag_count; |
1147 | kfree(ra); | ||
1148 | return defrag_count; | ||
1149 | 1176 | ||
1150 | out_ra: | 1177 | out_ra: |
1151 | if (!file) | 1178 | if (!file) |
@@ -1189,12 +1216,12 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1189 | *devstr = '\0'; | 1216 | *devstr = '\0'; |
1190 | devstr = vol_args->name; | 1217 | devstr = vol_args->name; |
1191 | devid = simple_strtoull(devstr, &end, 10); | 1218 | devid = simple_strtoull(devstr, &end, 10); |
1192 | printk(KERN_INFO "resizing devid %llu\n", | 1219 | printk(KERN_INFO "btrfs: resizing devid %llu\n", |
1193 | (unsigned long long)devid); | 1220 | (unsigned long long)devid); |
1194 | } | 1221 | } |
1195 | device = btrfs_find_device(root, devid, NULL, NULL); | 1222 | device = btrfs_find_device(root, devid, NULL, NULL); |
1196 | if (!device) { | 1223 | if (!device) { |
1197 | printk(KERN_INFO "resizer unable to find device %llu\n", | 1224 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", |
1198 | (unsigned long long)devid); | 1225 | (unsigned long long)devid); |
1199 | ret = -EINVAL; | 1226 | ret = -EINVAL; |
1200 | goto out_unlock; | 1227 | goto out_unlock; |
@@ -1240,7 +1267,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1240 | do_div(new_size, root->sectorsize); | 1267 | do_div(new_size, root->sectorsize); |
1241 | new_size *= root->sectorsize; | 1268 | new_size *= root->sectorsize; |
1242 | 1269 | ||
1243 | printk(KERN_INFO "new size for %s is %llu\n", | 1270 | printk(KERN_INFO "btrfs: new size for %s is %llu\n", |
1244 | device->name, (unsigned long long)new_size); | 1271 | device->name, (unsigned long long)new_size); |
1245 | 1272 | ||
1246 | if (new_size > old_size) { | 1273 | if (new_size > old_size) { |
@@ -1251,7 +1278,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1251 | } | 1278 | } |
1252 | ret = btrfs_grow_device(trans, device, new_size); | 1279 | ret = btrfs_grow_device(trans, device, new_size); |
1253 | btrfs_commit_transaction(trans, root); | 1280 | btrfs_commit_transaction(trans, root); |
1254 | } else { | 1281 | } else if (new_size < old_size) { |
1255 | ret = btrfs_shrink_device(device, new_size); | 1282 | ret = btrfs_shrink_device(device, new_size); |
1256 | } | 1283 | } |
1257 | 1284 | ||
@@ -2587,7 +2614,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
2587 | return PTR_ERR(trans); | 2614 | return PTR_ERR(trans); |
2588 | } | 2615 | } |
2589 | 2616 | ||
2590 | dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); | 2617 | dir_id = btrfs_super_root_dir(root->fs_info->super_copy); |
2591 | di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, | 2618 | di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, |
2592 | dir_id, "default", 7, 1); | 2619 | dir_id, "default", 7, 1); |
2593 | if (IS_ERR_OR_NULL(di)) { | 2620 | if (IS_ERR_OR_NULL(di)) { |
@@ -2603,7 +2630,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
2603 | btrfs_mark_buffer_dirty(path->nodes[0]); | 2630 | btrfs_mark_buffer_dirty(path->nodes[0]); |
2604 | btrfs_free_path(path); | 2631 | btrfs_free_path(path); |
2605 | 2632 | ||
2606 | disk_super = &root->fs_info->super_copy; | 2633 | disk_super = root->fs_info->super_copy; |
2607 | features = btrfs_super_incompat_flags(disk_super); | 2634 | features = btrfs_super_incompat_flags(disk_super); |
2608 | if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { | 2635 | if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { |
2609 | features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; | 2636 | features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; |
@@ -2864,6 +2891,147 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, | |||
2864 | return ret; | 2891 | return ret; |
2865 | } | 2892 | } |
2866 | 2893 | ||
2894 | static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) | ||
2895 | { | ||
2896 | int ret = 0; | ||
2897 | int i; | ||
2898 | u64 rel_ptr; | ||
2899 | int size; | ||
2900 | struct btrfs_ioctl_ino_path_args *ipa = NULL; | ||
2901 | struct inode_fs_paths *ipath = NULL; | ||
2902 | struct btrfs_path *path; | ||
2903 | |||
2904 | if (!capable(CAP_SYS_ADMIN)) | ||
2905 | return -EPERM; | ||
2906 | |||
2907 | path = btrfs_alloc_path(); | ||
2908 | if (!path) { | ||
2909 | ret = -ENOMEM; | ||
2910 | goto out; | ||
2911 | } | ||
2912 | |||
2913 | ipa = memdup_user(arg, sizeof(*ipa)); | ||
2914 | if (IS_ERR(ipa)) { | ||
2915 | ret = PTR_ERR(ipa); | ||
2916 | ipa = NULL; | ||
2917 | goto out; | ||
2918 | } | ||
2919 | |||
2920 | size = min_t(u32, ipa->size, 4096); | ||
2921 | ipath = init_ipath(size, root, path); | ||
2922 | if (IS_ERR(ipath)) { | ||
2923 | ret = PTR_ERR(ipath); | ||
2924 | ipath = NULL; | ||
2925 | goto out; | ||
2926 | } | ||
2927 | |||
2928 | ret = paths_from_inode(ipa->inum, ipath); | ||
2929 | if (ret < 0) | ||
2930 | goto out; | ||
2931 | |||
2932 | for (i = 0; i < ipath->fspath->elem_cnt; ++i) { | ||
2933 | rel_ptr = ipath->fspath->val[i] - | ||
2934 | (u64)(unsigned long)ipath->fspath->val; | ||
2935 | ipath->fspath->val[i] = rel_ptr; | ||
2936 | } | ||
2937 | |||
2938 | ret = copy_to_user((void *)(unsigned long)ipa->fspath, | ||
2939 | (void *)(unsigned long)ipath->fspath, size); | ||
2940 | if (ret) { | ||
2941 | ret = -EFAULT; | ||
2942 | goto out; | ||
2943 | } | ||
2944 | |||
2945 | out: | ||
2946 | btrfs_free_path(path); | ||
2947 | free_ipath(ipath); | ||
2948 | kfree(ipa); | ||
2949 | |||
2950 | return ret; | ||
2951 | } | ||
2952 | |||
2953 | static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx) | ||
2954 | { | ||
2955 | struct btrfs_data_container *inodes = ctx; | ||
2956 | const size_t c = 3 * sizeof(u64); | ||
2957 | |||
2958 | if (inodes->bytes_left >= c) { | ||
2959 | inodes->bytes_left -= c; | ||
2960 | inodes->val[inodes->elem_cnt] = inum; | ||
2961 | inodes->val[inodes->elem_cnt + 1] = offset; | ||
2962 | inodes->val[inodes->elem_cnt + 2] = root; | ||
2963 | inodes->elem_cnt += 3; | ||
2964 | } else { | ||
2965 | inodes->bytes_missing += c - inodes->bytes_left; | ||
2966 | inodes->bytes_left = 0; | ||
2967 | inodes->elem_missed += 3; | ||
2968 | } | ||
2969 | |||
2970 | return 0; | ||
2971 | } | ||
2972 | |||
2973 | static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, | ||
2974 | void __user *arg) | ||
2975 | { | ||
2976 | int ret = 0; | ||
2977 | int size; | ||
2978 | u64 extent_offset; | ||
2979 | struct btrfs_ioctl_logical_ino_args *loi; | ||
2980 | struct btrfs_data_container *inodes = NULL; | ||
2981 | struct btrfs_path *path = NULL; | ||
2982 | struct btrfs_key key; | ||
2983 | |||
2984 | if (!capable(CAP_SYS_ADMIN)) | ||
2985 | return -EPERM; | ||
2986 | |||
2987 | loi = memdup_user(arg, sizeof(*loi)); | ||
2988 | if (IS_ERR(loi)) { | ||
2989 | ret = PTR_ERR(loi); | ||
2990 | loi = NULL; | ||
2991 | goto out; | ||
2992 | } | ||
2993 | |||
2994 | path = btrfs_alloc_path(); | ||
2995 | if (!path) { | ||
2996 | ret = -ENOMEM; | ||
2997 | goto out; | ||
2998 | } | ||
2999 | |||
3000 | size = min_t(u32, loi->size, 4096); | ||
3001 | inodes = init_data_container(size); | ||
3002 | if (IS_ERR(inodes)) { | ||
3003 | ret = PTR_ERR(inodes); | ||
3004 | inodes = NULL; | ||
3005 | goto out; | ||
3006 | } | ||
3007 | |||
3008 | ret = extent_from_logical(root->fs_info, loi->logical, path, &key); | ||
3009 | |||
3010 | if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) | ||
3011 | ret = -ENOENT; | ||
3012 | if (ret < 0) | ||
3013 | goto out; | ||
3014 | |||
3015 | extent_offset = loi->logical - key.objectid; | ||
3016 | ret = iterate_extent_inodes(root->fs_info, path, key.objectid, | ||
3017 | extent_offset, build_ino_list, inodes); | ||
3018 | |||
3019 | if (ret < 0) | ||
3020 | goto out; | ||
3021 | |||
3022 | ret = copy_to_user((void *)(unsigned long)loi->inodes, | ||
3023 | (void *)(unsigned long)inodes, size); | ||
3024 | if (ret) | ||
3025 | ret = -EFAULT; | ||
3026 | |||
3027 | out: | ||
3028 | btrfs_free_path(path); | ||
3029 | kfree(inodes); | ||
3030 | kfree(loi); | ||
3031 | |||
3032 | return ret; | ||
3033 | } | ||
3034 | |||
2867 | long btrfs_ioctl(struct file *file, unsigned int | 3035 | long btrfs_ioctl(struct file *file, unsigned int |
2868 | cmd, unsigned long arg) | 3036 | cmd, unsigned long arg) |
2869 | { | 3037 | { |
@@ -2921,6 +3089,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2921 | return btrfs_ioctl_tree_search(file, argp); | 3089 | return btrfs_ioctl_tree_search(file, argp); |
2922 | case BTRFS_IOC_INO_LOOKUP: | 3090 | case BTRFS_IOC_INO_LOOKUP: |
2923 | return btrfs_ioctl_ino_lookup(file, argp); | 3091 | return btrfs_ioctl_ino_lookup(file, argp); |
3092 | case BTRFS_IOC_INO_PATHS: | ||
3093 | return btrfs_ioctl_ino_to_path(root, argp); | ||
3094 | case BTRFS_IOC_LOGICAL_INO: | ||
3095 | return btrfs_ioctl_logical_to_ino(root, argp); | ||
2924 | case BTRFS_IOC_SPACE_INFO: | 3096 | case BTRFS_IOC_SPACE_INFO: |
2925 | return btrfs_ioctl_space_info(root, argp); | 3097 | return btrfs_ioctl_space_info(root, argp); |
2926 | case BTRFS_IOC_SYNC: | 3098 | case BTRFS_IOC_SYNC: |