Skip to content

Commit

Permalink
fs: Add new pre-allocation ioctls to vfs for compatibility with legac…
Browse files Browse the repository at this point in the history
…y 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>
  • Loading branch information
Ankit Jain authored and Al Viro committed Jun 24, 2009
1 parent 01c0319 commit 3e63cbb
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 29 deletions.
48 changes: 48 additions & 0 deletions fs/compat_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/vt.h>
#include <linux/falloc.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/ppp_defs.h>
Expand Down Expand Up @@ -1779,6 +1780,41 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, cmd, (unsigned long)tn);
}

/* on ia32 l_start is on a 32-bit boundary */
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
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 FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32)
#define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32)

/* just account for different alignment */
static int compat_ioctl_preallocate(struct file *file, 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 ioctl_preallocate(file, p);
}
#endif


typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
unsigned long, struct file *);
Expand Down Expand Up @@ -2756,6 +2792,18 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
case FIOQSIZE:
break;

#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
case FS_IOC_RESVSP_32:
case FS_IOC_RESVSP64_32:
error = compat_ioctl_preallocate(filp, arg);
goto out_fput;
#else
case FS_IOC_RESVSP:
case FS_IOC_RESVSP64:
error = ioctl_preallocate(filp, (void __user *)arg);
goto out_fput;
#endif

case FIBMAP:
case FIGETBSZ:
case FIONREAD:
Expand Down
35 changes: 35 additions & 0 deletions fs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -403,6 +404,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, void __user *argp)
{
struct inode *inode = filp->f_path.dentry->d_inode;
struct space_resv sr;

if (copy_from_user(&sr, argp, 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)
{
Expand All @@ -414,6 +446,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
return ioctl_fibmap(filp, p);
case FIONREAD:
return put_user(i_size_read(inode) - filp->f_pos, p);
case FS_IOC_RESVSP:
case FS_IOC_RESVSP64:
return ioctl_preallocate(filp, p);
}

return vfs_ioctl(filp, cmd, arg);
Expand Down
58 changes: 29 additions & 29 deletions fs/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,63 +378,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
#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)
{
Expand Down
21 changes: 21 additions & 0 deletions include/linux/falloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,25 @@

#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]; /* reserved area */
};

#define FS_IOC_RESVSP _IOW('X', 40, struct space_resv)
#define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv)

#endif /* __KERNEL__ */

#endif /* _FALLOC_H_ */
6 changes: 6 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode)

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);
Expand All @@ -1914,6 +1916,10 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
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, void __user *argp);

/* fs/dcache.c */
extern void __init vfs_caches_init_early(void);
extern void __init vfs_caches_init(unsigned long);
Expand Down

0 comments on commit 3e63cbb

Please sign in to comment.