|
@@ -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.
|
|
|
*
|