aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnkit Jain <me@ankitjain.org>2009-06-19 14:28:07 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-24 08:15:27 -0400
commit3e63cbb1efca7dd3137de1bb475e2e068e38ef23 (patch)
tree5a7964068266e778e94c1348192d3c85eba4ac48
parent01c031945f2755c7afaaf456088543312f2b72ea (diff)
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>
-rw-r--r--fs/compat_ioctl.c48
-rw-r--r--fs/ioctl.c35
-rw-r--r--fs/open.c58
-rw-r--r--include/linux/falloc.h21
-rw-r--r--include/linux/fs.h6
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)
1785struct 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 */
1800static 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
1783typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, 1819typedef 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 */
414int 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
406static int file_ioctl(struct file *filp, unsigned int cmd, 438static 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);
diff --git a/fs/open.c b/fs/open.c
index 7200e23d9258..dd98e8076024 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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
381SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) 381
382int 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
433out_fput: 421 return inode->i_op->fallocate(inode, mode, offset, len);
434 fput(file);
435out:
436 return ret;
437} 422}
423
424SYSCALL_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
439asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) 439asmlinkage 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 */
12struct 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
1907extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, 1907extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
1908 struct file *filp); 1908 struct file *filp);
1909extern int do_fallocate(struct file *file, int mode, loff_t offset,
1910 loff_t len);
1909extern long do_sys_open(int dfd, const char __user *filename, int flags, 1911extern long do_sys_open(int dfd, const char __user *filename, int flags,
1910 int mode); 1912 int mode);
1911extern struct file *filp_open(const char *, int, int); 1913extern struct file *filp_open(const char *, int, int);
@@ -1914,6 +1916,10 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
1914extern int filp_close(struct file *, fl_owner_t id); 1916extern int filp_close(struct file *, fl_owner_t id);
1915extern char * getname(const char __user *); 1917extern char * getname(const char __user *);
1916 1918
1919/* fs/ioctl.c */
1920
1921extern int ioctl_preallocate(struct file *filp, void __user *argp);
1922
1917/* fs/dcache.c */ 1923/* fs/dcache.c */
1918extern void __init vfs_caches_init_early(void); 1924extern void __init vfs_caches_init_early(void);
1919extern void __init vfs_caches_init(unsigned long); 1925extern void __init vfs_caches_init(unsigned long);