Skip to contentSkip to conversation

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

RFC PATCH Superseded Ankit Jain 4 participants 9 messages Dec 15, 2008 – Dec 18, 2008

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Ankit Jain

author
#0 lore raw

RFC PATCH 1/1 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.
Note: These legacy ioctls are also implemented by OCFS2.

There are some things that I'm not sure about:
1. Should the struct space_resv be exposed to user-space? If not, then what would be the right place to put it? And the ioctl definitions?
2. Should the corresponding ioctls be removed from ocfs2?

---
 fs/ioctl.c             |   37 +++++++++++++++++++++++++++
 fs/open.c              |   51 ++++++++++++++++++-------------------
 include/linux/falloc.h |   19 ++++++++++++++
 include/linux/fs.h     |    2 +
 4 files changed, 83 insertions(+), 26 deletions(-)
fs/ioctl.c +37 -0
index 43e8b2c..5e565c8 100644
@@ -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>
 
@@ -346,6 +347,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.
+ */
+static 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)
 {
@@ -361,6 +393,11 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
 		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:
+	case F_IOC_UNRESVSP:
+	case F_IOC_UNRESVSP64:
+		return ioctl_preallocate(filp, arg);
 	}
 
 	return vfs_ioctl(filp, cmd, arg);
fs/open.c +25 -26

87 lines not on this page · raw message

include/linux/falloc.h +19 -0
index 8e912ab..4f2a727 100644
@@ -3,4 +3,23 @@
 
 #define FALLOC_FL_KEEP_SIZE	0x01 /* default is extend size */
 
+/*
+ * Space reservation / allocation 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_UNRESVSP	_IOW('X', 41, struct space_resv)
+#define F_IOC_RESVSP64	_IOW('X', 42, struct space_resv)
+#define F_IOC_UNRESVSP64	_IOW('X', 43, struct space_resv)
+
 #endif /* _FALLOC_H_ */
include/linux/fs.h +2 -0
index 4a853ef..b1d8f12 100644
@@ -1671,6 +1671,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 long 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);
#1 lore raw
Quoted 9 lines · Ankit Jain

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.
Note: These legacy ioctls are also implemented by OCFS2.

There are some things that I'm not sure about:
1. Should the struct space_resv be exposed to user-space? If not, then what would be the right place to put it? And the ioctl definitions?

Yes. As far as where to put it, I'm not sure. Maybe falloc.h?

Quoted 1 line

2. Should the corresponding ioctls be removed from ocfs2?

Well, a small amount of the code in fs/ocfs2/ioctl.c can certainly go away. Shouldn't we be talking about doing the same for xfs too?

Quoted 59 lines
---
 fs/ioctl.c             |   37 +++++++++++++++++++++++++++
 fs/open.c              |   51 ++++++++++++++++++-------------------
 include/linux/falloc.h |   19 ++++++++++++++
 include/linux/fs.h     |    2 +
 4 files changed, 83 insertions(+), 26 deletions(-)
fs/ioctl.c +32 -0
index 43e8b2c..5e565c8 100644
@@ -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>
 
