.setattr = nfs_setattr,
};
+#ifdef CONFIG_NFS_V3
+struct inode_operations nfs3_file_inode_operations = {
+ .permission = nfs_permission,
+ .getattr = nfs_getattr,
+ .setattr = nfs_setattr,
+ .listxattr = nfs3_listxattr,
+ .getxattr = nfs3_getxattr,
+ .setxattr = nfs3_setxattr,
+ .removexattr = nfs3_removexattr,
+};
+#endif /* CONFIG_NFS_v3 */
+
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
return NFS_PROTO(inode)->file_release(inode, filp);
}
+/**
+ * nfs_revalidate_file - Revalidate the page cache & related metadata
+ * @inode - pointer to inode struct
+ * @file - pointer to file
+ */
+static int nfs_revalidate_file(struct inode *inode, struct file *filp)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ int retval = 0;
+
+ if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))
+ || nfs_attribute_timeout(inode))
+ retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ nfs_revalidate_mapping(inode, filp->f_mapping);
+ return 0;
+}
+
/**
* nfs_revalidate_size - Revalidate the file size
* @inode - pointer to inode struct
goto force_reval;
if (nfsi->npages != 0)
return 0;
- return nfs_revalidate_inode(server, inode);
+ if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode))
+ return 0;
force_reval:
return __nfs_revalidate_inode(server, inode);
}
if (!status) {
status = ctx->error;
ctx->error = 0;
- if (!status && !nfs_have_delegation(inode, FMODE_READ))
- __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (!status)
+ nfs_revalidate_inode(NFS_SERVER(inode), inode);
}
unlock_kernel();
return status;
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long) pos);
- result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ result = nfs_revalidate_file(inode, iocb->ki_filp);
if (!result)
result = generic_file_aio_read(iocb, buf, count, pos);
return result;
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long long) *ppos);
- res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ res = nfs_revalidate_file(inode, filp);
if (!res)
res = generic_file_sendfile(filp, ppos, count, actor, target);
return res;
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ status = nfs_revalidate_file(inode, file);
if (!status)
status = generic_file_mmap(file, vma);
return status;
result = -EBUSY;
if (IS_SWAPFILE(inode))
goto out_swapfile;
- result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
- if (result)
- goto out;
+ /*
+ * O_APPEND implies that we must revalidate the file length.
+ */
+ if (iocb->ki_filp->f_flags & O_APPEND) {
+ result = nfs_revalidate_file_size(inode, iocb->ki_filp);
+ if (result)
+ goto out;
+ }
+ nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
result = count;
if (!count)
static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
{
+ struct file_lock *cfl;
struct inode *inode = filp->f_mapping->host;
int status = 0;
lock_kernel();
- /* Use local locking if mounted with "-onolock" */
- if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
- status = NFS_PROTO(inode)->lock(filp, cmd, fl);
- else {
- struct file_lock *cfl = posix_test_lock(filp, fl);
-
- fl->fl_type = F_UNLCK;
- if (cfl != NULL)
- memcpy(fl, cfl, sizeof(*fl));
+ /* Try local locking first */
+ cfl = posix_test_lock(filp, fl);
+ if (cfl != NULL) {
+ locks_copy_lock(fl, cfl);
+ goto out;
}
+
+ if (nfs_have_delegation(inode, FMODE_READ))
+ goto out_noconflict;
+
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+ goto out_noconflict;
+
+ status = NFS_PROTO(inode)->lock(filp, cmd, fl);
+out:
unlock_kernel();
return status;
+out_noconflict:
+ fl->fl_type = F_UNLCK;
+ goto out;
}
static int do_vfs_lock(struct file *file, struct file_lock *fl)
* Flush all pending writes before doing anything
* with locks..
*/
- filemap_fdatawrite(filp->f_mapping);
- down(&inode->i_sem);
- nfs_wb_all(inode);
- up(&inode->i_sem);
- filemap_fdatawait(filp->f_mapping);
+ nfs_sync_mapping(filp->f_mapping);
/* NOTE: special case
* If we're signalled while cleaning up locks on process exit, we
* Flush all pending writes before doing anything
* with locks..
*/
- status = filemap_fdatawrite(filp->f_mapping);
- if (status == 0) {
- down(&inode->i_sem);
- status = nfs_wb_all(inode);
- up(&inode->i_sem);
- if (status == 0)
- status = filemap_fdatawait(filp->f_mapping);
- }
- if (status < 0)
+ status = nfs_sync_mapping(filp->f_mapping);
+ if (status != 0)
goto out;
lock_kernel();
* Make sure we clear the cache whenever we try to get the lock.
* This makes locking act as a cache coherency point.
*/
- filemap_fdatawrite(filp->f_mapping);
- down(&inode->i_sem);
- nfs_wb_all(inode); /* we may have slept */
- up(&inode->i_sem);
- filemap_fdatawait(filp->f_mapping);
+ nfs_sync_mapping(filp->f_mapping);
nfs_zap_caches(inode);
out:
rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
return -EINVAL;
/* No mandatory locks over NFS */
- if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
+ fl->fl_type != F_UNLCK)
return -ENOLCK;
if (IS_GETLK(cmd))