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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux