Commit 3e63cbb1efca7dd3137de1bb475e2e068e38ef23

Authored by Ankit Jain
Committed by Al Viro
1 parent 01c031945f

fs: Add new pre-allocation ioctls to vfs for compatibility with legacy xfs ioctls

This patch adds ioctls to vfs for compatibility with legacy XFS
pre-allocation ioctls (XFS_IOC_*RESVP*). The implementation
effectively invokes sys_fallocate for the new ioctls.
Also handles the compat_ioctl case.
Note: These legacy ioctls are also implemented by OCFS2.

[AV: folded fixes from hch]

Signed-off-by: Ankit Jain <me@ankitjain.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 5 changed files with 139 additions and 29 deletions Side-by-side Diff

... ... @@ -31,6 +31,7 @@
31 31 #include <linux/skbuff.h>
32 32 #include <linux/netlink.h>
33 33 #include <linux/vt.h>
  34 +#include <linux/falloc.h>
34 35 #include <linux/fs.h>
35 36 #include <linux/file.h>
36 37 #include <linux/ppp_defs.h>
37 38  
... ... @@ -1779,7 +1780,42 @@
1779 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 +};
1782 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 +
  1818 +
1783 1819 typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
1784 1820 unsigned long, struct file *);
1785 1821  
... ... @@ -2755,6 +2791,18 @@
2755 2791 case FIOASYNC:
2756 2792 case FIOQSIZE:
2757 2793 break;
  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
2758 2806  
2759 2807 case FIBMAP:
2760 2808 case FIGETBSZ:
... ... @@ -15,6 +15,7 @@
15 15 #include <linux/uaccess.h>
16 16 #include <linux/writeback.h>
17 17 #include <linux/buffer_head.h>
  18 +#include <linux/falloc.h>
18 19  
19 20 #include <asm/ioctls.h>
20 21  
... ... @@ -403,6 +404,37 @@
403 404  
404 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 438 static int file_ioctl(struct file *filp, unsigned int cmd,
407 439 unsigned long arg)
408 440 {
... ... @@ -414,6 +446,9 @@
414 446 return ioctl_fibmap(filp, p);
415 447 case FIONREAD:
416 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 454 return vfs_ioctl(filp, cmd, arg);
... ... @@ -378,63 +378,63 @@
378 378 #endif
379 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;
385   - long ret = -EINVAL;
  384 + struct inode *inode = file->f_path.dentry->d_inode;
  385 + long ret;
386 386  
387 387 if (offset < 0 || len <= 0)
388   - goto out;
  388 + return -EINVAL;
389 389  
390 390 /* Return error if mode is not supported */
391   - ret = -EOPNOTSUPP;
392 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 394 if (!(file->f_mode & FMODE_WRITE))
400   - goto out_fput;
  395 + return -EBADF;
401 396 /*
402 397 * Revalidate the write permissions, in case security policy has
403 398 * changed since the files were opened.
404 399 */
405 400 ret = security_file_permission(file, MAY_WRITE);
406 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 404 if (S_ISFIFO(inode->i_mode))
413   - goto out_fput;
  405 + return -ESPIPE;
414 406  
415   - ret = -ENODEV;
416 407 /*
417 408 * Let individual file system decide if it supports preallocation
418 409 * for directories or not.
419 410 */
420 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 414 /* Check for wrap through zero too */
425 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)
429   - ret = inode->i_op->fallocate(inode, mode, offset, len);
430   - else
431   - ret = -EOPNOTSUPP;
  418 + if (!inode->i_op->fallocate)
  419 + return -EOPNOTSUPP;
432 420  
433   -out_fput:
434   - fput(file);
435   -out:
436   - return ret;
  421 + return inode->i_op->fallocate(inode, mode, offset, len);
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 438 #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
439 439 asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
440 440 {
include/linux/falloc.h
... ... @@ -3,5 +3,26 @@
3 3  
4 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 27 #endif /* _FALLOC_H_ */
... ... @@ -1906,6 +1906,8 @@
1906 1906  
1907 1907 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
1908 1908 struct file *filp);
  1909 +extern int do_fallocate(struct file *file, int mode, loff_t offset,
  1910 + loff_t len);
1909 1911 extern long do_sys_open(int dfd, const char __user *filename, int flags,
1910 1912 int mode);
1911 1913 extern struct file *filp_open(const char *, int, int);
... ... @@ -1913,6 +1915,10 @@
1913 1915 const struct cred *);
1914 1916 extern int filp_close(struct file *, fl_owner_t id);
1915 1917 extern char * getname(const char __user *);
  1918 +
  1919 +/* fs/ioctl.c */
  1920 +
  1921 +extern int ioctl_preallocate(struct file *filp, void __user *argp);
1916 1922  
1917 1923 /* fs/dcache.c */
1918 1924 extern void __init vfs_caches_init_early(void);