mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
c22fa3acbc
commit
980802e311
|
@ -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.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue