[PATCH] fs: Add new pre-allocation ioctls to vfs for compatibilitywith legacy xfs ioctls

From: Ankit Jain
Date: Wed Jan 28 2009 - 16:01:00 EST


Al, Could this be included in the vfs queue?

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.

Signed-off-by: Ankit Jain <me@xxxxxxxxxxxxx>
Reviewed-by: Christoph Hellwig <hch@xxxxxx>
Tested-by: Christoph Hellwig <hch@xxxxxx>
---
fs/compat_ioctl.c | 29 +++++++++++++++++++++++++++
fs/ioctl.c | 35 ++++++++++++++++++++++++++++++++
fs/open.c | 51 +++++++++++++++++++++++------------------------
include/linux/falloc.h | 44 +++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 6 +++++
5 files changed, 139 insertions(+), 26 deletions(-)

Index: xfs/fs/compat_ioctl.c
===================================================================
--- xfs.orig/fs/compat_ioctl.c 2009-01-21 21:03:26.217449883 +0100
+++ xfs/fs/compat_ioctl.c 2009-01-27 20:36:59.189424147 +0100
@@ -2765,6 +2765,26 @@ static void compat_ioctl_error(struct fi
free_page((unsigned long)path);
}

+#ifdef BROKEN_X86_ALIGNMENT
+/* just account for different alignment */
+static unsigned long copy_to_space_resv(unsigned long arg)
+{
+ struct space_resv_32 __user *p32 = (void __user *)arg;
+ struct space_resv __user *p = compat_alloc_user_space(sizeof(*p));
+
+ if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) ||
+ copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) ||
+ copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) ||
+ copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) ||
+ copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) ||
+ copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) ||
+ copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32)))
+ return -EFAULT;
+
+ return (unsigned long)p;
+}
+#endif
+
asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
unsigned long arg)
{
@@ -2795,6 +2815,15 @@ asmlinkage long compat_sys_ioctl(unsigne
case FIOQSIZE:
break;

+ case F_IOC_RESVSP_32:
+ case F_IOC_RESVSP64_32:
+#ifdef BROKEN_X86_ALIGNMENT
+ arg = copy_to_space_resv(arg);
+ cmd = _NATIVE_IOC(cmd, struct space_resv);
+#endif
+ error = ioctl_preallocate(filp, arg);
+ goto out_fput;
+
case FIBMAP:
case FIGETBSZ:
case FIONREAD:
Index: xfs/fs/ioctl.c
===================================================================
--- xfs.orig/fs/ioctl.c 2009-01-21 21:03:27.321448363 +0100
+++ xfs/fs/ioctl.c 2009-01-27 20:36:59.189424147 +0100
@@ -15,6 +15,7 @@
#include <linux/uaccess.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h>
+#include <linux/falloc.h>

#include <asm/ioctls.h>

@@ -370,6 +371,37 @@ EXPORT_SYMBOL(generic_block_fiemap);

#endif /* CONFIG_BLOCK */

+/*
+ * This provides compatibility with legacy XFS pre-allocation ioctls
+ * which predate the fallocate syscall.
+ *
+ * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
+ * are used here, rest are ignored.
+ */
+int ioctl_preallocate(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ struct space_resv sr;
+
+ if (copy_from_user(&sr, (struct space_resv __user *) arg, sizeof(sr)))
+ return -EFAULT;
+
+ switch (sr.l_whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ sr.l_start += filp->f_pos;
+ break;
+ case SEEK_END:
+ sr.l_start += i_size_read(inode);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+}
+
static int file_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -385,6 +417,9 @@ static int file_ioctl(struct file *filp,
return put_user(inode->i_sb->s_blocksize, p);
case FIONREAD:
return put_user(i_size_read(inode) - filp->f_pos, p);
+ case F_IOC_RESVSP:
+ case F_IOC_RESVSP64:
+ return ioctl_preallocate(filp, arg);
}

return vfs_ioctl(filp, cmd, arg);
Index: xfs/fs/open.c
===================================================================
--- xfs.orig/fs/open.c 2009-01-21 21:03:27.740294372 +0100
+++ xfs/fs/open.c 2009-01-27 20:41:38.208298998 +0100
@@ -377,63 +377,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftrun
#endif
#endif /* BITS_PER_LONG == 32 */

-SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+
+int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
- struct file *file;
- struct inode *inode;
- long ret = -EINVAL;
+ struct inode *inode = file->f_path.dentry->d_inode;
+ long ret;

if (offset < 0 || len <= 0)
- goto out;
+ return -EINVAL;

/* Return error if mode is not supported */
- ret = -EOPNOTSUPP;
if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
- goto out;
+ return -EOPNOTSUPP;

- ret = -EBADF;
- file = fget(fd);
- if (!file)
- goto out;
if (!(file->f_mode & FMODE_WRITE))
- goto out_fput;
+ return -EBADF;
/*
* Revalidate the write permissions, in case security policy has
* changed since the files were opened.
*/
ret = security_file_permission(file, MAY_WRITE);
if (ret)
- goto out_fput;
+ return ret;

- inode = file->f_path.dentry->d_inode;
-
- ret = -ESPIPE;
if (S_ISFIFO(inode->i_mode))
- goto out_fput;
+ return -ESPIPE;

- ret = -ENODEV;
/*
* Let individual file system decide if it supports preallocation
* for directories or not.
*/
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
- goto out_fput;
+ return -ENODEV;

- ret = -EFBIG;
/* Check for wrap through zero too */
if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
- goto out_fput;
+ return -EFBIG;

- if (inode->i_op->fallocate)
- ret = inode->i_op->fallocate(inode, mode, offset, len);
- else
- ret = -EOPNOTSUPP;
+ if (!inode->i_op->fallocate)
+ return -EOPNOTSUPP;

-out_fput:
- fput(file);
-out:
- return ret;
+ return inode->i_op->fallocate(inode, mode, offset, len);
}
+
+SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+{
+ struct file *file;
+ int error = -EBADF;
+
+ file = fget(fd);
+ if (file) {
+ error = do_fallocate(file, mode, offset, len);
+ fput(file);
+ }
+
+ return error;
+}
+
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
{
Index: xfs/include/linux/falloc.h
===================================================================
--- xfs.orig/include/linux/falloc.h 2009-01-21 21:03:28.076324621 +0100
+++ xfs/include/linux/falloc.h 2009-01-27 20:36:59.190423995 +0100
@@ -3,4 +3,48 @@

#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */

+#ifdef __KERNEL__
+
+/*
+ * Space reservation ioctls and argument structure
+ * are designed to be compatible with the legacy XFS ioctls.
+ */
+struct space_resv {
+ __s16 l_type;
+ __s16 l_whence;
+ __s64 l_start;
+ __s64 l_len; /* len == 0 means until end of file */
+ __s32 l_sysid;
+ __u32 l_pid;
+ __s32 l_pad[4]; /* reserve area */
+};
+
+#define F_IOC_RESVSP _IOW('X', 40, struct space_resv)
+#define F_IOC_RESVSP64 _IOW('X', 42, struct space_resv)
+
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+#define BROKEN_X86_ALIGNMENT
+
+#define _NATIVE_IOC(cmd, type) \
+ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
+
+/* on ia32 l_start is on a 32-bit boundary */
+struct space_resv_32 {
+ __s16 l_type;
+ __s16 l_whence;
+ __s64 l_start __attribute__((packed));
+ /* len == 0 means until end of file */
+ __s64 l_len __attribute__((packed));
+ __s32 l_sysid;
+ __u32 l_pid;
+ __s32 l_pad[4]; /* reserve area */
+};
+
+#define F_IOC_RESVSP_32 _IOW('X', 40, struct space_resv_32)
+#define F_IOC_RESVSP64_32 _IOW('X', 42, struct space_resv_32)
+
+#endif
+
+#endif /* __KERNEL__ */
+
#endif /* _FALLOC_H_ */
Index: xfs/include/linux/fs.h
===================================================================
--- xfs.orig/include/linux/fs.h 2009-01-24 17:58:48.960904090 +0100
+++ xfs/include/linux/fs.h 2009-01-27 20:42:01.675299140 +0100
@@ -1694,6 +1694,8 @@ static inline int break_lease(struct ino

extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp);
+extern int do_fallocate(struct file *file, int mode, loff_t offset,
+ loff_t len);
extern long do_sys_open(int dfd, const char __user *filename, int flags,
int mode);
extern struct file *filp_open(const char *, int, int);
@@ -1702,6 +1704,10 @@ extern struct file * dentry_open(struct
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char __user *);

+/* fs/ioctl.c */
+
+extern int ioctl_preallocate(struct file *filp, unsigned long arg);
+
/* fs/dcache.c */
extern void __init vfs_caches_init_early(void);
extern void __init vfs_caches_init(unsigned long);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/