@@ -346,6 +347,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.
+ */
+static 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)
 {

fs/ioctl.c static int file_ioctl(struct file *filp, unsigned int cmd, · line 400

Quoted 8 lines
fs/ioctl.c +5 -0
@@ -361,6 +393,11 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
 		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:
+	case F_IOC_UNRESVSP:
+	case F_IOC_UNRESVSP64:
+		return ioctl_preallocate(filp, arg);

This patch is not implementing proper support for F_IOC_UNRESVSP and F_IOC_UNRESVSP64, so why are you catching those here? To be more clear, those are used for freeing space in a file ("puching holes"), which fallocate is not set up to do right now.

	--Mark

--
Mark Fasheh

#2 lore raw
Quoted 6 lines · Mark Fasheh
Quoted 5 lines · Ankit Jain

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.
Note: These legacy ioctls are also implemented by OCFS2.

Quoted 6 lines
Quoted 4 lines

There are some things that I'm not sure about:
1. Should the struct space_resv be exposed to user-space? If not, then what would be the right place to put it? And the ioctl definitions?

Yes. As far as where to put it, I'm not sure. Maybe falloc.h?

I'd sort of rather not; why should that legacy struct space_resv be available in a header... I thought this was for people already using the xfs ioctl, in which case they are already using the xfs header... and if they want preallocation in any new work, they should use fallocate() instead, yes?

I mean it wouldn't hurt anything but it sort of confuses the interface story IMHO.

-Eric

#3 lore raw
Quoted 5 lines · Eric Sandeen
Quoted 5 lines
Quoted 4 lines

There are some things that I'm not sure about:
1. Should the struct space_resv be exposed to user-space? If not, then what would be the right place to put it? And the ioctl definitions?

Quoted 7 lines
Quoted 1 line

Yes. As far as where to put it, I'm not sure. Maybe falloc.h?

I'd sort of rather not; why should that legacy struct space_resv be available in a header... I thought this was for people already using the xfs ioctl, in which case they are already using the xfs header... and if they want preallocation in any new work, they should use fallocate() instead, yes?

Actually, yeah agreed - I take that back. Old users are already getting them from file system headers, new ones should use fallocate. So there's no need to expose the ioctls to userspace, at least not if all we're talking about is the RESVP ioctls.

	--Mark

--
Mark Fasheh

author
#4 lore raw
Quoted 6 lines · Mark Fasheh

On Wed, Dec 17, 2008 at 03:06:14PM -0600, Eric Sandeen wrote:

Actually, yeah agreed - I take that back. Old users are already getting them from file system headers, new ones should use fallocate. So there's no need to expose the ioctls to userspace, at least not if all we're talking about is the RESVP ioctls.

Makes sense. So I can just keep them in falloc.h in a #ifdef __KERNEL__ ? Or should this be in a new ioctl.h ?

-Ankit

Quoted 4 lines
	--Mark

--
Mark Fasheh

author
#5 lore raw
In reply to Mark Fasheh
Quoted 4 lines · Mark Fasheh
Quoted 1 line

2. Should the corresponding ioctls be removed from ocfs2?

Well, a small amount of the code in fs/ocfs2/ioctl.c can certainly go away. Shouldn't we be talking about doing the same for xfs too?

Yep. I'll cook up cleanup patches for these two and post them.

-Ankit

Quoted 78 lines
Quoted 61 lines
---
 fs/ioctl.c             |   37 +++++++++++++++++++++++++++
 fs/open.c              |   51 ++++++++++++++++++-------------------
 include/linux/falloc.h |   19 ++++++++++++++
 include/linux/fs.h     |    2 +
 4 files changed, 83 insertions(+), 26 deletions(-)
fs/ioctl.c +32 -0
index 43e8b2c..5e565c8 100644
@@ -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>
 
@@ -346,6 +347,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.
+ */
+static 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)
 {

fs/ioctl.c static int file_ioctl(struct file *filp, unsigned int cmd, · line 400

Quoted 8 lines
fs/ioctl.c +5 -0
@@ -361,6 +393,11 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
 		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:
+	case F_IOC_UNRESVSP:
+	case F_IOC_UNRESVSP64:
+		return ioctl_preallocate(filp, arg);

This patch is not implementing proper support for F_IOC_UNRESVSP and F_IOC_UNRESVSP64, so why are you catching those here? To be more clear, those are used for freeing space in a file ("puching holes"), which fallocate is not set up to do right now.

	--Mark

--
Mark Fasheh

author
#6 lore raw
In reply to Mark Fasheh
Quoted 5 lines · Mark Fasheh
Quoted 1 line · Ankit Jain

2. Should the corresponding ioctls be removed from ocfs2?

Well, a small amount of the code in fs/ocfs2/ioctl.c can certainly go away. Shouldn't we be talking about doing the same for xfs too?

Reading the code a bit, my understanding is that as compat_ioctl is also supported and that just delegates to ioctl (ocfs2_ioctl), so we can't remove the *_RESVSP* handling.
Same goes for xfs also.

Does that sound fair or did I not understand it correctly?

-Ankit

#7 lore raw
In reply to Ankit Jain
Quoted 3 lines · Ankit Jain

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.

I don't think we can use sys_fallocate for XFS_IOC_UNRESVSP* commands, which suppose to release currently allocated file blocks.
See more comments below.

Felix

Quoted 70 lines

Note: These legacy ioctls are also implemented by OCFS2.

There are some things that I'm not sure about:
1. Should the struct space_resv be exposed to user-space? If not, then what would be the right place to put it? And the ioctl definitions?
2. Should the corresponding ioctls be removed from ocfs2?

---
 fs/ioctl.c             |   37 +++++++++++++++++++++++++++
 fs/open.c              |   51 ++++++++++++++++++-------------------
 include/linux/falloc.h |   19 ++++++++++++++
 include/linux/fs.h     |    2 +
 4 files changed, 83 insertions(+), 26 deletions(-)
fs/ioctl.c +6 -0
index 43e8b2c..5e565c8 100644
@@ -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>
 
@@ -346,6 +347,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.
+ */

fs/ioctl.c +6 -0
+static 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)))

