diff options
Diffstat (limited to 'fs/ioctl.c')
-rw-r--r-- | fs/ioctl.c | 92 |
1 files changed, 81 insertions, 11 deletions
diff --git a/fs/ioctl.c b/fs/ioctl.c index 43e8b2c0664b..240ec63984cb 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -231,7 +231,8 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
231 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | 231 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) |
232 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | 232 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); |
233 | 233 | ||
234 | /* | 234 | /** |
235 | * __generic_block_fiemap - FIEMAP for block based inodes (no locking) | ||
235 | * @inode - the inode to map | 236 | * @inode - the inode to map |
236 | * @arg - the pointer to userspace where we copy everything to | 237 | * @arg - the pointer to userspace where we copy everything to |
237 | * @get_block - the fs's get_block function | 238 | * @get_block - the fs's get_block function |
@@ -242,11 +243,15 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
242 | * | 243 | * |
243 | * If it is possible to have data blocks beyond a hole past @inode->i_size, then | 244 | * If it is possible to have data blocks beyond a hole past @inode->i_size, then |
244 | * please do not use this function, it will stop at the first unmapped block | 245 | * please do not use this function, it will stop at the first unmapped block |
245 | * beyond i_size | 246 | * beyond i_size. |
247 | * | ||
248 | * If you use this function directly, you need to do your own locking. Use | ||
249 | * generic_block_fiemap if you want the locking done for you. | ||
246 | */ | 250 | */ |
247 | int generic_block_fiemap(struct inode *inode, | 251 | |
248 | struct fiemap_extent_info *fieinfo, u64 start, | 252 | int __generic_block_fiemap(struct inode *inode, |
249 | u64 len, get_block_t *get_block) | 253 | struct fiemap_extent_info *fieinfo, u64 start, |
254 | u64 len, get_block_t *get_block) | ||
250 | { | 255 | { |
251 | struct buffer_head tmp; | 256 | struct buffer_head tmp; |
252 | unsigned int start_blk; | 257 | unsigned int start_blk; |
@@ -260,9 +265,6 @@ int generic_block_fiemap(struct inode *inode, | |||
260 | 265 | ||
261 | start_blk = logical_to_blk(inode, start); | 266 | start_blk = logical_to_blk(inode, start); |
262 | 267 | ||
263 | /* guard against change */ | ||
264 | mutex_lock(&inode->i_mutex); | ||
265 | |||
266 | length = (long long)min_t(u64, len, i_size_read(inode)); | 268 | length = (long long)min_t(u64, len, i_size_read(inode)); |
267 | map_len = length; | 269 | map_len = length; |
268 | 270 | ||
@@ -334,14 +336,36 @@ int generic_block_fiemap(struct inode *inode, | |||
334 | cond_resched(); | 336 | cond_resched(); |
335 | } while (1); | 337 | } while (1); |
336 | 338 | ||
337 | mutex_unlock(&inode->i_mutex); | ||
338 | |||
339 | /* if ret is 1 then we just hit the end of the extent array */ | 339 | /* if ret is 1 then we just hit the end of the extent array */ |
340 | if (ret == 1) | 340 | if (ret == 1) |
341 | ret = 0; | 341 | ret = 0; |
342 | 342 | ||
343 | return ret; | 343 | return ret; |
344 | } | 344 | } |
345 | EXPORT_SYMBOL(__generic_block_fiemap); | ||
346 | |||
347 | /** | ||
348 | * generic_block_fiemap - FIEMAP for block based inodes | ||
349 | * @inode: The inode to map | ||
350 | * @fieinfo: The mapping information | ||
351 | * @start: The initial block to map | ||
352 | * @len: The length of the extect to attempt to map | ||
353 | * @get_block: The block mapping function for the fs | ||
354 | * | ||
355 | * Calls __generic_block_fiemap to map the inode, after taking | ||
356 | * the inode's mutex lock. | ||
357 | */ | ||
358 | |||
359 | int generic_block_fiemap(struct inode *inode, | ||
360 | struct fiemap_extent_info *fieinfo, u64 start, | ||
361 | u64 len, get_block_t *get_block) | ||
362 | { | ||
363 | int ret; | ||
364 | mutex_lock(&inode->i_mutex); | ||
365 | ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block); | ||
366 | mutex_unlock(&inode->i_mutex); | ||
367 | return ret; | ||
368 | } | ||
345 | EXPORT_SYMBOL(generic_block_fiemap); | 369 | EXPORT_SYMBOL(generic_block_fiemap); |
346 | 370 | ||
347 | #endif /* CONFIG_BLOCK */ | 371 | #endif /* CONFIG_BLOCK */ |
@@ -415,6 +439,43 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp, | |||
415 | return error; | 439 | return error; |
416 | } | 440 | } |
417 | 441 | ||
442 | static int ioctl_fsfreeze(struct file *filp) | ||
443 | { | ||
444 | struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; | ||
445 | |||
446 | if (!capable(CAP_SYS_ADMIN)) | ||
447 | return -EPERM; | ||
448 | |||
449 | /* If filesystem doesn't support freeze feature, return. */ | ||
450 | if (sb->s_op->freeze_fs == NULL) | ||
451 | return -EOPNOTSUPP; | ||
452 | |||
453 | /* If a blockdevice-backed filesystem isn't specified, return. */ | ||
454 | if (sb->s_bdev == NULL) | ||
455 | return -EINVAL; | ||
456 | |||
457 | /* Freeze */ | ||
458 | sb = freeze_bdev(sb->s_bdev); | ||
459 | if (IS_ERR(sb)) | ||
460 | return PTR_ERR(sb); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static int ioctl_fsthaw(struct file *filp) | ||
465 | { | ||
466 | struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; | ||
467 | |||
468 | if (!capable(CAP_SYS_ADMIN)) | ||
469 | return -EPERM; | ||
470 | |||
471 | /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ | ||
472 | if (sb->s_bdev == NULL) | ||
473 | return -EINVAL; | ||
474 | |||
475 | /* Thaw */ | ||
476 | return thaw_bdev(sb->s_bdev, sb); | ||
477 | } | ||
478 | |||
418 | /* | 479 | /* |
419 | * When you add any new common ioctls to the switches above and below | 480 | * When you add any new common ioctls to the switches above and below |
420 | * please update compat_sys_ioctl() too. | 481 | * please update compat_sys_ioctl() too. |
@@ -462,6 +523,15 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | |||
462 | } else | 523 | } else |
463 | error = -ENOTTY; | 524 | error = -ENOTTY; |
464 | break; | 525 | break; |
526 | |||
527 | case FIFREEZE: | ||
528 | error = ioctl_fsfreeze(filp); | ||
529 | break; | ||
530 | |||
531 | case FITHAW: | ||
532 | error = ioctl_fsthaw(filp); | ||
533 | break; | ||
534 | |||
465 | default: | 535 | default: |
466 | if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) | 536 | if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) |
467 | error = file_ioctl(filp, cmd, arg); | 537 | error = file_ioctl(filp, cmd, arg); |
@@ -472,7 +542,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | |||
472 | return error; | 542 | return error; |
473 | } | 543 | } |
474 | 544 | ||
475 | asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | 545 | SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) |
476 | { | 546 | { |
477 | struct file *filp; | 547 | struct file *filp; |
478 | int error = -EBADF; | 548 | int error = -EBADF; |