[PATCH 1/4] fs: fcntl add set_flags wrapper -v2

From: Dmitry Monakhov
Date: Sat Oct 18 2014 - 11:24:44 EST


fcntl(F_SETFL) performs direct f_flags manipulation which may be not be suitable
for some filesytems (mostly stack-fs like ecryptfs, unionfs, etc)
For example O_DIRECT toggling may require some actions (page cache flush)
Let's introduce new ->set_flags() callback for that purpose. This callback
is responsible for flags check so ->check_flags() no longer needed.

changes from v1:
- add generic_file_set_flags helper

Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
---
fs/bad_inode.c | 4 ++--
fs/fcntl.c | 14 ++++----------
fs/nfs/dir.c | 5 ++---
fs/nfs/file.c | 12 ++++++++----
fs/nfs/internal.h | 2 +-
fs/nfs/nfs4file.c | 2 +-
include/linux/fs.h | 10 +++++++++-
7 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index afd2b44..1977f10 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -121,7 +121,7 @@ static unsigned long bad_file_get_unmapped_area(struct file *file,
return -EIO;
}

-static int bad_file_check_flags(int flags)
+static int bad_file_set_flags(struct file *file, int flags)
{
return -EIO;
}
@@ -166,7 +166,7 @@ static const struct file_operations bad_file_ops =
.lock = bad_file_lock,
.sendpage = bad_file_sendpage,
.get_unmapped_area = bad_file_get_unmapped_area,
- .check_flags = bad_file_check_flags,
+ .set_flags = bad_file_set_flags,
.flock = bad_file_flock,
.splice_write = bad_file_splice_write,
.splice_read = bad_file_splice_read,
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 22d1c3d..2c1b3d7 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -27,8 +27,6 @@
#include <asm/siginfo.h>
#include <asm/uaccess.h>

-#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
-
static int setfl(int fd, struct file * filp, unsigned long arg)
{
struct inode * inode = file_inode(filp);
@@ -57,11 +55,6 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
return -EINVAL;
}

- if (filp->f_op->check_flags)
- error = filp->f_op->check_flags(arg);
- if (error)
- return error;
-
/*
* ->fasync() is responsible for setting the FASYNC bit.
*/
@@ -72,10 +65,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
if (error > 0)
error = 0;
}
- spin_lock(&filp->f_lock);
- filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
- spin_unlock(&filp->f_lock);

+ if (filp->f_op && filp->f_op->set_flags)
+ error = filp->f_op->set_flags(filp, arg);
+ else
+ generic_file_set_flags(filp, arg);
out:
return error;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 06e8cfc..8b5d9dc 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1480,9 +1480,8 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
dfprintk(VFS, "NFS: atomic_open(%s/%lu), %pd\n",
dir->i_sb->s_id, dir->i_ino, dentry);

- err = nfs_check_flags(open_flags);
- if (err)
- return err;
+ if ((open_flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
+ return -EINVAL;

/* NFS only supports OPEN on regular files */
if ((open_flags & O_DIRECTORY)) {
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 524dd80..b68d272 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -48,14 +48,18 @@ static const struct vm_operations_struct nfs_file_vm_ops;
# define IS_SWAPFILE(inode) (0)
#endif

-int nfs_check_flags(int flags)
+#define NFS_FL_MASK (O_NONBLOCK | O_NDELAY | O_NOATIME)
+int nfs_set_flags(struct file *filp, int flags)
{
if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
return -EINVAL;

+ spin_lock(&filp->f_lock);
+ filp->f_flags = (flags & NFS_FL_MASK) | (filp->f_flags & ~NFS_FL_MASK);
+ spin_unlock(&filp->f_lock);
return 0;
}
-EXPORT_SYMBOL_GPL(nfs_check_flags);
+EXPORT_SYMBOL_GPL(nfs_set_flags);

/*
* Open file
@@ -68,7 +72,7 @@ nfs_file_open(struct inode *inode, struct file *filp)
dprintk("NFS: open file(%pD2)\n", filp);

nfs_inc_stats(inode, NFSIOS_VFSOPEN);
- res = nfs_check_flags(filp->f_flags);
+ res = nfs_set_flags(filp, filp->f_flags);
if (res)
return res;

@@ -917,7 +921,7 @@ const struct file_operations nfs_file_operations = {
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
- .check_flags = nfs_check_flags,
+ .set_flags = nfs_set_flags,
.setlease = nfs_setlease,
};
EXPORT_SYMBOL_GPL(nfs_file_operations);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9056622..00cf588 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -345,7 +345,7 @@ ssize_t nfs_file_write(struct kiocb *, struct iov_iter *);
int nfs_file_release(struct inode *, struct file *);
int nfs_lock(struct file *, int, struct file_lock *);
int nfs_flock(struct file *, int, struct file_lock *);
-int nfs_check_flags(int);
+int nfs_set_flags(struct file *file, int flags);
int nfs_setlease(struct file *, long, struct file_lock **);

/* inode.c */
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index a816f06..cc192f4 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -130,6 +130,6 @@ const struct file_operations nfs4_file_operations = {
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
- .check_flags = nfs_check_flags,
+ .set_flags = nfs_set_flags,
.setlease = nfs_setlease,
};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9214836..4ce1414 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -944,6 +944,14 @@ struct file_lock {
#endif

#include <linux/fcntl.h>
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
+
+static inline void generic_file_set_flags(struct file *filp, unsigned arg)
+{
+ spin_lock(&filp->f_lock);
+ filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
+ spin_unlock(&filp->f_lock);
+}

extern void send_sigio(struct fown_struct *fown, int fd, int band);

@@ -1502,7 +1510,7 @@ struct file_operations {
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
- int (*check_flags)(int);
+ int (*set_flags)(struct file *, unsigned);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
--
1.7.1

--
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/