History

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

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

Linus Torvalds committed 12 years ago

Commit 16d52ef2 parents a311c48 47a306a9 files · +192 −36Browse files

Unified · Split

9 files
  1. fs/btrfs/extent_io.c +38 −1
  2. fs/btrfs/extent_io.h +3 −0
  3. fs/btrfs/ioctl.c +121 −26
  4. fs/btrfs/qgroup.c +3 −1
  5. fs/btrfs/reada.c +7 −2
  6. fs/btrfs/tests/btrfs-tests.c +1 −1
  7. fs/btrfs/tests/qgroup-tests.c +2 −0
  8. fs/btrfs/transaction.c +7 −5
  9. include/uapi/linux/btrfs.h +10 −0
fs/btrfs/extent_io.c+38−1
@@ -2354,7 +2354,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) · 2353 unmodified lines
23542354 {
23552355 int uptodate = (err == 0);
23562356 struct extent_io_tree *tree;
2357− int ret;
2357+ int ret = 0;
23582358
23592359 tree = &BTRFS_I(page->mapping->host)->io_tree;
23602360
@@ -5068,6 +5068,43 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, · 2707 unmodified lines
50685068 }
50695069 }
50705070
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+
50715108 int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
50725109 unsigned long min_len, char **map,
50735110 unsigned long *map_start,
fs/btrfs/extent_io.h+3−0
@@ -304,6 +304,9 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, · 303 unmodified lines
304304 void read_extent_buffer(struct extent_buffer *eb, void *dst,
305305 unsigned long start,
306306 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);
307310 void write_extent_buffer(struct extent_buffer *eb, const void *src,
308311 unsigned long start, unsigned long len);
309312 void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
fs/btrfs/ioctl.c+121−26
@@ -1957,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 1956 unmodified lines
19571957 struct btrfs_path *path,
19581958 struct btrfs_key *key,
19591959 struct btrfs_ioctl_search_key *sk,
1960− char *buf,
1960+ size_t *buf_size,
1961+ char __user *ubuf,
19611962 unsigned long *sk_offset,
19621963 int *num_found)
19631964 {
@@ -1989,13 +1990,25 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 25 unmodified lines
19891990 if (!key_in_sk(key, sk))
19901991 continue;
19911992
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;
19932005 item_len = 0;
2006+ ret = -EOVERFLOW;
2007+ }
19942008
1995− if (sizeof(sh) + item_len + *sk_offset >
1996− BTRFS_SEARCH_ARGS_BUFSIZE) {
2009+ if (sizeof(sh) + item_len + *sk_offset > *buf_size) {
19972010 ret = 1;
1998− goto overflow;
2011+ goto out;
19992012 }
20002013
20012014 sh.objectid = key->objectid;
@@ -2005,20 +2018,33 @@ static noinline int copy_to_sk(struct btrfs_root *root, · 3 unmodified lines
20052018 sh.transid = found_transid;
20062019
20072020 /* 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+
20092026 *sk_offset += sizeof(sh);
20102027
20112028 if (item_len) {
2012− char *p = buf + *sk_offset;
2029+ char __user *up = ubuf + *sk_offset;
20132030 /* 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+
20162037 *sk_offset += item_len;
20172038 }
20182039 (*num_found)++;
20192040
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+ }
20222048 }
20232049 advance_key:
20242050 ret = 0;
@@ -2033,22 +2059,37 @@ advance_key: · 8 unmodified lines
20332059 key->objectid++;
20342060 } else
20352061 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+ */
20372072 return ret;
20382073 }
20392074
20402075 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)
20422079 {
20432080 struct btrfs_root *root;
20442081 struct btrfs_key key;
20452082 struct btrfs_path *path;
2046− struct btrfs_ioctl_search_key *sk = &args->key;
20472083 struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
20482084 int ret;
20492085 int num_found = 0;
20502086 unsigned long sk_offset = 0;
20512087
2088+ if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) {
2089+ *buf_size = sizeof(struct btrfs_ioctl_search_header);
2090+ return -EOVERFLOW;
2091+ }
2092+
20522093 path = btrfs_alloc_path();
20532094 if (!path)
20542095 return -ENOMEM;
@@ -2082,14 +2123,15 @@ static noinline int search_ioctl(struct inode *inode, · 27 unmodified lines
20822123 ret = 0;
20832124 goto err;
20842125 }
2085− ret = copy_to_sk(root, path, &key, sk, args->buf,
2126+ ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf,
20862127 &sk_offset, &num_found);
20872128 btrfs_release_path(path);
2088− if (ret || num_found >= sk->nr_items)
2129+ if (ret)
20892130 break;
20902131
20912132 }
2092− ret = 0;
2133+ if (ret > 0)
2134+ ret = 0;
20932135 err:
20942136 sk->nr_items = num_found;
20952137 btrfs_free_path(path);
@@ -2099,22 +2141,73 @@ err: · 3 unmodified lines
20992141 static noinline int btrfs_ioctl_tree_search(struct file *file,
21002142 void __user *argp)
21012143 {
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;
21052149
21062150 if (!capable(CAP_SYS_ADMIN))
21072151 return -EPERM;
21082152
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);
21122159
21132160 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)))
21162171 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+
21182211 return ret;
21192212 }
21202213
@@ -5198,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int · 3077 unmodified lines
51985291 return btrfs_ioctl_trans_end(file);
51995292 case BTRFS_IOC_TREE_SEARCH:
52005293 return btrfs_ioctl_tree_search(file, argp);
5294+ case BTRFS_IOC_TREE_SEARCH_V2:
5295+ return btrfs_ioctl_tree_search_v2(file, argp);
52015296 case BTRFS_IOC_INO_LOOKUP:
52025297 return btrfs_ioctl_ino_lookup(file, argp);
52035298 case BTRFS_IOC_INO_PATHS:
fs/btrfs/qgroup.c+3−1
@@ -1798,8 +1798,10 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans, · 1797 unmodified lines
17981798 return -ENOMEM;
17991799
18001800 tmp = ulist_alloc(GFP_NOFS);
1801− if (!tmp)
1801+ if (!tmp) {
1802+ ulist_free(qgroups);
18021803 return -ENOMEM;
1804+ }
18031805
18041806 btrfs_get_tree_mod_seq(fs_info, &elem);
18051807 ret = btrfs_find_all_roots(trans, fs_info, oper->bytenr, elem.seq,
fs/btrfs/reada.c+7−2
@@ -428,8 +428,13 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, · 427 unmodified lines
428428 continue;
429429 }
430430 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;
433438 }
434439 if (dev_replace_is_ongoing &&
435440 dev == fs_info->dev_replace.tgtdev) {
fs/btrfs/tests/btrfs-tests.c+1−1
@@ -135,7 +135,7 @@ restart: · 134 unmodified lines
135135 radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
136136 struct extent_buffer *eb;
137137
138− eb = radix_tree_deref_slot(slot);
138+ eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
139139 if (!eb)
140140 continue;
141141 /* Shouldn't happen but that kind of thinking creates CVE's */
fs/btrfs/tests/qgroup-tests.c+2−0
@@ -415,6 +415,8 @@ int btrfs_test_qgroups(void) · 414 unmodified lines
415415 ret = -ENOMEM;
416416 goto out;
417417 }
418+ btrfs_set_header_level(root->node, 0);
419+ btrfs_set_header_nritems(root->node, 0);
418420 root->alloc_bytenr += 8192;
419421
420422 tmp_root = btrfs_alloc_dummy_root();
fs/btrfs/transaction.c+7−5
@@ -1284,11 +1284,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, · 1283 unmodified lines
12841284 goto fail;
12851285 }
12861286
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+ }
12921294
12931295 /* see comments in should_cow_block() */
12941296 set_bit(BTRFS_ROOT_FORCE_COW, &root->state);
include/uapi/linux/btrfs.h+10−0
@@ -306,6 +306,14 @@ struct btrfs_ioctl_search_args { · 305 unmodified lines
306306 char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
307307 };
308308
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+
309317 struct btrfs_ioctl_clone_range_args {
310318 __s64 src_fd;
311319 __u64 src_offset, src_length;
@@ -558,6 +566,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) · 246 unmodified lines
558566 struct btrfs_ioctl_defrag_range_args)
559567 #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
560568 struct btrfs_ioctl_search_args)
569+#define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \
570+ struct btrfs_ioctl_search_args_v2)
561571 #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
562572 struct btrfs_ioctl_ino_lookup_args)
563573 #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64)