aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c49
-rw-r--r--fs/nfs/file.c42
-rw-r--r--fs/nfs/idmap.c4
-rw-r--r--fs/nfs/inode.c4
4 files changed, 80 insertions, 19 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 73f96acd5d37..ff6155f5e8d9 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -528,19 +528,39 @@ static inline void nfs_renew_times(struct dentry * dentry)
dentry->d_time = jiffies;
}
+/*
+ * Return the intent data that applies to this particular path component
+ *
+ * Note that the current set of intents only apply to the very last
+ * component of the path.
+ * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT.
+ */
+static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask)
+{
+ if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))
+ return 0;
+ return nd->flags & mask;
+}
+
+/*
+ * Inode and filehandle revalidation for lookups.
+ *
+ * We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
+ * or if the intent information indicates that we're about to open this
+ * particular file and the "nocto" mount flag is not set.
+ *
+ */
static inline
int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
{
struct nfs_server *server = NFS_SERVER(inode);
if (nd != NULL) {
- int ndflags = nd->flags;
/* VFS wants an on-the-wire revalidation */
- if (ndflags & LOOKUP_REVAL)
+ if (nd->flags & LOOKUP_REVAL)
goto out_force;
/* This is an open(2) */
- if ((ndflags & LOOKUP_OPEN) &&
- !(ndflags & LOOKUP_CONTINUE) &&
+ if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
!(server->flags & NFS_MOUNT_NOCTO))
goto out_force;
}
@@ -560,12 +580,8 @@ static inline
int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
- int ndflags = 0;
-
- if (nd)
- ndflags = nd->flags;
/* Don't revalidate a negative dentry if we're creating a new file */
- if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
+ if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
return 0;
return !nfs_check_verifier(dir, dentry);
}
@@ -700,12 +716,16 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
+/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
static inline
int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
{
if (NFS_PROTO(dir)->version == 2)
return 0;
- if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
+ if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
return 0;
return (nd->intent.open.flags & O_EXCL) != 0;
}
@@ -772,12 +792,13 @@ struct dentry_operations nfs4_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
+/*
+ * Use intent information to determine whether we need to substitute
+ * the NFSv4-style stateful OPEN for the LOOKUP call
+ */
static int is_atomic_open(struct inode *dir, struct nameidata *nd)
{
- if (!nd)
- return 0;
- /* Check that we are indeed trying to open this file */
- if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN))
+ if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
return 0;
/* NFS does not (yet) have a stateful open for directories */
if (nd->flags & LOOKUP_DIRECTORY)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f06eee6dcff5..55c907592490 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -37,6 +37,7 @@
static int nfs_file_open(struct inode *, struct file *);
static int nfs_file_release(struct inode *, struct file *);
+static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
static int nfs_file_mmap(struct file *, struct vm_area_struct *);
static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
@@ -48,7 +49,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
struct file_operations nfs_file_operations = {
- .llseek = remote_llseek,
+ .llseek = nfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = nfs_file_read,
@@ -114,6 +115,45 @@ nfs_file_release(struct inode *inode, struct file *filp)
return NFS_PROTO(inode)->file_release(inode, filp);
}
+/**
+ * nfs_revalidate_size - Revalidate the file size
+ * @inode - pointer to inode struct
+ * @file - pointer to struct file
+ *
+ * Revalidates the file length. This is basically a wrapper around
+ * nfs_revalidate_inode() that takes into account the fact that we may
+ * have cached writes (in which case we don't care about the server's
+ * idea of what the file length is), or O_DIRECT (in which case we
+ * shouldn't trust the cache).
+ */
+static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ if (server->flags & NFS_MOUNT_NOAC)
+ goto force_reval;
+ if (filp->f_flags & O_DIRECT)
+ goto force_reval;
+ if (nfsi->npages != 0)
+ return 0;
+ return nfs_revalidate_inode(server, inode);
+force_reval:
+ return __nfs_revalidate_inode(server, inode);
+}
+
+static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
+{
+ /* origin == SEEK_END => we must revalidate the cached file length */
+ if (origin == 2) {
+ struct inode *inode = filp->f_mapping->host;
+ int retval = nfs_revalidate_file_size(inode, filp);
+ if (retval < 0)
+ return (loff_t)retval;
+ }
+ return remote_llseek(filp, offset, origin);
+}
+
/*
* Flush all dirty pages, and check for write errors.
*
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index b74c4e3a64e2..87f4f9aeac86 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -79,7 +79,7 @@ static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *,
char __user *, size_t);
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
size_t);
-void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
+static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
static unsigned int fnvhash32(const void *, size_t);
@@ -434,7 +434,7 @@ out:
return ret;
}
-void
+static void
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
struct idmap_msg *im = msg->data;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6345f26e87ee..f2317f3e29f9 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1904,7 +1904,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
}
}
-int nfs_init_inodecache(void)
+static int nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
@@ -1916,7 +1916,7 @@ int nfs_init_inodecache(void)
return 0;
}
-void nfs_destroy_inodecache(void)
+static void nfs_destroy_inodecache(void)
{
if (kmem_cache_destroy(nfs_inode_cachep))
printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");