Pull more btrfs updates from Chris Mason: "This has a few fixes since our last pull and a new ioctl for doing btree searches from userland. It's very similar to the existing ioctl, but lets us return larger items back down to the app" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: btrfs: fix error handling in create_pending_snapshot btrfs: fix use of uninit "ret" in end_extent_writepage() btrfs: free ulist in qgroup_shared_accounting() error path Btrfs: fix qgroups sanity test crash or hang btrfs: prevent RCU warning when dereferencing radix tree slot Btrfs: fix unfinished readahead thread for raid5/6 degraded mounting btrfs: new ioctl TREE_SEARCH_V2 btrfs: tree_search, search_ioctl: direct copy to userspace btrfs: new function read_extent_buffer_to_user btrfs: tree_search, copy_to_sk: return needed size on EOVERFLOW btrfs: tree_search, copy_to_sk: return EOVERFLOW for too small buffer btrfs: tree_search, search_ioctl: accept varying buffer btrfs: tree_search: eliminate redundant nr_items check
Unified · Split
| @@ -2354,7 +2354,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) · 2353 unmodified lines | ||
| 2354 | 2354 | { |
| 2355 | 2355 | int uptodate = (err == 0); |
| 2356 | 2356 | struct extent_io_tree *tree; |
| 2357 | − int ret; | |
| 2357 | + int ret = 0; | |
| 2358 | 2358 | |
| 2359 | 2359 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
| 2360 | 2360 | |
| @@ -5068,6 +5068,43 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, · 2707 unmodified lines | ||
| 5068 | 5068 | } |
| 5069 | 5069 | } |
| 5070 | 5070 | |
| 5071 | +int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv, | |
| 5072 | + unsigned long start, | |
| 5073 | + unsigned long len) | |
| 5074 | +{ | |
| 5075 | + size_t cur; | |
| 5076 | + size_t offset; | |
| 5077 | + struct page *page; | |
| 5078 | + char *kaddr; | |
| 5079 | + char __user *dst = (char __user *)dstv; | |
| 5080 | + size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1); | |
| 5081 | + unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT; | |
| 5082 | + int ret = 0; | |
| 5083 | + | |
| 5084 | + WARN_ON(start > eb->len); | |
| 5085 | + WARN_ON(start + len > eb->start + eb->len); | |
| 5086 | + | |
| 5087 | + offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1); | |
| 5088 | + | |
| 5089 | + while (len > 0) { | |
| 5090 | + page = extent_buffer_page(eb, i); | |
| 5091 | + | |
| 5092 | + cur = min(len, (PAGE_CACHE_SIZE - offset)); | |
| 5093 | + kaddr = page_address(page); | |
| 5094 | + if (copy_to_user(dst, kaddr + offset, cur)) { | |
| 5095 | + ret = -EFAULT; | |
| 5096 | + break; | |
| 5097 | + } | |
| 5098 | + | |
| 5099 | + dst += cur; | |
| 5100 | + len -= cur; | |
| 5101 | + offset = 0; | |
| 5102 | + i++; | |
| 5103 | + } | |
| 5104 | + | |
| 5105 | + return ret; | |
| 5106 | +} | |
| 5107 | + | |
| 5071 | 5108 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, |
| 5072 | 5109 | unsigned long min_len, char **map, |
| 5073 | 5110 | unsigned long *map_start, |
| @@ -304,6 +304,9 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, · 303 unmodified lines | ||
| 304 | 304 | void read_extent_buffer(struct extent_buffer *eb, void *dst, |
| 305 | 305 | unsigned long start, |
| 306 | 306 | unsigned long len); |
| 307 | +int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst, | |
| 308 | + unsigned long start, | |
| 309 | + unsigned long len); | |
| 307 | 310 | void write_extent_buffer(struct extent_buffer *eb, const void *src, |
| 308 | 311 | unsigned long start, unsigned long len); |
| 309 | 312 | void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, |
| @@ -1957,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 1956 unmodified lines | ||
| 1957 | 1957 | struct btrfs_path *path, |
| 1958 | 1958 | struct btrfs_key *key, |
| 1959 | 1959 | struct btrfs_ioctl_search_key *sk, |
| 1960 | − char *buf, | |
| 1960 | + size_t *buf_size, | |
| 1961 | + char __user *ubuf, | |
| 1961 | 1962 | unsigned long *sk_offset, |
| 1962 | 1963 | int *num_found) |
| 1963 | 1964 | { |
| @@ -1989,13 +1990,25 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 25 unmodified lines | ||
| 1989 | 1990 | if (!key_in_sk(key, sk)) |
| 1990 | 1991 | continue; |
| 1991 | 1992 | |
| 1992 | − if (sizeof(sh) + item_len > BTRFS_SEARCH_ARGS_BUFSIZE) | |
| 1993 | + if (sizeof(sh) + item_len > *buf_size) { | |
| 1994 | + if (*num_found) { | |
| 1995 | + ret = 1; | |
| 1996 | + goto out; | |
| 1997 | + } | |
| 1998 | + | |
| 1999 | + /* | |
| 2000 | + * return one empty item back for v1, which does not | |
| 2001 | + * handle -EOVERFLOW | |
| 2002 | + */ | |
| 2003 | + | |
| 2004 | + *buf_size = sizeof(sh) + item_len; | |
| 1993 | 2005 | item_len = 0; |
| 2006 | + ret = -EOVERFLOW; | |
| 2007 | + } | |
| 1994 | 2008 | |
| 1995 | − if (sizeof(sh) + item_len + *sk_offset > | |
| 1996 | − BTRFS_SEARCH_ARGS_BUFSIZE) { | |
| 2009 | + if (sizeof(sh) + item_len + *sk_offset > *buf_size) { | |
| 1997 | 2010 | ret = 1; |
| 1998 | − goto overflow; | |
| 2011 | + goto out; | |
| 1999 | 2012 | } |
| 2000 | 2013 | |
| 2001 | 2014 | sh.objectid = key->objectid; |
| @@ -2005,20 +2018,33 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 3 unmodified lines | ||
| 2005 | 2018 | sh.transid = found_transid; |
| 2006 | 2019 | |
| 2007 | 2020 | /* copy search result header */ |
| 2008 | − memcpy(buf + *sk_offset, &sh, sizeof(sh)); | |
| 2021 | + if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) { | |
| 2022 | + ret = -EFAULT; | |
| 2023 | + goto out; | |
| 2024 | + } | |
| 2025 | + | |
| 2009 | 2026 | *sk_offset += sizeof(sh); |
| 2010 | 2027 | |
| 2011 | 2028 | if (item_len) { |
| 2012 | − char *p = buf + *sk_offset; | |
| 2029 | + char __user *up = ubuf + *sk_offset; | |
| 2013 | 2030 | /* copy the item */ |
| 2014 | − read_extent_buffer(leaf, p, | |
| 2015 | − item_off, item_len); | |
| 2031 | + if (read_extent_buffer_to_user(leaf, up, | |
| 2032 | + item_off, item_len)) { | |
| 2033 | + ret = -EFAULT; | |
| 2034 | + goto out; | |
| 2035 | + } | |
| 2036 | + | |
| 2016 | 2037 | *sk_offset += item_len; |
| 2017 | 2038 | } |
| 2018 | 2039 | (*num_found)++; |
| 2019 | 2040 | |
| 2020 | − if (*num_found >= sk->nr_items) | |
| 2021 | − break; | |
| 2041 | + if (ret) /* -EOVERFLOW from above */ | |
| 2042 | + goto out; | |
| 2043 | + | |
| 2044 | + if (*num_found >= sk->nr_items) { | |
| 2045 | + ret = 1; | |
| 2046 | + goto out; | |
| 2047 | + } | |
| 2022 | 2048 | } |
| 2023 | 2049 | advance_key: |
| 2024 | 2050 | ret = 0; |
| @@ -2033,22 +2059,37 @@ advance_key: · 8 unmodified lines | ||
| 2033 | 2059 | key->objectid++; |
| 2034 | 2060 | } else |
| 2035 | 2061 | ret = 1; |
| 2036 | −overflow: | |
| 2062 | +out: | |
| 2063 | + /* | |
| 2064 | + * 0: all items from this leaf copied, continue with next | |
| 2065 | + * 1: * more items can be copied, but unused buffer is too small | |
| 2066 | + * * all items were found | |
| 2067 | + * Either way, it will stops the loop which iterates to the next | |
| 2068 | + * leaf | |
| 2069 | + * -EOVERFLOW: item was to large for buffer | |
| 2070 | + * -EFAULT: could not copy extent buffer back to userspace | |
| 2071 | + */ | |
| 2037 | 2072 | return ret; |
| 2038 | 2073 | } |
| 2039 | 2074 | |
| 2040 | 2075 | static noinline int search_ioctl(struct inode *inode, |
| 2041 | − struct btrfs_ioctl_search_args *args) | |
| 2076 | + struct btrfs_ioctl_search_key *sk, | |
| 2077 | + size_t *buf_size, | |
| 2078 | + char __user *ubuf) | |
| 2042 | 2079 | { |
| 2043 | 2080 | struct btrfs_root *root; |
| 2044 | 2081 | struct btrfs_key key; |
| 2045 | 2082 | struct btrfs_path *path; |
| 2046 | − struct btrfs_ioctl_search_key *sk = &args->key; | |
| 2047 | 2083 | struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info; |
| 2048 | 2084 | int ret; |
| 2049 | 2085 | int num_found = 0; |
| 2050 | 2086 | unsigned long sk_offset = 0; |
| 2051 | 2087 | |
| 2088 | + if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { | |
| 2089 | + *buf_size = sizeof(struct btrfs_ioctl_search_header); | |
| 2090 | + return -EOVERFLOW; | |
| 2091 | + } | |
| 2092 | + | |
| 2052 | 2093 | path = btrfs_alloc_path(); |
| 2053 | 2094 | if (!path) |
| 2054 | 2095 | return -ENOMEM; |
| @@ -2082,14 +2123,15 @@ static noinline int search_ioctl(struct inode *inode, · 27 unmodified lines | ||
| 2082 | 2123 | ret = 0; |
| 2083 | 2124 | goto err; |
| 2084 | 2125 | } |
| 2085 | − ret = copy_to_sk(root, path, &key, sk, args->buf, | |
| 2126 | + ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf, | |
| 2086 | 2127 | &sk_offset, &num_found); |
| 2087 | 2128 | btrfs_release_path(path); |
| 2088 | − if (ret || num_found >= sk->nr_items) | |
| 2129 | + if (ret) | |
| 2089 | 2130 | break; |
| 2090 | 2131 | |
| 2091 | 2132 | } |
| 2092 | − ret = 0; | |
| 2133 | + if (ret > 0) | |
| 2134 | + ret = 0; | |
| 2093 | 2135 | err: |
| 2094 | 2136 | sk->nr_items = num_found; |
| 2095 | 2137 | btrfs_free_path(path); |
| @@ -2099,22 +2141,73 @@ err: · 3 unmodified lines | ||
| 2099 | 2141 | static noinline int btrfs_ioctl_tree_search(struct file *file, |
| 2100 | 2142 | void __user *argp) |
| 2101 | 2143 | { |
| 2102 | − struct btrfs_ioctl_search_args *args; | |
| 2103 | − struct inode *inode; | |
| 2104 | − int ret; | |
| 2144 | + struct btrfs_ioctl_search_args __user *uargs; | |
| 2145 | + struct btrfs_ioctl_search_key sk; | |
| 2146 | + struct inode *inode; | |
| 2147 | + int ret; | |
| 2148 | + size_t buf_size; | |
| 2105 | 2149 | |
| 2106 | 2150 | if (!capable(CAP_SYS_ADMIN)) |
| 2107 | 2151 | return -EPERM; |
| 2108 | 2152 | |
| 2109 | − args = memdup_user(argp, sizeof(*args)); | |
| 2110 | − if (IS_ERR(args)) | |
| 2111 | − return PTR_ERR(args); | |
| 2153 | + uargs = (struct btrfs_ioctl_search_args __user *)argp; | |
| 2154 | + | |
| 2155 | + if (copy_from_user(&sk, &uargs->key, sizeof(sk))) | |
| 2156 | + return -EFAULT; | |
| 2157 | + | |
| 2158 | + buf_size = sizeof(uargs->buf); | |
| 2112 | 2159 | |
| 2113 | 2160 | inode = file_inode(file); |
| 2114 | − ret = search_ioctl(inode, args); | |
| 2115 | − if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) | |
| 2161 | + ret = search_ioctl(inode, &sk, &buf_size, uargs->buf); | |
| 2162 | + | |
| 2163 | + /* | |
| 2164 | + * In the origin implementation an overflow is handled by returning a | |
| 2165 | + * search header with a len of zero, so reset ret. | |
| 2166 | + */ | |
| 2167 | + if (ret == -EOVERFLOW) | |
| 2168 | + ret = 0; | |
| 2169 | + | |
| 2170 | + if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk))) | |
| 2116 | 2171 | ret = -EFAULT; |
| 2117 | − kfree(args); | |
| 2172 | + return ret; | |
| 2173 | +} | |
| 2174 | + | |
| 2175 | +static noinline int btrfs_ioctl_tree_search_v2(struct file *file, | |
| 2176 | + void __user *argp) | |
| 2177 | +{ | |
| 2178 | + struct btrfs_ioctl_search_args_v2 __user *uarg; | |
| 2179 | + struct btrfs_ioctl_search_args_v2 args; | |
| 2180 | + struct inode *inode; | |
| 2181 | + int ret; | |
| 2182 | + size_t buf_size; | |
| 2183 | + const size_t buf_limit = 16 * 1024 * 1024; | |
| 2184 | + | |
| 2185 | + if (!capable(CAP_SYS_ADMIN)) | |
| 2186 | + return -EPERM; | |
| 2187 | + | |
| 2188 | + /* copy search header and buffer size */ | |
| 2189 | + uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp; | |
| 2190 | + if (copy_from_user(&args, uarg, sizeof(args))) | |
| 2191 | + return -EFAULT; | |
| 2192 | + | |
| 2193 | + buf_size = args.buf_size; | |
| 2194 | + | |
| 2195 | + if (buf_size < sizeof(struct btrfs_ioctl_search_header)) | |
| 2196 | + return -EOVERFLOW; | |
| 2197 | + | |
| 2198 | + /* limit result size to 16MB */ | |
| 2199 | + if (buf_size > buf_limit) | |
| 2200 | + buf_size = buf_limit; | |
| 2201 | + | |
| 2202 | + inode = file_inode(file); | |
| 2203 | + ret = search_ioctl(inode, &args.key, &buf_size, | |
| 2204 | + (char *)(&uarg->buf[0])); | |
| 2205 | + if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) | |
| 2206 | + ret = -EFAULT; | |
| 2207 | + else if (ret == -EOVERFLOW && | |
| 2208 | + copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size))) | |
| 2209 | + ret = -EFAULT; | |
| 2210 | + | |
| 2118 | 2211 | return ret; |
| 2119 | 2212 | } |
| 2120 | 2213 | |
| @@ -5198,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int · 3077 unmodified lines | ||
| 5198 | 5291 | return btrfs_ioctl_trans_end(file); |
| 5199 | 5292 | case BTRFS_IOC_TREE_SEARCH: |
| 5200 | 5293 | return btrfs_ioctl_tree_search(file, argp); |
| 5294 | + case BTRFS_IOC_TREE_SEARCH_V2: | |
| 5295 | + return btrfs_ioctl_tree_search_v2(file, argp); | |
| 5201 | 5296 | case BTRFS_IOC_INO_LOOKUP: |
| 5202 | 5297 | return btrfs_ioctl_ino_lookup(file, argp); |
| 5203 | 5298 | case BTRFS_IOC_INO_PATHS: |
| @@ -1798,8 +1798,10 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans, · 1797 unmodified lines | ||
| 1798 | 1798 | return -ENOMEM; |
| 1799 | 1799 | |
| 1800 | 1800 | tmp = ulist_alloc(GFP_NOFS); |
| 1801 | − if (!tmp) | |
| 1801 | + if (!tmp) { | |
| 1802 | + ulist_free(qgroups); | |
| 1802 | 1803 | return -ENOMEM; |
| 1804 | + } | |
| 1803 | 1805 | |
| 1804 | 1806 | btrfs_get_tree_mod_seq(fs_info, &elem); |
| 1805 | 1807 | ret = btrfs_find_all_roots(trans, fs_info, oper->bytenr, elem.seq, |
| @@ -428,8 +428,13 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, · 427 unmodified lines | ||
| 428 | 428 | continue; |
| 429 | 429 | } |
| 430 | 430 | if (!dev->bdev) { |
| 431 | − /* cannot read ahead on missing device */ | |
| 432 | − continue; | |
| 431 | + /* | |
| 432 | + * cannot read ahead on missing device, but for RAID5/6, | |
| 433 | + * REQ_GET_READ_MIRRORS return 1. So don't skip missing | |
| 434 | + * device for such case. | |
| 435 | + */ | |
| 436 | + if (nzones > 1) | |
| 437 | + continue; | |
| 433 | 438 | } |
| 434 | 439 | if (dev_replace_is_ongoing && |
| 435 | 440 | dev == fs_info->dev_replace.tgtdev) { |
| @@ -135,7 +135,7 @@ restart: · 134 unmodified lines | ||
| 135 | 135 | radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { |
| 136 | 136 | struct extent_buffer *eb; |
| 137 | 137 | |
| 138 | − eb = radix_tree_deref_slot(slot); | |
| 138 | + eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); | |
| 139 | 139 | if (!eb) |
| 140 | 140 | continue; |
| 141 | 141 | /* Shouldn't happen but that kind of thinking creates CVE's */ |
| @@ -415,6 +415,8 @@ int btrfs_test_qgroups(void) · 414 unmodified lines | ||
| 415 | 415 | ret = -ENOMEM; |
| 416 | 416 | goto out; |
| 417 | 417 | } |
| 418 | + btrfs_set_header_level(root->node, 0); | |
| 419 | + btrfs_set_header_nritems(root->node, 0); | |
| 418 | 420 | root->alloc_bytenr += 8192; |
| 419 | 421 | |
| 420 | 422 | tmp_root = btrfs_alloc_dummy_root(); |
| @@ -1284,11 +1284,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, · 1283 unmodified lines | ||
| 1284 | 1284 | goto fail; |
| 1285 | 1285 | } |
| 1286 | 1286 | |
| 1287 | − pending->error = btrfs_qgroup_inherit(trans, fs_info, | |
| 1288 | − root->root_key.objectid, | |
| 1289 | − objectid, pending->inherit); | |
| 1290 | − if (pending->error) | |
| 1291 | − goto no_free_objectid; | |
| 1287 | + ret = btrfs_qgroup_inherit(trans, fs_info, | |
| 1288 | + root->root_key.objectid, | |
| 1289 | + objectid, pending->inherit); | |
| 1290 | + if (ret) { | |
| 1291 | + btrfs_abort_transaction(trans, root, ret); | |
| 1292 | + goto fail; | |
| 1293 | + } | |
| 1292 | 1294 | |
| 1293 | 1295 | /* see comments in should_cow_block() */ |
| 1294 | 1296 | set_bit(BTRFS_ROOT_FORCE_COW, &root->state); |
| @@ -306,6 +306,14 @@ struct btrfs_ioctl_search_args { · 305 unmodified lines | ||
| 306 | 306 | char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; |
| 307 | 307 | }; |
| 308 | 308 | |
| 309 | +struct btrfs_ioctl_search_args_v2 { | |
| 310 | + struct btrfs_ioctl_search_key key; /* in/out - search parameters */ | |
| 311 | + __u64 buf_size; /* in - size of buffer | |
| 312 | + * out - on EOVERFLOW: needed size | |
| 313 | + * to store item */ | |
| 314 | + __u64 buf[0]; /* out - found items */ | |
| 315 | +}; | |
| 316 | + | |
| 309 | 317 | struct btrfs_ioctl_clone_range_args { |
| 310 | 318 | __s64 src_fd; |
| 311 | 319 | __u64 src_offset, src_length; |
| @@ -558,6 +566,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) · 246 unmodified lines | ||
| 558 | 566 | struct btrfs_ioctl_defrag_range_args) |
| 559 | 567 | #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ |
| 560 | 568 | struct btrfs_ioctl_search_args) |
| 569 | +#define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \ | |
| 570 | + struct btrfs_ioctl_search_args_v2) | |
| 561 | 571 | #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ |
| 562 | 572 | struct btrfs_ioctl_ino_lookup_args) |
| 563 | 573 | #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) |