diff options
| -rw-r--r-- | fs/compat_ioctl.c | 48 | ||||
| -rw-r--r-- | fs/ioctl.c | 35 | ||||
| -rw-r--r-- | fs/open.c | 58 | ||||
| -rw-r--r-- | include/linux/falloc.h | 21 | ||||
| -rw-r--r-- | include/linux/fs.h | 6 |
5 files changed, 139 insertions, 29 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c135202c38b3..626c7483b4de 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/skbuff.h> | 31 | #include <linux/skbuff.h> |
| 32 | #include <linux/netlink.h> | 32 | #include <linux/netlink.h> |
| 33 | #include <linux/vt.h> | 33 | #include <linux/vt.h> |
| 34 | #include <linux/falloc.h> | ||
| 34 | #include <linux/fs.h> | 35 | #include <linux/fs.h> |
| 35 | #include <linux/file.h> | 36 | #include <linux/file.h> |
| 36 | #include <linux/ppp_defs.h> | 37 | #include <linux/ppp_defs.h> |
| @@ -1779,6 +1780,41 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
| 1779 | return sys_ioctl(fd, cmd, (unsigned long)tn); | 1780 | return sys_ioctl(fd, cmd, (unsigned long)tn); |
| 1780 | } | 1781 | } |
| 1781 | 1782 | ||
| 1783 | /* on ia32 l_start is on a 32-bit boundary */ | ||
| 1784 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
| 1785 | struct space_resv_32 { | ||
| 1786 | __s16 l_type; | ||
| 1787 | __s16 l_whence; | ||
| 1788 | __s64 l_start __attribute__((packed)); | ||
| 1789 | /* len == 0 means until end of file */ | ||
| 1790 | __s64 l_len __attribute__((packed)); | ||
| 1791 | __s32 l_sysid; | ||
| 1792 | __u32 l_pid; | ||
| 1793 | __s32 l_pad[4]; /* reserve area */ | ||
| 1794 | }; | ||
| 1795 | |||
| 1796 | #define FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32) | ||
| 1797 | #define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32) | ||
| 1798 | |||
| 1799 | /* just account for different alignment */ | ||
| 1800 | static int compat_ioctl_preallocate(struct file *file, unsigned long arg) | ||
| 1801 | { | ||
| 1802 | struct space_resv_32 __user *p32 = (void __user *)arg; | ||
| 1803 | struct space_resv __user *p = compat_alloc_user_space(sizeof(*p)); | ||
| 1804 | |||
| 1805 | if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) || | ||
| 1806 | copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) || | ||
| 1807 | copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) || | ||
| 1808 | copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) || | ||
| 1809 | copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) || | ||
| 1810 | copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) || | ||
| 1811 | copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32))) | ||
| 1812 | return -EFAULT; | ||
| 1813 | |||
| 1814 | return ioctl_preallocate(file, p); | ||
| 1815 | } | ||
| 1816 | #endif | ||
| 1817 | |||
| 1782 | 1818 | ||
| 1783 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, | 1819 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, |
| 1784 | unsigned long, struct file *); | 1820 | unsigned long, struct file *); |
| @@ -2756,6 +2792,18 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | |||
| 2756 | case FIOQSIZE: | 2792 | case FIOQSIZE: |
| 2757 | break; | 2793 | break; |
| 2758 | 2794 | ||
| 2795 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
| 2796 | case FS_IOC_RESVSP_32: | ||
| 2797 | case FS_IOC_RESVSP64_32: | ||
| 2798 | error = compat_ioctl_preallocate(filp, arg); | ||
| 2799 | goto out_fput; | ||
| 2800 | #else | ||
| 2801 | case FS_IOC_RESVSP: | ||
| 2802 | case FS_IOC_RESVSP64: | ||
| 2803 | error = ioctl_preallocate(filp, (void __user *)arg); | ||
| 2804 | goto out_fput; | ||
| 2805 | #endif | ||
| 2806 | |||
| 2759 | case FIBMAP: | 2807 | case FIBMAP: |
| 2760 | case FIGETBSZ: | 2808 | case FIGETBSZ: |
| 2761 | case FIONREAD: | 2809 | case FIONREAD: |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 001f8d3118f2..5612880fcbe7 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
| 16 | #include <linux/writeback.h> | 16 | #include <linux/writeback.h> |
| 17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
| 18 | #include <linux/falloc.h> | ||
| 18 | 19 | ||
| 19 | #include <asm/ioctls.h> | 20 | #include <asm/ioctls.h> |
| 20 | 21 | ||
| @@ -403,6 +404,37 @@ EXPORT_SYMBOL(generic_block_fiemap); | |||
| 403 | 404 | ||
| 404 | #endif /* CONFIG_BLOCK */ | 405 | #endif /* CONFIG_BLOCK */ |
| 405 | 406 | ||
| 407 | /* | ||
| 408 | * This provides compatibility with legacy XFS pre-allocation ioctls | ||
| 409 | * which predate the fallocate syscall. | ||
| 410 | * | ||
| 411 | * Only the l_start, l_len and l_whence fields of the 'struct space_resv' | ||
| 412 | * are used here, rest are ignored. | ||
| 413 | */ | ||
| 414 | int ioctl_preallocate(struct file *filp, void __user *argp) | ||
| 415 | { | ||
| 416 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 417 | struct space_resv sr; | ||
| 418 | |||
| 419 | if (copy_from_user(&sr, argp, sizeof(sr))) | ||
| 420 | return -EFAULT; | ||
| 421 | |||
| 422 | switch (sr.l_whence) { | ||
| 423 | case SEEK_SET: | ||
| 424 | break; | ||
| 425 | case SEEK_CUR: | ||
| 426 | sr.l_start += filp->f_pos; | ||
| 427 | break; | ||
| 428 | case SEEK_END: | ||
| 429 | sr.l_start += i_size_read(inode); | ||
| 430 | break; | ||
| 431 | default: | ||
| 432 | return -EINVAL; | ||
| 433 | } | ||
| 434 | |||
| 435 | return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); | ||
| 436 | } | ||
| 437 | |||
| 406 | static int file_ioctl(struct file *filp, unsigned int cmd, | 438 | static int file_ioctl(struct file *filp, unsigned int cmd, |
| 407 | unsigned long arg) | 439 | unsigned long arg) |
| 408 | { | 440 | { |
| @@ -414,6 +446,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd, | |||
| 414 | return ioctl_fibmap(filp, p); | 446 | return ioctl_fibmap(filp, p); |
| 415 | case FIONREAD: | 447 | case FIONREAD: |
| 416 | return put_user(i_size_read(inode) - filp->f_pos, p); | 448 | return put_user(i_size_read(inode) - filp->f_pos, p); |
| 449 | case FS_IOC_RESVSP: | ||
| 450 | case FS_IOC_RESVSP64: | ||
| 451 | return ioctl_preallocate(filp, p); | ||
| 417 | } | 452 | } |
| 418 | 453 | ||
| 419 | return vfs_ioctl(filp, cmd, arg); | 454 | return vfs_ioctl(filp, cmd, arg); |
| @@ -378,63 +378,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64); | |||
| 378 | #endif | 378 | #endif |
| 379 | #endif /* BITS_PER_LONG == 32 */ | 379 | #endif /* BITS_PER_LONG == 32 */ |
| 380 | 380 | ||
| 381 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | 381 | |
| 382 | int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | ||
| 382 | { | 383 | { |
| 383 | struct file *file; | 384 | struct inode *inode = file->f_path.dentry->d_inode; |
| 384 | struct inode *inode; | 385 | long ret; |
| 385 | long ret = -EINVAL; | ||
| 386 | 386 | ||
| 387 | if (offset < 0 || len <= 0) | 387 | if (offset < 0 || len <= 0) |
| 388 | goto out; | 388 | return -EINVAL; |
| 389 | 389 | ||
| 390 | /* Return error if mode is not supported */ | 390 | /* Return error if mode is not supported */ |
| 391 | ret = -EOPNOTSUPP; | ||
| 392 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) | 391 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) |
| 393 | goto out; | 392 | return -EOPNOTSUPP; |
| 394 | 393 | ||
| 395 | ret = -EBADF; | ||
| 396 | file = fget(fd); | ||
| 397 | if (!file) | ||
| 398 | goto out; | ||
| 399 | if (!(file->f_mode & FMODE_WRITE)) | 394 | if (!(file->f_mode & FMODE_WRITE)) |
| 400 | goto out_fput; | 395 | return -EBADF; |
| 401 | /* | 396 | /* |
| 402 | * Revalidate the write permissions, in case security policy has | 397 | * Revalidate the write permissions, in case security policy has |
| 403 | * changed since the files were opened. | 398 | * changed since the files were opened. |
| 404 | */ | 399 | */ |
| 405 | ret = security_file_permission(file, MAY_WRITE); | 400 | ret = security_file_permission(file, MAY_WRITE); |
| 406 | if (ret) | 401 | if (ret) |
| 407 | goto out_fput; | 402 | return ret; |
| 408 | 403 | ||
| 409 | inode = file->f_path.dentry->d_inode; | ||
| 410 | |||
| 411 | ret = -ESPIPE; | ||
| 412 | if (S_ISFIFO(inode->i_mode)) | 404 | if (S_ISFIFO(inode->i_mode)) |
| 413 | goto out_fput; | 405 | return -ESPIPE; |
| 414 | 406 | ||
| 415 | ret = -ENODEV; | ||
| 416 | /* | 407 | /* |
| 417 | * Let individual file system decide if it supports preallocation | 408 | * Let individual file system decide if it supports preallocation |
| 418 | * for directories or not. | 409 | * for directories or not. |
| 419 | */ | 410 | */ |
| 420 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) | 411 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
| 421 | goto out_fput; | 412 | return -ENODEV; |
| 422 | 413 | ||
| 423 | ret = -EFBIG; | ||
| 424 | /* Check for wrap through zero too */ | 414 | /* Check for wrap through zero too */ |
| 425 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) | 415 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) |
| 426 | goto out_fput; | 416 | return -EFBIG; |
| 427 | 417 | ||
| 428 | if (inode->i_op->fallocate) | 418 | if (!inode->i_op->fallocate) |
| 429 | ret = inode->i_op->fallocate(inode, mode, offset, len); | 419 | return -EOPNOTSUPP; |
| 430 | else | ||
| 431 | ret = -EOPNOTSUPP; | ||
| 432 | 420 | ||
| 433 | out_fput: | 421 | return inode->i_op->fallocate(inode, mode, offset, len); |
| 434 | fput(file); | ||
| 435 | out: | ||
| 436 | return ret; | ||
| 437 | } | 422 | } |
| 423 | |||
| 424 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | ||
| 425 | { | ||
| 426 | struct file *file; | ||
| 427 | int error = -EBADF; | ||
| 428 | |||
| 429 | file = fget(fd); | ||
| 430 | if (file) { | ||
| 431 | error = do_fallocate(file, mode, offset, len); | ||
| 432 | fput(file); | ||
| 433 | } | ||
| 434 | |||
| 435 | return error; | ||
| 436 | } | ||
| 437 | |||
| 438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS | 438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS |
| 439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) | 439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) |
| 440 | { | 440 | { |
diff --git a/include/linux/falloc.h b/include/linux/falloc.h index 8e912ab6a072..3c155107d61f 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h | |||
| @@ -3,4 +3,25 @@ | |||
| 3 | 3 | ||
| 4 | #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ | 4 | #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ |
| 5 | 5 | ||
| 6 | #ifdef __KERNEL__ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * Space reservation ioctls and argument structure | ||
| 10 | * are designed to be compatible with the legacy XFS ioctls. | ||
| 11 | */ | ||
| 12 | struct space_resv { | ||
| 13 | __s16 l_type; | ||
| 14 | __s16 l_whence; | ||
| 15 | __s64 l_start; | ||
| 16 | __s64 l_len; /* len == 0 means until end of file */ | ||
| 17 | __s32 l_sysid; | ||
| 18 | __u32 l_pid; | ||
| 19 | __s32 l_pad[4]; /* reserved area */ | ||
| 20 | }; | ||
| 21 | |||
| 22 | #define FS_IOC_RESVSP _IOW('X', 40, struct space_resv) | ||
| 23 | #define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv) | ||
| 24 | |||
| 25 | #endif /* __KERNEL__ */ | ||
| 26 | |||
| 6 | #endif /* _FALLOC_H_ */ | 27 | #endif /* _FALLOC_H_ */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 1ff5e4e01952..79e302ddde0f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1906,6 +1906,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode) | |||
| 1906 | 1906 | ||
| 1907 | extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, | 1907 | extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, |
| 1908 | struct file *filp); | 1908 | struct file *filp); |
| 1909 | extern int do_fallocate(struct file *file, int mode, loff_t offset, | ||
| 1910 | loff_t len); | ||
| 1909 | extern long do_sys_open(int dfd, const char __user *filename, int flags, | 1911 | extern long do_sys_open(int dfd, const char __user *filename, int flags, |
| 1910 | int mode); | 1912 | int mode); |
| 1911 | extern struct file *filp_open(const char *, int, int); | 1913 | extern struct file *filp_open(const char *, int, int); |
| @@ -1914,6 +1916,10 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, | |||
| 1914 | extern int filp_close(struct file *, fl_owner_t id); | 1916 | extern int filp_close(struct file *, fl_owner_t id); |
| 1915 | extern char * getname(const char __user *); | 1917 | extern char * getname(const char __user *); |
| 1916 | 1918 | ||
| 1919 | /* fs/ioctl.c */ | ||
| 1920 | |||
| 1921 | extern int ioctl_preallocate(struct file *filp, void __user *argp); | ||
| 1922 | |||
| 1917 | /* fs/dcache.c */ | 1923 | /* fs/dcache.c */ |
| 1918 | extern void __init vfs_caches_init_early(void); | 1924 | extern void __init vfs_caches_init_early(void); |
| 1919 | extern void __init vfs_caches_init(unsigned long); | 1925 | extern void __init vfs_caches_init(unsigned long); |
