Discussion:
[PATCH 1/3] fs: fcntl add set_flags wrapper
Dmitry Monakhov
2014-10-10 16:29:34 UTC
Permalink
fcntl(F_SETFL) performs direct manipulation f_flags, which may be not be appropriate
for some filesytems (mostly stack-fs like FUSE, ecryptfs, unionfs, etc)
For example O_DIRECT toggling may require extra 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.

Signed-off-by: Dmitry Monakhov <***@openvz.org>
---
fs/bad_inode.c | 4 ++--
fs/fcntl.c | 18 ++++++++----------
fs/nfs/dir.c | 5 ++---
fs/nfs/file.c | 12 ++++++++----
fs/nfs/internal.h | 2 +-
fs/nfs/nfs4file.c | 2 +-
include/linux/fs.h | 3 ++-
7 files changed, 24 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..71ce217 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,15 @@ 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 {
+ spin_lock(&filp->f_lock);
+ filp->f_flags = (arg & SETFL_MASK) |
+ (filp->f_flags & ~SETFL_MASK);
+ spin_unlock(&filp->f_lock);
+ }
out:
return error;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 36d921f..a112d53 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1485,9 +1485,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 9418772..bbf40a5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -944,6 +944,7 @@ struct file_lock {
#endif

#include <linux/fcntl.h>
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)

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

@@ -1502,7 +1503,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 *, 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);
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...