fs/ioctl.c +16 -0
+		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);

fs/ioctl.c +2 -0
+}
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {

fs/ioctl.c static int file_ioctl(struct file *filp, · line 401

Quoted 9 lines
fs/ioctl.c +5 -0
@@ -361,6 +393,11 @@ static int file_ioctl(struct file *filp,  
 unsigned int cmd,
 		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:
+	case F_IOC_UNRESVSP:
+	case F_IOC_UNRESVSP64:
+		return ioctl_preallocate(filp, arg);

At this point the original command 'cmd' is dropped, and ioctl_preallocate() assumes F_IOC_RESVSP*. Indeed, in the following path

ioctl_preallocate
do_fallocate
.fallocate/xfs_vn_fallocate
xfs_change_file_space(XFS_IOC_RESVSP)

UNRESVSP is never considered.

Quoted 141 lines
fs/ioctl.c +0 -0
 	}
 
fs/ioctl.c +0 -0
 	return vfs_ioctl(filp, cmd, arg);
fs/open.c +14 -26
index 83cdb9d..0703bcb 100644
@@ -360,62 +360,61 @@ asmlinkage long sys_ftruncate64(unsigned int  
 fd, loff_t length)
 }
 #endif
 
-asmlinkage long sys_fallocate(int fd, int mode, loff_t offset,  
 loff_t len)
+long do_fallocate(struct file *file, int mode, loff_t offset,  
 loff_t len)
 {
-	struct file *file;
 	struct inode *inode;
-	long ret = -EINVAL;
+	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;
+	if (!file || !(file->f_mode & FMODE_WRITE))
+		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 && inode->i_op->fallocate)
-		ret = inode->i_op->fallocate(inode, mode, offset, len);
+		return inode->i_op->fallocate(inode, mode, offset, len);
 	else
-		ret = -EOPNOTSUPP;
+		return -EOPNOTSUPP;
+}
 
-out_fput:
-	fput(file);
-out:
-	return ret;
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset,  

loff_t len)

fs/open.c +11 -0
+{
+	struct file *file;
+	int error = -EBADF;
+
+	file = fget(fd);
+	if (file) {
+		error = do_fallocate(file, mode, offset, len);
+		fput(file);
+	}
+
+	return error;
 }
 
 /*
include/linux/falloc.h +19 -0
index 8e912ab..4f2a727 100644
@@ -3,4 +3,23 @@
 
 #define FALLOC_FL_KEEP_SIZE	0x01 /* default is extend size */
 
+/*
+ * Space reservation / allocation 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_UNRESVSP	_IOW('X', 41, struct space_resv)
+#define F_IOC_RESVSP64	_IOW('X', 42, struct space_resv)
+#define F_IOC_UNRESVSP64	_IOW('X', 43, struct space_resv)
+
 #endif /* _FALLOC_H_ */
include/linux/fs.h +2 -0
index 4a853ef..b1d8f12 100644
@@ -1671,6 +1671,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 long 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  
Quoted 8 lines

flags,
int mode);
extern struct file *filp_open(const char *, int, int);
--
To unsubscribe from this list: send the line "unsubscribe linux- fsdevel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

author
#8 lore raw
Quoted 9 lines · Felix Blyakher
Quoted 4 lines

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.

I don't think we can use sys_fallocate for XFS_IOC_UNRESVSP* commands, which suppose to release currently allocated file blocks.
See more comments below.

My bad :( I'll drop the *UNRESV* completely from the new ioctl and post an updated patch.

-Ankit