aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-13 11:14:01 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-13 13:33:02 -0400
commit980802e311088fda56c16650589faa4597c695fb (patch)
tree37092823ea5ad1203253ee5e54e7c9631df4087d
parentc22fa3acbc2ef79ea57217643f6cd6d226963069 (diff)
[PATCH] NFS: Ensure that we revalidate the cached file length for llseek(SEEK_END)
This fixes a data corruption error for mail delivery applications that expect to be able to do posix locking and then append writes on NFS. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfs/file.c42
1 files changed, 41 insertions, 1 deletions
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 @@
37 37
38static int nfs_file_open(struct inode *, struct file *); 38static int nfs_file_open(struct inode *, struct file *);
39static int nfs_file_release(struct inode *, struct file *); 39static int nfs_file_release(struct inode *, struct file *);
40static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
40static int nfs_file_mmap(struct file *, struct vm_area_struct *); 41static int nfs_file_mmap(struct file *, struct vm_area_struct *);
41static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); 42static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
42static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); 43static 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);
48static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); 49static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
49 50
50struct file_operations nfs_file_operations = { 51struct file_operations nfs_file_operations = {
51 .llseek = remote_llseek, 52 .llseek = nfs_file_llseek,
52 .read = do_sync_read, 53 .read = do_sync_read,
53 .write = do_sync_write, 54 .write = do_sync_write,
54 .aio_read = nfs_file_read, 55 .aio_read = nfs_file_read,
@@ -114,6 +115,45 @@ nfs_file_release(struct inode *inode, struct file *filp)
114 return NFS_PROTO(inode)->file_release(inode, filp); 115 return NFS_PROTO(inode)->file_release(inode, filp);
115} 116}
116 117
118/**
119 * nfs_revalidate_size - Revalidate the file size
120 * @inode - pointer to inode struct
121 * @file - pointer to struct file
122 *
123 * Revalidates the file length. This is basically a wrapper around
124 * nfs_revalidate_inode() that takes into account the fact that we may
125 * have cached writes (in which case we don't care about the server's
126 * idea of what the file length is), or O_DIRECT (in which case we
127 * shouldn't trust the cache).
128 */
129static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
130{
131 struct nfs_server *server = NFS_SERVER(inode);
132 struct nfs_inode *nfsi = NFS_I(inode);
133
134 if (server->flags & NFS_MOUNT_NOAC)
135 goto force_reval;
136 if (filp->f_flags & O_DIRECT)
137 goto force_reval;
138 if (nfsi->npages != 0)
139 return 0;
140 return nfs_revalidate_inode(server, inode);
141force_reval:
142 return __nfs_revalidate_inode(server, inode);
143}
144
145static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
146{
147 /* origin == SEEK_END => we must revalidate the cached file length */
148 if (origin == 2) {
149 struct inode *inode = filp->f_mapping->host;
150 int retval = nfs_revalidate_file_size(inode, filp);
151 if (retval < 0)
152 return (loff_t)retval;
153 }
154 return remote_llseek(filp, offset, origin);
155}
156
117/* 157/*
118 * Flush all dirty pages, and check for write errors. 158 * Flush all dirty pages, and check for write errors.
119 * 159 *