diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 112 |
1 files changed, 102 insertions, 10 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5fdb2abc4fa7..ffb48d6c5433 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/xattr.h> | 40 | #include <linux/xattr.h> |
41 | #include <linux/vmalloc.h> | 41 | #include <linux/vmalloc.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/blkdev.h> | ||
43 | #include "compat.h" | 44 | #include "compat.h" |
44 | #include "ctree.h" | 45 | #include "ctree.h" |
45 | #include "disk-io.h" | 46 | #include "disk-io.h" |
@@ -138,6 +139,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) | |||
138 | return 0; | 139 | return 0; |
139 | } | 140 | } |
140 | 141 | ||
142 | static int check_flags(unsigned int flags) | ||
143 | { | ||
144 | if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ | ||
145 | FS_NOATIME_FL | FS_NODUMP_FL | \ | ||
146 | FS_SYNC_FL | FS_DIRSYNC_FL | \ | ||
147 | FS_NOCOMP_FL | FS_COMPR_FL | \ | ||
148 | FS_NOCOW_FL | FS_COW_FL)) | ||
149 | return -EOPNOTSUPP; | ||
150 | |||
151 | if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) | ||
152 | return -EINVAL; | ||
153 | |||
154 | if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
141 | static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | 160 | static int btrfs_ioctl_setflags(struct file *file, void __user *arg) |
142 | { | 161 | { |
143 | struct inode *inode = file->f_path.dentry->d_inode; | 162 | struct inode *inode = file->f_path.dentry->d_inode; |
@@ -153,12 +172,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
153 | if (copy_from_user(&flags, arg, sizeof(flags))) | 172 | if (copy_from_user(&flags, arg, sizeof(flags))) |
154 | return -EFAULT; | 173 | return -EFAULT; |
155 | 174 | ||
156 | if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ | 175 | ret = check_flags(flags); |
157 | FS_NOATIME_FL | FS_NODUMP_FL | \ | 176 | if (ret) |
158 | FS_SYNC_FL | FS_DIRSYNC_FL)) | 177 | return ret; |
159 | return -EOPNOTSUPP; | ||
160 | 178 | ||
161 | if (!is_owner_or_cap(inode)) | 179 | if (!inode_owner_or_capable(inode)) |
162 | return -EACCES; | 180 | return -EACCES; |
163 | 181 | ||
164 | mutex_lock(&inode->i_mutex); | 182 | mutex_lock(&inode->i_mutex); |
@@ -201,6 +219,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
201 | else | 219 | else |
202 | ip->flags &= ~BTRFS_INODE_DIRSYNC; | 220 | ip->flags &= ~BTRFS_INODE_DIRSYNC; |
203 | 221 | ||
222 | /* | ||
223 | * The COMPRESS flag can only be changed by users, while the NOCOMPRESS | ||
224 | * flag may be changed automatically if compression code won't make | ||
225 | * things smaller. | ||
226 | */ | ||
227 | if (flags & FS_NOCOMP_FL) { | ||
228 | ip->flags &= ~BTRFS_INODE_COMPRESS; | ||
229 | ip->flags |= BTRFS_INODE_NOCOMPRESS; | ||
230 | } else if (flags & FS_COMPR_FL) { | ||
231 | ip->flags |= BTRFS_INODE_COMPRESS; | ||
232 | ip->flags &= ~BTRFS_INODE_NOCOMPRESS; | ||
233 | } | ||
234 | if (flags & FS_NOCOW_FL) | ||
235 | ip->flags |= BTRFS_INODE_NODATACOW; | ||
236 | else if (flags & FS_COW_FL) | ||
237 | ip->flags &= ~BTRFS_INODE_NODATACOW; | ||
204 | 238 | ||
205 | trans = btrfs_join_transaction(root, 1); | 239 | trans = btrfs_join_transaction(root, 1); |
206 | BUG_ON(IS_ERR(trans)); | 240 | BUG_ON(IS_ERR(trans)); |
@@ -213,9 +247,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
213 | btrfs_end_transaction(trans, root); | 247 | btrfs_end_transaction(trans, root); |
214 | 248 | ||
215 | mnt_drop_write(file->f_path.mnt); | 249 | mnt_drop_write(file->f_path.mnt); |
250 | |||
251 | ret = 0; | ||
216 | out_unlock: | 252 | out_unlock: |
217 | mutex_unlock(&inode->i_mutex); | 253 | mutex_unlock(&inode->i_mutex); |
218 | return 0; | 254 | return ret; |
219 | } | 255 | } |
220 | 256 | ||
221 | static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | 257 | static int btrfs_ioctl_getversion(struct file *file, int __user *arg) |
@@ -225,6 +261,49 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | |||
225 | return put_user(inode->i_generation, arg); | 261 | return put_user(inode->i_generation, arg); |
226 | } | 262 | } |
227 | 263 | ||
264 | static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | ||
265 | { | ||
266 | struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info; | ||
267 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
268 | struct btrfs_device *device; | ||
269 | struct request_queue *q; | ||
270 | struct fstrim_range range; | ||
271 | u64 minlen = ULLONG_MAX; | ||
272 | u64 num_devices = 0; | ||
273 | int ret; | ||
274 | |||
275 | if (!capable(CAP_SYS_ADMIN)) | ||
276 | return -EPERM; | ||
277 | |||
278 | mutex_lock(&fs_info->fs_devices->device_list_mutex); | ||
279 | list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { | ||
280 | if (!device->bdev) | ||
281 | continue; | ||
282 | q = bdev_get_queue(device->bdev); | ||
283 | if (blk_queue_discard(q)) { | ||
284 | num_devices++; | ||
285 | minlen = min((u64)q->limits.discard_granularity, | ||
286 | minlen); | ||
287 | } | ||
288 | } | ||
289 | mutex_unlock(&fs_info->fs_devices->device_list_mutex); | ||
290 | if (!num_devices) | ||
291 | return -EOPNOTSUPP; | ||
292 | |||
293 | if (copy_from_user(&range, arg, sizeof(range))) | ||
294 | return -EFAULT; | ||
295 | |||
296 | range.minlen = max(range.minlen, minlen); | ||
297 | ret = btrfs_trim_fs(root, &range); | ||
298 | if (ret < 0) | ||
299 | return ret; | ||
300 | |||
301 | if (copy_to_user(arg, &range, sizeof(range))) | ||
302 | return -EFAULT; | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
228 | static noinline int create_subvol(struct btrfs_root *root, | 307 | static noinline int create_subvol(struct btrfs_root *root, |
229 | struct dentry *dentry, | 308 | struct dentry *dentry, |
230 | char *name, int namelen, | 309 | char *name, int namelen, |
@@ -294,6 +373,10 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
294 | inode_item->nbytes = cpu_to_le64(root->leafsize); | 373 | inode_item->nbytes = cpu_to_le64(root->leafsize); |
295 | inode_item->mode = cpu_to_le32(S_IFDIR | 0755); | 374 | inode_item->mode = cpu_to_le32(S_IFDIR | 0755); |
296 | 375 | ||
376 | root_item.flags = 0; | ||
377 | root_item.byte_limit = 0; | ||
378 | inode_item->flags = cpu_to_le64(BTRFS_INODE_ROOT_ITEM_INIT); | ||
379 | |||
297 | btrfs_set_root_bytenr(&root_item, leaf->start); | 380 | btrfs_set_root_bytenr(&root_item, leaf->start); |
298 | btrfs_set_root_generation(&root_item, trans->transid); | 381 | btrfs_set_root_generation(&root_item, trans->transid); |
299 | btrfs_set_root_level(&root_item, 0); | 382 | btrfs_set_root_level(&root_item, 0); |
@@ -409,7 +492,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
409 | if (ret) | 492 | if (ret) |
410 | goto fail; | 493 | goto fail; |
411 | 494 | ||
412 | btrfs_orphan_cleanup(pending_snapshot->snap); | 495 | ret = btrfs_orphan_cleanup(pending_snapshot->snap); |
496 | if (ret) | ||
497 | goto fail; | ||
413 | 498 | ||
414 | parent = dget_parent(dentry); | 499 | parent = dget_parent(dentry); |
415 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); | 500 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); |
@@ -1077,7 +1162,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
1077 | if (flags & ~BTRFS_SUBVOL_RDONLY) | 1162 | if (flags & ~BTRFS_SUBVOL_RDONLY) |
1078 | return -EOPNOTSUPP; | 1163 | return -EOPNOTSUPP; |
1079 | 1164 | ||
1080 | if (!is_owner_or_cap(inode)) | 1165 | if (!inode_owner_or_capable(inode)) |
1081 | return -EACCES; | 1166 | return -EACCES; |
1082 | 1167 | ||
1083 | down_write(&root->fs_info->subvol_sem); | 1168 | down_write(&root->fs_info->subvol_sem); |
@@ -2202,7 +2287,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
2202 | struct btrfs_ioctl_space_info space; | 2287 | struct btrfs_ioctl_space_info space; |
2203 | struct btrfs_ioctl_space_info *dest; | 2288 | struct btrfs_ioctl_space_info *dest; |
2204 | struct btrfs_ioctl_space_info *dest_orig; | 2289 | struct btrfs_ioctl_space_info *dest_orig; |
2205 | struct btrfs_ioctl_space_info *user_dest; | 2290 | struct btrfs_ioctl_space_info __user *user_dest; |
2206 | struct btrfs_space_info *info; | 2291 | struct btrfs_space_info *info; |
2207 | u64 types[] = {BTRFS_BLOCK_GROUP_DATA, | 2292 | u64 types[] = {BTRFS_BLOCK_GROUP_DATA, |
2208 | BTRFS_BLOCK_GROUP_SYSTEM, | 2293 | BTRFS_BLOCK_GROUP_SYSTEM, |
@@ -2348,12 +2433,17 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp | |||
2348 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | 2433 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; |
2349 | struct btrfs_trans_handle *trans; | 2434 | struct btrfs_trans_handle *trans; |
2350 | u64 transid; | 2435 | u64 transid; |
2436 | int ret; | ||
2351 | 2437 | ||
2352 | trans = btrfs_start_transaction(root, 0); | 2438 | trans = btrfs_start_transaction(root, 0); |
2353 | if (IS_ERR(trans)) | 2439 | if (IS_ERR(trans)) |
2354 | return PTR_ERR(trans); | 2440 | return PTR_ERR(trans); |
2355 | transid = trans->transid; | 2441 | transid = trans->transid; |
2356 | btrfs_commit_transaction_async(trans, root, 0); | 2442 | ret = btrfs_commit_transaction_async(trans, root, 0); |
2443 | if (ret) { | ||
2444 | btrfs_end_transaction(trans, root); | ||
2445 | return ret; | ||
2446 | } | ||
2357 | 2447 | ||
2358 | if (argp) | 2448 | if (argp) |
2359 | if (copy_to_user(argp, &transid, sizeof(transid))) | 2449 | if (copy_to_user(argp, &transid, sizeof(transid))) |
@@ -2388,6 +2478,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2388 | return btrfs_ioctl_setflags(file, argp); | 2478 | return btrfs_ioctl_setflags(file, argp); |
2389 | case FS_IOC_GETVERSION: | 2479 | case FS_IOC_GETVERSION: |
2390 | return btrfs_ioctl_getversion(file, argp); | 2480 | return btrfs_ioctl_getversion(file, argp); |
2481 | case FITRIM: | ||
2482 | return btrfs_ioctl_fitrim(file, argp); | ||
2391 | case BTRFS_IOC_SNAP_CREATE: | 2483 | case BTRFS_IOC_SNAP_CREATE: |
2392 | return btrfs_ioctl_snap_create(file, argp, 0); | 2484 | return btrfs_ioctl_snap_create(file, argp, 0); |
2393 | case BTRFS_IOC_SNAP_CREATE_V2: | 2485 | case BTRFS_IOC_SNAP_CREATE_V2: |