diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-28 18:31:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-28 18:31:05 -0400 |
commit | 212a17ab878305600e607f637d2d8a49d9f7ef25 (patch) | |
tree | 64ad97fcc3d5c49ebd735f5508643c798aeecddf /fs/btrfs/ioctl.c | |
parent | baaca1a61497d97cec595fedce03b0a23b983e64 (diff) | |
parent | d9d04879321af570ea7285c6dad92d9c3cd108a1 (diff) |
Merge branch 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (45 commits)
Btrfs: fix __btrfs_map_block on 32 bit machines
btrfs: fix possible deadlock by clearing __GFP_FS flag
btrfs: check link counter overflow in link(2)
btrfs: don't mess with i_nlink of unlocked inode in rename()
Btrfs: check return value of btrfs_alloc_path()
Btrfs: fix OOPS of empty filesystem after balance
Btrfs: fix memory leak of empty filesystem after balance
Btrfs: fix return value of setflags ioctl
Btrfs: fix uncheck memory allocations
btrfs: make inode ref log recovery faster
Btrfs: add btrfs_trim_fs() to handle FITRIM
Btrfs: adjust btrfs_discard_extent() return errors and trimmed bytes
Btrfs: make btrfs_map_block() return entire free extent for each device of RAID0/1/10/DUP
Btrfs: make update_reserved_bytes() public
btrfs: return EXDEV when linking from different subvolumes
Btrfs: Per file/directory controls for COW and compression
Btrfs: add datacow flag in inode flag
btrfs: use GFP_NOFS instead of GFP_KERNEL
Btrfs: check return value of read_tree_block()
btrfs: properly access unaligned checksum buffer
...
Fix up trivial conflicts in fs/btrfs/volumes.c due to plug removal in
the block layer.
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d1bace3df9b6..7c07fe26b7cf 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,10 +172,9 @@ 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 (!inode_owner_or_capable(inode)) | 179 | if (!inode_owner_or_capable(inode)) |
162 | return -EACCES; | 180 | return -EACCES; |
@@ -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, |
@@ -409,7 +488,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
409 | if (ret) | 488 | if (ret) |
410 | goto fail; | 489 | goto fail; |
411 | 490 | ||
412 | btrfs_orphan_cleanup(pending_snapshot->snap); | 491 | ret = btrfs_orphan_cleanup(pending_snapshot->snap); |
492 | if (ret) | ||
493 | goto fail; | ||
413 | 494 | ||
414 | parent = dget_parent(dentry); | 495 | parent = dget_parent(dentry); |
415 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); | 496 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); |
@@ -2348,12 +2429,15 @@ 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; | 2429 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; |
2349 | struct btrfs_trans_handle *trans; | 2430 | struct btrfs_trans_handle *trans; |
2350 | u64 transid; | 2431 | u64 transid; |
2432 | int ret; | ||
2351 | 2433 | ||
2352 | trans = btrfs_start_transaction(root, 0); | 2434 | trans = btrfs_start_transaction(root, 0); |
2353 | if (IS_ERR(trans)) | 2435 | if (IS_ERR(trans)) |
2354 | return PTR_ERR(trans); | 2436 | return PTR_ERR(trans); |
2355 | transid = trans->transid; | 2437 | transid = trans->transid; |
2356 | btrfs_commit_transaction_async(trans, root, 0); | 2438 | ret = btrfs_commit_transaction_async(trans, root, 0); |
2439 | if (ret) | ||
2440 | return ret; | ||
2357 | 2441 | ||
2358 | if (argp) | 2442 | if (argp) |
2359 | if (copy_to_user(argp, &transid, sizeof(transid))) | 2443 | if (copy_to_user(argp, &transid, sizeof(transid))) |
@@ -2388,6 +2472,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2388 | return btrfs_ioctl_setflags(file, argp); | 2472 | return btrfs_ioctl_setflags(file, argp); |
2389 | case FS_IOC_GETVERSION: | 2473 | case FS_IOC_GETVERSION: |
2390 | return btrfs_ioctl_getversion(file, argp); | 2474 | return btrfs_ioctl_getversion(file, argp); |
2475 | case FITRIM: | ||
2476 | return btrfs_ioctl_fitrim(file, argp); | ||
2391 | case BTRFS_IOC_SNAP_CREATE: | 2477 | case BTRFS_IOC_SNAP_CREATE: |
2392 | return btrfs_ioctl_snap_create(file, argp, 0); | 2478 | return btrfs_ioctl_snap_create(file, argp, 0); |
2393 | case BTRFS_IOC_SNAP_CREATE_V2: | 2479 | case BTRFS_IOC_SNAP_CREATE_V2: |