aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-14 20:48:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-14 20:48:43 -0400
commit16d52ef7c026f925893a1c0fc46516349928f319 (patch)
tree1cb9bf5406e22bb3f4fb37d9e6d4e926304dfe04 /fs/btrfs/ioctl.c
parenta311c480384c5aa9aaae195b89c3ec89c3b66379 (diff)
parent47a306a74842248dcd537b85f9a36c7b156c59a9 (diff)
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
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c147
1 files changed, 121 insertions, 26 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 82c18ba12e3f..0d321c23069a 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1957,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root,
1957 struct btrfs_path *path, 1957 struct btrfs_path *path,
1958 struct btrfs_key *key, 1958 struct btrfs_key *key,
1959 struct btrfs_ioctl_search_key *sk, 1959 struct btrfs_ioctl_search_key *sk,
1960 char *buf, 1960 size_t *buf_size,
1961 char __user *ubuf,
1961 unsigned long *sk_offset, 1962 unsigned long *sk_offset,
1962 int *num_found) 1963 int *num_found)
1963{ 1964{
@@ -1989,13 +1990,25 @@ static noinline int copy_to_sk(struct btrfs_root *root,
1989 if (!key_in_sk(key, sk)) 1990 if (!key_in_sk(key, sk))
1990 continue; 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 item_len = 0; 2005 item_len = 0;
2006 ret = -EOVERFLOW;
2007 }
1994 2008
1995 if (sizeof(sh) + item_len + *sk_offset > 2009 if (sizeof(sh) + item_len + *sk_offset > *buf_size) {
1996 BTRFS_SEARCH_ARGS_BUFSIZE) {
1997 ret = 1; 2010 ret = 1;
1998 goto overflow; 2011 goto out;
1999 } 2012 }
2000 2013
2001 sh.objectid = key->objectid; 2014 sh.objectid = key->objectid;
@@ -2005,20 +2018,33 @@ static noinline int copy_to_sk(struct btrfs_root *root,
2005 sh.transid = found_transid; 2018 sh.transid = found_transid;
2006 2019
2007 /* copy search result header */ 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 *sk_offset += sizeof(sh); 2026 *sk_offset += sizeof(sh);
2010 2027
2011 if (item_len) { 2028 if (item_len) {
2012 char *p = buf + *sk_offset; 2029 char __user *up = ubuf + *sk_offset;
2013 /* copy the item */ 2030 /* copy the item */
2014 read_extent_buffer(leaf, p, 2031 if (read_extent_buffer_to_user(leaf, up,
2015 item_off, item_len); 2032 item_off, item_len)) {
2033 ret = -EFAULT;
2034 goto out;
2035 }
2036
2016 *sk_offset += item_len; 2037 *sk_offset += item_len;
2017 } 2038 }
2018 (*num_found)++; 2039 (*num_found)++;
2019 2040
2020 if (*num_found >= sk->nr_items) 2041 if (ret) /* -EOVERFLOW from above */
2021 break; 2042 goto out;
2043
2044 if (*num_found >= sk->nr_items) {
2045 ret = 1;
2046 goto out;
2047 }
2022 } 2048 }
2023advance_key: 2049advance_key:
2024 ret = 0; 2050 ret = 0;
@@ -2033,22 +2059,37 @@ advance_key:
2033 key->objectid++; 2059 key->objectid++;
2034 } else 2060 } else
2035 ret = 1; 2061 ret = 1;
2036overflow: 2062out:
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 return ret; 2072 return ret;
2038} 2073}
2039 2074
2040static noinline int search_ioctl(struct inode *inode, 2075static 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 struct btrfs_root *root; 2080 struct btrfs_root *root;
2044 struct btrfs_key key; 2081 struct btrfs_key key;
2045 struct btrfs_path *path; 2082 struct btrfs_path *path;
2046 struct btrfs_ioctl_search_key *sk = &args->key;
2047 struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info; 2083 struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
2048 int ret; 2084 int ret;
2049 int num_found = 0; 2085 int num_found = 0;
2050 unsigned long sk_offset = 0; 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 path = btrfs_alloc_path(); 2093 path = btrfs_alloc_path();
2053 if (!path) 2094 if (!path)
2054 return -ENOMEM; 2095 return -ENOMEM;
@@ -2082,14 +2123,15 @@ static noinline int search_ioctl(struct inode *inode,
2082 ret = 0; 2123 ret = 0;
2083 goto err; 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 &sk_offset, &num_found); 2127 &sk_offset, &num_found);
2087 btrfs_release_path(path); 2128 btrfs_release_path(path);
2088 if (ret || num_found >= sk->nr_items) 2129 if (ret)
2089 break; 2130 break;
2090 2131
2091 } 2132 }
2092 ret = 0; 2133 if (ret > 0)
2134 ret = 0;
2093err: 2135err:
2094 sk->nr_items = num_found; 2136 sk->nr_items = num_found;
2095 btrfs_free_path(path); 2137 btrfs_free_path(path);
@@ -2099,22 +2141,73 @@ err:
2099static noinline int btrfs_ioctl_tree_search(struct file *file, 2141static noinline int btrfs_ioctl_tree_search(struct file *file,
2100 void __user *argp) 2142 void __user *argp)
2101{ 2143{
2102 struct btrfs_ioctl_search_args *args; 2144 struct btrfs_ioctl_search_args __user *uargs;
2103 struct inode *inode; 2145 struct btrfs_ioctl_search_key sk;
2104 int ret; 2146 struct inode *inode;
2147 int ret;
2148 size_t buf_size;
2105 2149
2106 if (!capable(CAP_SYS_ADMIN)) 2150 if (!capable(CAP_SYS_ADMIN))
2107 return -EPERM; 2151 return -EPERM;
2108 2152
2109 args = memdup_user(argp, sizeof(*args)); 2153 uargs = (struct btrfs_ioctl_search_args __user *)argp;
2110 if (IS_ERR(args)) 2154
2111 return PTR_ERR(args); 2155 if (copy_from_user(&sk, &uargs->key, sizeof(sk)))
2156 return -EFAULT;
2157
2158 buf_size = sizeof(uargs->buf);
2112 2159
2113 inode = file_inode(file); 2160 inode = file_inode(file);
2114 ret = search_ioctl(inode, args); 2161 ret = search_ioctl(inode, &sk, &buf_size, uargs->buf);
2115 if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) 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 ret = -EFAULT; 2171 ret = -EFAULT;
2117 kfree(args); 2172 return ret;
2173}
2174
2175static 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 return ret; 2211 return ret;
2119} 2212}
2120 2213
@@ -5198,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int
5198 return btrfs_ioctl_trans_end(file); 5291 return btrfs_ioctl_trans_end(file);
5199 case BTRFS_IOC_TREE_SEARCH: 5292 case BTRFS_IOC_TREE_SEARCH:
5200 return btrfs_ioctl_tree_search(file, argp); 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 case BTRFS_IOC_INO_LOOKUP: 5296 case BTRFS_IOC_INO_LOOKUP:
5202 return btrfs_ioctl_ino_lookup(file, argp); 5297 return btrfs_ioctl_ino_lookup(file, argp);
5203 case BTRFS_IOC_INO_PATHS: 5298 case BTRFS_IOC_INO_PATHS: