add a FMODE flag to make XFS invisible I/O less hacky
PATCH 1/1 add a FMODE flag to make XFS invisible I/O less hacky
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Instead of doing directly assignment of file operations that set an internal flag for it add a new FMODE_INVISIBLE flag that we can check in the normal file operations.
Signature · 255 lines
fs/xfs/linux-2.6/xfs_file.c | 134 +++++++------------------------------------
fs/xfs/linux-2.6/xfs_ioctl.c | 3
fs/xfs/linux-2.6/xfs_iops.h | 1
include/linux/fs.h | 2
4 files changed, 28 insertions(+), 112 deletions(-)
Index: linux-2.6/fs/xfs/linux-2.6/xfs_ioctl.c
===================================================================
--- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl.c 2008-11-12 00:59:25.000000000 +0530
+++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl.c 2008-11-28 16:11:30.000000000 +0530
@@ -326,10 +326,11 @@ xfs_open_by_handle(
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
}
+
if (inode->i_mode & S_IFREG) {
/* invisible operation should not change atime */
filp->f_flags |= O_NOATIME;
- filp->f_op = &xfs_invis_file_operations;
+ filp->f_mode |= FMODE_INVISIBLE;
}
fd_install(new_fd, filp);
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h 2008-11-28 16:04:52.000000000 +0530
+++ linux-2.6/include/linux/fs.h 2008-11-28 16:04:53.000000000 +0530
@@ -81,6 +81,8 @@ extern int dir_notify_enable;
/* File is opened using open(.., 3, ..) and is writeable only for ioctls
(specialy hack for floppy.c) */
#define FMODE_WRITE_IOCTL ((__force fmode_t)128)
+/* Invisible I/O - special hack for XFS ioctls */
+#define FMODE_INVISIBLE ((__force fmode_t)256)
#define RW_MASK 1
#define RWA_MASK 2
Index: linux-2.6/fs/xfs/linux-2.6/xfs_file.c
===================================================================
--- linux-2.6.orig/fs/xfs/linux-2.6/xfs_file.c 2008-11-28 16:04:59.000000000 +0530
+++ linux-2.6/fs/xfs/linux-2.6/xfs_file.c 2008-11-28 16:08:27.000000000 +0530
@@ -44,81 +44,45 @@
static struct vm_operations_struct xfs_file_vm_ops;
-STATIC_INLINE ssize_t
-__xfs_file_read(
+STATIC ssize_t
+xfs_file_aio_read(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
- int ioflags,
loff_t pos)
{
struct file *file = iocb->ki_filp;
+ int ioflags = IO_ISAIO;
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
+ if (file->f_mode |= FMODE_INVISIBLE)
+ ioflags |= IO_INVIS;
return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov,
nr_segs, &iocb->ki_pos, ioflags);
}
STATIC ssize_t
-xfs_file_aio_read(
- struct kiocb *iocb,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t pos)
-{
- return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
-}
-
-STATIC ssize_t
-xfs_file_aio_read_invis(
- struct kiocb *iocb,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t pos)
-{
- return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
-}
-
-STATIC_INLINE ssize_t
-__xfs_file_write(
+xfs_file_aio_write(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
- int ioflags,
loff_t pos)
{
- struct file *file = iocb->ki_filp;
+ struct file *file = iocb->ki_filp;
+ int ioflags = IO_ISAIO;
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
+ if (file->f_mode |= FMODE_INVISIBLE)
+ ioflags |= IO_INVIS;
return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs,
&iocb->ki_pos, ioflags);
}
STATIC ssize_t
-xfs_file_aio_write(
- struct kiocb *iocb,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t pos)
-{
- return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
-}
-
-STATIC ssize_t
-xfs_file_aio_write_invis(
- struct kiocb *iocb,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t pos)
-{
- return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
-}
-
-STATIC ssize_t
xfs_file_splice_read(
struct file *infilp,
loff_t *ppos,
@@ -126,20 +90,13 @@ xfs_file_splice_read(
size_t len,
unsigned int flags)
{
- return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
- infilp, ppos, pipe, len, flags, 0);
-}
+ int ioflags = 0;
+
+ if (infilp->f_mode |= FMODE_INVISIBLE)
+ ioflags |= IO_INVIS;
-STATIC ssize_t
-xfs_file_splice_read_invis(
- struct file *infilp,
- loff_t *ppos,
- struct pipe_inode_info *pipe,
- size_t len,
- unsigned int flags)
-{
return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
- infilp, ppos, pipe, len, flags, IO_INVIS);
+ infilp, ppos, pipe, len, flags, ioflags);
}
STATIC ssize_t
@@ -150,20 +107,13 @@ xfs_file_splice_write(
size_t len,
unsigned int flags)
{
- return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
- pipe, outfilp, ppos, len, flags, 0);
-}
+ int ioflags = 0;
+
+ if (outfilp->f_mode |= FMODE_INVISIBLE)
+ ioflags |= IO_INVIS;
-STATIC ssize_t
-xfs_file_splice_write_invis(
- struct pipe_inode_info *pipe,
- struct file *outfilp,
- loff_t *ppos,
- size_t len,
- unsigned int flags)
-{
return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
- pipe, outfilp, ppos, len, flags, IO_INVIS);
+ pipe, outfilp, ppos, len, flags, ioflags);
}
STATIC int
@@ -256,29 +206,12 @@ xfs_file_ioctl(
{
int error;
struct inode *inode = filp->f_path.dentry->d_inode;
+ int ioflags = 0;
- error = xfs_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p);
- xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
+ if (filp->f_mode |= FMODE_INVISIBLE)
+ ioflags |= IO_INVIS;
- /* NOTE: some of the ioctl's return positive #'s as a
- * byte count indicating success, such as
- * readlink_by_handle. So we don't "sign flip"
- * like most other routines. This means true
- * errors need to be returned as a negative value.
- */
- return error;
-}
-
-STATIC long
-xfs_file_ioctl_invis(
- struct file *filp,
- unsigned int cmd,
- unsigned long p)
-{
- int error;
- struct inode *inode = filp->f_path.dentry->d_inode;
-
- error = xfs_ioctl(XFS_I(inode), filp, IO_INVIS, cmd, (void __user *)p);
+ error = xfs_ioctl(XFS_I(inode), filp, ioflags, cmd, (void __user *)p);
xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
/* NOTE: some of the ioctl's return positive #'s as a
@@ -325,25 +258,6 @@ const struct file_operations xfs_file_op
#endif
};
-const struct file_operations xfs_invis_file_operations = {
- .llseek = generic_file_llseek,
- .read = do_sync_read,
- .write = do_sync_write,
- .aio_read = xfs_file_aio_read_invis,
- .aio_write = xfs_file_aio_write_invis,
- .splice_read = xfs_file_splice_read_invis,
- .splice_write = xfs_file_splice_write_invis,
- .unlocked_ioctl = xfs_file_ioctl_invis,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = xfs_file_compat_invis_ioctl,
-#endif
- .mmap = xfs_file_mmap,
- .open = xfs_file_open,
- .release = xfs_file_release,
- .fsync = xfs_file_fsync,
-};
-
-
const struct file_operations xfs_dir_file_operations = {
.read = generic_read_dir,
.readdir = xfs_file_readdir,
Index: linux-2.6/fs/xfs/linux-2.6/xfs_iops.h
===================================================================
--- linux-2.6.orig/fs/xfs/linux-2.6/xfs_iops.h 2008-11-28 16:08:37.000000000 +0530
+++ linux-2.6/fs/xfs/linux-2.6/xfs_iops.h 2008-11-28 16:08:42.000000000 +0530
@@ -22,7 +22,6 @@ struct xfs_inode;
extern const struct file_operations xfs_file_operations;
extern const struct file_operations xfs_dir_file_operations;
-extern const struct file_operations xfs_invis_file_operations;
extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);Al Viro
maintainerQuoted 7 lines · Christoph Hellwig
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Instead of doing directly assignment of file operations that set an internal flag for it add a new
FMODE_INVISIBLEflag that we can check in the normal file operations.
Seeing that it's similar to O_NOATIME, why not do it in O_... space?
Quoted 10 lines · Al Viro
Quoted 7 lines · Christoph Hellwig
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Instead of doing directly assignment of file operations that set an internal flag for it add a new
FMODE_INVISIBLEflag that we can check in the normal file operations.Seeing that it's similar to
O_NOATIME, why not do it in O_... space?
For now I just want to get rid of the horrible hack in XFS. Adding this as a user-visible feature might be a good idea that those who need it can submit.
Quoted 10 lines · Christoph Hellwig
Quoted 9 lines · Al Viro
Quoted 7 lines · Christoph Hellwig
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Instead of doing directly assignment of file operations that set an internal flag for it add a new
FMODE_INVISIBLEflag that we can check in the normal file operations.
Quoted 5 lines
Quoted 1 line
Seeing that it's similar to
O_NOATIME, why not do it in O_... space?For now I just want to get rid of the horrible hack in XFS. Adding this as a user-visible feature might be a good idea that those who need it can submit.
Taking about that submission, any chance I could just put in this with a flag allocated high enough to not clash in the XFS tree and then sort out things once the vfs and xfs trees get merged for 2.6.29? That's help making progress on the XFS side a lot, as there would be tons of merge conflicts there othwerwise. (compat_ioctl handling just got a big rework, touch just 2/3s of the hunks of this patch)
Quoted 7 lines · Christoph Hellwig
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Instead of doing directly assignment of file operations that set an internal flag for it add a new
FMODE_INVISIBLEflag that we can check in the normal file operations.
Why not call this "FMODE_NOCMTIME" similar to the inode flag "S_NOCMTIME" that already exists, and . That makes it more clear what is being done, instead of calling it "INVISIBLE".
It should also not be possible to skip ctime updates for non-root users, as that provides some forensic trail if files have been modified by users. Not sure if that is relevant here though (it looks like this is only used internally), but worth mentioning in any case.
Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.
Quoted 5 lines · Andreas Dilger
Quoted 4 lines · Christoph Hellwig
XFS has a mode called invisble I/O that doesn't update any of the timestamps. It's used for HSM-style applications and exposed through the nasty open by handle ioctl.
Quoted 7 lines
Quoted 3 lines
Instead of doing directly assignment of file operations that set an internal flag for it add a new
FMODE_INVISIBLEflag that we can check in the normal file operations.Why not call this "
FMODE_NOCMTIME" similar to the inode flag "S_NOCMTIME" that already exists, and . That makes it more clear what is being done, instead of calling it "INVISIBLE".
The flag is called invisible inside XFS because it also has the implication of not sending HSM notification when you have dmapi enabled. Doesn't matter too much on mainline, but for now I'd keep the semantics the same as the old one, at least as long as it's not exposed to userland (which Al's suggestions of doing it in the O_ namespace would)
Quoted 4 lines
It should also not be possible to skip ctime updates for non-root users, as that provides some forensic trail if files have been modified by users. Not sure if that is relevant here though (it looks like this is only used internally), but worth mentioning in any case.
Yes, the open by handle ioctl which sets this flag requires CAP_SYS_ADMIN.