[PATCH] VFS: pass the flag setting by fcntl() to vfs

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

 



VFS: pass the flag setting by fcntl() to vfs

Several flags such as O_NONBLOCK are set using the fcntl() system call.
Currently the flags are validated in setfl() by the vfs using the
"check_flags" operation, but the eventual setting is not passed to the
vfs.

We have an application that uses the vfs/fuse and the flag O_NONBLOCK
is critical for the application.

This patch extends the "check_flags" function so that the flags are
passed to the vfs layer for setting in addition to validating. More
specifically:

  o add additional parameters to "check_flags", one for the file pointer,
    and one for setting. Also change the "flags" parameter from "int" to
    "unsigned int" to make it consistent with "filp->f_flags".

  o in setfl() pass the flags to vfs for setting once the flags are
    set correctly in the kernel.

  o use the "check_flags" operation in ioctl_fionbio() also for
    ioctl(fd, FIONOIO, &on).

  o make necessary adjustments to several files in fs/nfs (NFS is the
    only module using "check_flags").

Signed-off-by: Enke Chen <enkechen@xxxxxxxxx>

Version: 4.6.0_rc6_next_20160503

 Documentation/filesystems/Locking |    2 +-
 Documentation/filesystems/vfs.txt |    2 +-
 fs/fcntl.c                        |   10 +++++++++-
 fs/ioctl.c                        |    9 +++++++++
 fs/nfs/dir.c                      |    2 +-
 fs/nfs/file.c                     |    7 +++++--
 fs/nfs/internal.h                 |    2 +-
 fs/nfs/nfs4file.c                 |    2 +-
 include/linux/fs.h                |    2 +-
 9 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 75eea7c..c1cf807 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -452,7 +452,7 @@ prototypes:
 			loff_t *, int);
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long,
 			unsigned long, unsigned long, unsigned long);
-	int (*check_flags)(int);
+	int (*check_flags)(unsigned int, struct file *, int);
 	int (*flock) (struct file *, int, struct file_lock *);
 	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
 			size_t, unsigned int);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index c61a223..193ee19 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -822,7 +822,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 (*check_flags)(unsigned int, struct file *, int);
 	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);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 350a2c8..5582dc8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -32,6 +32,7 @@
 static int setfl(int fd, struct file * filp, unsigned long arg)
 {
 	struct inode * inode = file_inode(filp);
+	unsigned int flags;
 	int error = 0;
 
 	/*
@@ -59,7 +60,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 	}
 
 	if (filp->f_op->check_flags)
-		error = filp->f_op->check_flags(arg);
+		error = filp->f_op->check_flags(arg, filp, 0);
 	if (error)
 		return error;
 
@@ -75,8 +76,15 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 	}
 	spin_lock(&filp->f_lock);
 	filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
+	flags = filp->f_flags;
 	spin_unlock(&filp->f_lock);
 
+	/*
+	 * Pass the flags to VFS for setting.
+	 */
+	if (filp->f_op->check_flags)
+		error = filp->f_op->check_flags(flags, filp, 1);
+
  out:
 	return error;
 }
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 116a333..de06d93 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -496,6 +496,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
 static int ioctl_fionbio(struct file *filp, int __user *argp)
 {
 	unsigned int flag;
+	unsigned int setfl;
 	int on, error;
 
 	error = get_user(on, argp);
@@ -512,7 +513,15 @@ static int ioctl_fionbio(struct file *filp, int __user *argp)
 		filp->f_flags |= flag;
 	else
 		filp->f_flags &= ~flag;
+	setfl = filp->f_flags;
 	spin_unlock(&filp->f_lock);
+
+	/*
+	 * Do the same as in fcntl().
+	 */
+	if (filp->f_op->check_flags)
+		error = filp->f_op->check_flags(setfl, filp, 1);
+
 	return error;
 }
 
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index aaf7bd0..e16de49 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1495,7 +1495,7 @@ 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);
+	err = nfs_check_flags(open_flags, file, 0);
 	if (err)
 		return err;
 
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 717a8d6..d049929 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -48,8 +48,11 @@ static const struct vm_operations_struct nfs_file_vm_ops;
 # define IS_SWAPFILE(inode)	(0)
 #endif
 
-int nfs_check_flags(int flags)
+int nfs_check_flags(unsigned int flags, struct file *filp, int setting)
 {
+	if (setting)
+		return 0;
+
 	if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
 		return -EINVAL;
 
@@ -68,7 +71,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_check_flags(filp->f_flags, filp, 0);
 	if (res)
 		return res;
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index f1d1d2c..0916d99 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -368,7 +368,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_check_flags(unsigned int, struct file *, int);
 
 /* inode.c */
 extern struct workqueue_struct *nfsiod_workqueue;
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index d039051..7ae0d15 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -44,7 +44,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
 
 	dprintk("NFS: open file(%pd2)\n", dentry);
 
-	err = nfs_check_flags(openflags);
+	err = nfs_check_flags(openflags, filp, 0);
 	if (err)
 		return err;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d61cd08..fdc9cc9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1717,7 +1717,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 (*check_flags)(unsigned int, struct file *, int);
 	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);
--
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