Skip to content

Commit 16d52ef

Browse files
committed
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
2 parents a311c48 + 47a306a commit 16d52ef

File tree

9 files changed

+192
-36
lines changed

9 files changed

+192
-36
lines changed

fs/btrfs/extent_io.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,7 +2354,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
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,
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
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

Lines changed: 121 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root,
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,
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,
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 @@ static noinline int copy_to_sk(struct btrfs_root *root,
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,
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 @@ static noinline int search_ioctl(struct inode *inode,
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
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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1798,8 +1798,10 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans,
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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,13 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ int btrfs_test_qgroups(void)
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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,11 +1284,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ struct btrfs_ioctl_search_args {
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)
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)

0 commit comments

Comments
 (0)