NFS client bugfixes for Linux 4.0
Highlights include: - Fix a regression in the NFSv4 open state recovery code - Fix a regression in the NFSv4 close code - Fix regressions and side-effects of the loop-back mounted NFS fixes in 3.18, that cause the NFS read() syscall to return EBUSY. - Fix regressions around the readdirplus code and how it interacts with the VFS lazy unmount changes that went into v3.18. - Fix issues with out-of-order RPC call replies replacing updated attributes with stale ones (particularly after a truncate()). - Fix an underflow checking issue with RPC/RDMA credits - Fix a number of issues with the NFSv4 delegation return/free code. - Fix issues around stale NFSv4.1 leases when doing a mount -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJU+SJ6AAoJEGcL54qWCgDyVgQQAKNsF/O2O9ip2uAHZRZvM6TS Ev8c3Spj/FmRI1tlCcGi1zZ8uCSwvPQz3uAN0vOTMocUWjokT5sAgN5yBIxHasem 6YK7jxs9WHiP7MGyReaAFJwG/W6LZndnlNqPWPs9KiaWwKVXIsQ3uFm/Y0lr90Fi ew16DQm0DUd4Yvv42WJR9ay7UwUPvT7wmaGIVVK2hjQqr2lx02jspt5kfrC+vsMU OYU/0YDofb2ajs5krbah6tUHf3VDnSVrXP6if66IrukCM9S4AvowpnMJQ5QJALh+ cPlqHDm2ZzuIecpqZEgYLM73wQ2q+KBXTlDLcgYg6LjnqBEivwO9RDn6tfCwKTcS tCFohQc9iDOj9rTZ9EQlQME6u/FdxWncpxyTsMyBk7FlcLsOQRqio/FXZhbyJGuH gvIdIW3fPseijtejpYkxgabe6JL9NRvjv3SnOay7xHs9Vn4tRkFF2mkkQDZOG6HT atkxQp8kB3m9gMoeAmTLdTcJkcFdk6AKnNrcyJaa1GW4msmMuGZtq/6vayKJsBZb OIw788bDSOVpcVR+6SAC24/dutcl+WJHlSJShqvIrTKejBxPCc7IVSeg63FJsWTO sxfXdUr3wVJ1ooDFCspeBj+3zAimIq7qDmRRs85ekgEtxrgdUldhg/VwbDjvLjmb whXFpiCS7Ii0fVYtZvjz =qMB7 -----END PGP SIGNATURE----- Merge tag 'nfs-for-4.0-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: "Highlights include: - Fix a regression in the NFSv4 open state recovery code - Fix a regression in the NFSv4 close code - Fix regressions and side-effects of the loop-back mounted NFS fixes in 3.18, that cause the NFS read() syscall to return EBUSY. - Fix regressions around the readdirplus code and how it interacts with the VFS lazy unmount changes that went into v3.18. - Fix issues with out-of-order RPC call replies replacing updated attributes with stale ones (particularly after a truncate()). - Fix an underflow checking issue with RPC/RDMA credits - Fix a number of issues with the NFSv4 delegation return/free code. - Fix issues around stale NFSv4.1 leases when doing a mount" * tag 'nfs-for-4.0-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (24 commits) NFSv4.1: Clear the old state by our client id before establishing a new lease NFSv4: Fix a race in NFSv4.1 server trunking discovery NFS: Don't write enable new pages while an invalidation is proceeding NFS: Fix a regression in the read() syscall NFSv4: Ensure we skip delegations that are already being returned NFSv4: Pin the superblock while we're returning the delegation NFSv4: Ensure we honour NFS_DELEGATION_RETURNING in nfs_inode_set_delegation() NFSv4: Ensure that we don't reap a delegation that is being returned NFS: Fix stateid used for NFS v4 closes NFSv4: Don't call put_rpccred() under the rcu_read_lock() NFS: Don't require a filehandle to refresh the inode in nfs_prime_dcache() NFSv3: Use the readdir fileid as the mounted-on-fileid NFS: Don't invalidate a submounted dentry in nfs_prime_dcache() NFSv4: Set a barrier in the update_changeattr() helper NFS: Fix nfs_post_op_update_inode() to set an attribute barrier NFS: Remove size hack in nfs_inode_attrs_need_update() NFSv4: Add attribute update barriers to delegreturn and pNFS layoutcommit NFS: Add attribute update barriers to NFS writebacks NFS: Set an attribute barrier on all updates NFS: Add attribute update barriers to nfs_setattr_update_inode() ...
This commit is contained in:
commit
1b1bd56191
|
@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
|
|||
|
||||
static bool nfs_client_init_is_complete(const struct nfs_client *clp)
|
||||
{
|
||||
return clp->cl_cons_state != NFS_CS_INITING;
|
||||
return clp->cl_cons_state <= NFS_CS_READY;
|
||||
}
|
||||
|
||||
int nfs_wait_client_init_complete(const struct nfs_client *clp)
|
||||
|
|
|
@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
|
|||
clear_bit(NFS_DELEGATION_NEED_RECLAIM,
|
||||
&delegation->flags);
|
||||
spin_unlock(&delegation->lock);
|
||||
put_rpccred(oldcred);
|
||||
rcu_read_unlock();
|
||||
put_rpccred(oldcred);
|
||||
trace_nfs4_reclaim_delegation(inode, res->delegation_type);
|
||||
} else {
|
||||
/* We appear to have raced with a delegation return. */
|
||||
|
@ -370,7 +370,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
|
|||
delegation = NULL;
|
||||
goto out;
|
||||
}
|
||||
freeme = nfs_detach_delegation_locked(nfsi,
|
||||
if (test_and_set_bit(NFS_DELEGATION_RETURNING,
|
||||
&old_delegation->flags))
|
||||
goto out;
|
||||
freeme = nfs_detach_delegation_locked(nfsi,
|
||||
old_delegation, clp);
|
||||
if (freeme == NULL)
|
||||
goto out;
|
||||
|
@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
|
||||
goto out;
|
||||
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
|
||||
ret = true;
|
||||
if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
|
||||
|
@ -444,6 +449,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
|
|||
ret = true;
|
||||
spin_unlock(&delegation->lock);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -471,14 +477,20 @@ restart:
|
|||
super_list) {
|
||||
if (!nfs_delegation_need_return(delegation))
|
||||
continue;
|
||||
inode = nfs_delegation_grab_inode(delegation);
|
||||
if (inode == NULL)
|
||||
if (!nfs_sb_active(server->super))
|
||||
continue;
|
||||
inode = nfs_delegation_grab_inode(delegation);
|
||||
if (inode == NULL) {
|
||||
rcu_read_unlock();
|
||||
nfs_sb_deactive(server->super);
|
||||
goto restart;
|
||||
}
|
||||
delegation = nfs_start_delegation_return_locked(NFS_I(inode));
|
||||
rcu_read_unlock();
|
||||
|
||||
err = nfs_end_delegation_return(inode, delegation, 0);
|
||||
iput(inode);
|
||||
nfs_sb_deactive(server->super);
|
||||
if (!err)
|
||||
goto restart;
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
|
||||
|
@ -809,19 +821,30 @@ restart:
|
|||
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
|
||||
list_for_each_entry_rcu(delegation, &server->delegations,
|
||||
super_list) {
|
||||
if (test_bit(NFS_DELEGATION_RETURNING,
|
||||
&delegation->flags))
|
||||
continue;
|
||||
if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
|
||||
&delegation->flags) == 0)
|
||||
continue;
|
||||
inode = nfs_delegation_grab_inode(delegation);
|
||||
if (inode == NULL)
|
||||
if (!nfs_sb_active(server->super))
|
||||
continue;
|
||||
delegation = nfs_detach_delegation(NFS_I(inode),
|
||||
delegation, server);
|
||||
inode = nfs_delegation_grab_inode(delegation);
|
||||
if (inode == NULL) {
|
||||
rcu_read_unlock();
|
||||
nfs_sb_deactive(server->super);
|
||||
goto restart;
|
||||
}
|
||||
delegation = nfs_start_delegation_return_locked(NFS_I(inode));
|
||||
rcu_read_unlock();
|
||||
|
||||
if (delegation != NULL)
|
||||
nfs_free_delegation(delegation);
|
||||
if (delegation != NULL) {
|
||||
delegation = nfs_detach_delegation(NFS_I(inode),
|
||||
delegation, server);
|
||||
if (delegation != NULL)
|
||||
nfs_free_delegation(delegation);
|
||||
}
|
||||
iput(inode);
|
||||
nfs_sb_deactive(server->super);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
|
22
fs/nfs/dir.c
22
fs/nfs/dir.c
|
@ -408,14 +408,22 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Match file and dirent using either filehandle or fileid
|
||||
* Note: caller is responsible for checking the fsid
|
||||
*/
|
||||
static
|
||||
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
|
||||
{
|
||||
struct nfs_inode *nfsi;
|
||||
|
||||
if (dentry->d_inode == NULL)
|
||||
goto different;
|
||||
if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
|
||||
goto different;
|
||||
return 1;
|
||||
|
||||
nfsi = NFS_I(dentry->d_inode);
|
||||
if (entry->fattr->fileid == nfsi->fileid)
|
||||
return 1;
|
||||
if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
|
||||
return 1;
|
||||
different:
|
||||
return 0;
|
||||
}
|
||||
|
@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|||
struct inode *inode;
|
||||
int status;
|
||||
|
||||
if (!(entry->fattr->valid & NFS_ATTR_FATTR_FILEID))
|
||||
return;
|
||||
if (!(entry->fattr->valid & NFS_ATTR_FATTR_FSID))
|
||||
return;
|
||||
if (filename.name[0] == '.') {
|
||||
if (filename.len == 1)
|
||||
return;
|
||||
|
@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|||
|
||||
dentry = d_lookup(parent, &filename);
|
||||
if (dentry != NULL) {
|
||||
/* Is there a mountpoint here? If so, just exit */
|
||||
if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
|
||||
&entry->fattr->fsid))
|
||||
goto out;
|
||||
if (nfs_same_file(dentry, entry)) {
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
|
||||
|
|
|
@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
|
|||
iocb->ki_filp,
|
||||
iov_iter_count(to), (unsigned long) iocb->ki_pos);
|
||||
|
||||
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
|
||||
result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
|
||||
if (!result) {
|
||||
result = generic_file_read_iter(iocb, to);
|
||||
if (result > 0)
|
||||
|
@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
|
|||
dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
|
||||
filp, (unsigned long) count, (unsigned long long) *ppos);
|
||||
|
||||
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||||
res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
|
||||
if (!res) {
|
||||
res = generic_file_splice_read(filp, ppos, pipe, count, flags);
|
||||
if (res > 0)
|
||||
|
@ -372,6 +372,10 @@ start:
|
|||
nfs_wait_bit_killable, TASK_KILLABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* Wait for O_DIRECT to complete
|
||||
*/
|
||||
nfs_inode_dio_wait(mapping->host);
|
||||
|
||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||
if (!page)
|
||||
|
@ -619,6 +623,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
/* make sure the cache has finished storing the page */
|
||||
nfs_fscache_wait_on_page_write(NFS_I(inode), page);
|
||||
|
||||
wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING,
|
||||
nfs_wait_bit_killable, TASK_KILLABLE);
|
||||
|
||||
lock_page(page);
|
||||
mapping = page_file_mapping(page);
|
||||
if (mapping != inode->i_mapping)
|
||||
|
|
111
fs/nfs/inode.c
111
fs/nfs/inode.c
|
@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
|
|||
* This is a copy of the common vmtruncate, but with the locking
|
||||
* corrected to take into account the fact that NFS requires
|
||||
* inode->i_size to be updated under the inode->i_lock.
|
||||
* Note: must be called with inode->i_lock held!
|
||||
*/
|
||||
static int nfs_vmtruncate(struct inode * inode, loff_t offset)
|
||||
{
|
||||
|
@ -565,14 +566,14 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
i_size_write(inode, offset);
|
||||
/* Optimisation */
|
||||
if (offset == 0)
|
||||
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
spin_unlock(&inode->i_lock);
|
||||
truncate_pagecache(inode, offset);
|
||||
spin_lock(&inode->i_lock);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -585,10 +586,15 @@ out:
|
|||
* Note: we do this in the *proc.c in order to ensure that
|
||||
* it works for things like exclusive creates too.
|
||||
*/
|
||||
void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
|
||||
void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
|
||||
struct nfs_fattr *fattr)
|
||||
{
|
||||
/* Barrier: bump the attribute generation count. */
|
||||
nfs_fattr_set_barrier(fattr);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
NFS_I(inode)->attr_gencount = fattr->gencount;
|
||||
if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
|
||||
spin_lock(&inode->i_lock);
|
||||
if ((attr->ia_valid & ATTR_MODE) != 0) {
|
||||
int mode = attr->ia_mode & S_IALLUGO;
|
||||
mode |= inode->i_mode & ~S_IALLUGO;
|
||||
|
@ -600,12 +606,13 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
|
|||
inode->i_gid = attr->ia_gid;
|
||||
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
|
||||
| NFS_INO_INVALID_ACL);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
if ((attr->ia_valid & ATTR_SIZE) != 0) {
|
||||
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
|
||||
nfs_vmtruncate(inode, attr->ia_size);
|
||||
}
|
||||
nfs_update_inode(inode, fattr);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
|
||||
|
||||
|
@ -1028,6 +1035,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
|
|||
|
||||
if (mapping->nrpages != 0) {
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
unmap_mapping_range(mapping, 0, 0, 0);
|
||||
ret = nfs_sync_mapping(mapping);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -1060,11 +1068,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
|
|||
}
|
||||
|
||||
/**
|
||||
* nfs_revalidate_mapping - Revalidate the pagecache
|
||||
* __nfs_revalidate_mapping - Revalidate the pagecache
|
||||
* @inode - pointer to host inode
|
||||
* @mapping - pointer to mapping
|
||||
* @may_lock - take inode->i_mutex?
|
||||
*/
|
||||
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
|
||||
static int __nfs_revalidate_mapping(struct inode *inode,
|
||||
struct address_space *mapping,
|
||||
bool may_lock)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
unsigned long *bitlock = &nfsi->flags;
|
||||
|
@ -1113,7 +1124,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
|
|||
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
|
||||
spin_unlock(&inode->i_lock);
|
||||
trace_nfs_invalidate_mapping_enter(inode);
|
||||
ret = nfs_invalidate_mapping(inode, mapping);
|
||||
if (may_lock) {
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = nfs_invalidate_mapping(inode, mapping);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
} else
|
||||
ret = nfs_invalidate_mapping(inode, mapping);
|
||||
trace_nfs_invalidate_mapping_exit(inode, ret);
|
||||
|
||||
clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
|
||||
|
@ -1123,6 +1139,29 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_revalidate_mapping - Revalidate the pagecache
|
||||
* @inode - pointer to host inode
|
||||
* @mapping - pointer to mapping
|
||||
*/
|
||||
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
|
||||
{
|
||||
return __nfs_revalidate_mapping(inode, mapping, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_revalidate_mapping_protected - Revalidate the pagecache
|
||||
* @inode - pointer to host inode
|
||||
* @mapping - pointer to mapping
|
||||
*
|
||||
* Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
|
||||
* while invalidating the mapping.
|
||||
*/
|
||||
int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
|
||||
{
|
||||
return __nfs_revalidate_mapping(inode, mapping, true);
|
||||
}
|
||||
|
||||
static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
@ -1231,13 +1270,6 @@ static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fat
|
|||
return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
|
||||
}
|
||||
|
||||
static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
|
||||
{
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
|
||||
return 0;
|
||||
return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
|
||||
}
|
||||
|
||||
static atomic_long_t nfs_attr_generation_counter;
|
||||
|
||||
static unsigned long nfs_read_attr_generation_counter(void)
|
||||
|
@ -1249,6 +1281,7 @@ unsigned long nfs_inc_attr_generation_counter(void)
|
|||
{
|
||||
return atomic_long_inc_return(&nfs_attr_generation_counter);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter);
|
||||
|
||||
void nfs_fattr_init(struct nfs_fattr *fattr)
|
||||
{
|
||||
|
@ -1260,6 +1293,22 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_fattr_init);
|
||||
|
||||
/**
|
||||
* nfs_fattr_set_barrier
|
||||
* @fattr: attributes
|
||||
*
|
||||
* Used to set a barrier after an attribute was updated. This
|
||||
* barrier ensures that older attributes from RPC calls that may
|
||||
* have raced with our update cannot clobber these new values.
|
||||
* Note that you are still responsible for ensuring that other
|
||||
* operations which change the attribute on the server do not
|
||||
* collide.
|
||||
*/
|
||||
void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
|
||||
{
|
||||
fattr->gencount = nfs_inc_attr_generation_counter();
|
||||
}
|
||||
|
||||
struct nfs_fattr *nfs_alloc_fattr(void)
|
||||
{
|
||||
struct nfs_fattr *fattr;
|
||||
|
@ -1370,7 +1419,6 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
|
|||
|
||||
return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
|
||||
nfs_ctime_need_update(inode, fattr) ||
|
||||
nfs_size_need_update(inode, fattr) ||
|
||||
((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
|
||||
}
|
||||
|
||||
|
@ -1460,6 +1508,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
int status;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
nfs_fattr_set_barrier(fattr);
|
||||
status = nfs_post_op_update_inode_locked(inode, fattr);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
|
@ -1468,7 +1517,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
|
||||
|
||||
/**
|
||||
* nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
|
||||
* nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
|
||||
* @inode - pointer to inode
|
||||
* @fattr - updated attributes
|
||||
*
|
||||
|
@ -1478,11 +1527,10 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
|
|||
*
|
||||
* This function is mainly designed to be used by the ->write_done() functions.
|
||||
*/
|
||||
int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
|
||||
int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
int status;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
/* Don't do a WCC update if these attributes are already stale */
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
|
||||
!nfs_inode_attrs_need_update(inode, fattr)) {
|
||||
|
@ -1514,6 +1562,27 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
|
|||
}
|
||||
out_noforce:
|
||||
status = nfs_post_op_update_inode_locked(inode, fattr);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
|
||||
* @inode - pointer to inode
|
||||
* @fattr - updated attributes
|
||||
*
|
||||
* After an operation that has changed the inode metadata, mark the
|
||||
* attribute cache as being invalid, then try to update it. Fake up
|
||||
* weak cache consistency data, if none exist.
|
||||
*
|
||||
* This function is mainly designed to be used by the ->write_done() functions.
|
||||
*/
|
||||
int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
int status;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
nfs_fattr_set_barrier(fattr);
|
||||
status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
|
||||
spin_unlock(&inode->i_lock);
|
||||
return status;
|
||||
}
|
||||
|
@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
|
||||
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
||||
nfsi->attrtimeo_timestamp = now;
|
||||
/* Set barrier to be more recent than all outstanding updates */
|
||||
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
|
||||
} else {
|
||||
if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
|
||||
|
@ -1722,6 +1792,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
|
||||
nfsi->attrtimeo_timestamp = now;
|
||||
}
|
||||
/* Set the barrier to be more recent than this fattr */
|
||||
if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
|
||||
nfsi->attr_gencount = fattr->gencount;
|
||||
}
|
||||
invalid &= ~NFS_INO_INVALID_ATTR;
|
||||
/* Don't invalidate the data if we were to blame */
|
||||
|
|
|
@ -459,6 +459,7 @@ void nfs_mark_request_commit(struct nfs_page *req,
|
|||
struct nfs_commit_info *cinfo,
|
||||
u32 ds_commit_idx);
|
||||
int nfs_write_need_commit(struct nfs_pgio_header *);
|
||||
void nfs_writeback_update_inode(struct nfs_pgio_header *hdr);
|
||||
int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
|
||||
int how, struct nfs_commit_info *cinfo);
|
||||
void nfs_retry_commit(struct list_head *page_list,
|
||||
|
|
|
@ -138,7 +138,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
nfs_fattr_init(fattr);
|
||||
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
|
||||
if (status == 0)
|
||||
nfs_setattr_update_inode(inode, sattr);
|
||||
nfs_setattr_update_inode(inode, sattr, fattr);
|
||||
dprintk("NFS reply setattr: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
@ -834,7 +834,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
|
|||
if (nfs3_async_handle_jukebox(task, inode))
|
||||
return -EAGAIN;
|
||||
if (task->tk_status >= 0)
|
||||
nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
|
||||
nfs_writeback_update_inode(hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1987,6 +1987,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
|||
if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
|
||||
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
|
||||
|
||||
if (entry->fattr->fileid != entry->ino) {
|
||||
entry->fattr->mounted_on_fileid = entry->ino;
|
||||
entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
|
||||
}
|
||||
|
||||
/* In fact, a post_op_fh3: */
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(p == NULL))
|
||||
|
|
|
@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new,
|
|||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
|
||||
|
||||
if (pos == new)
|
||||
goto found;
|
||||
|
||||
if (pos->rpc_ops != new->rpc_ops)
|
||||
continue;
|
||||
|
||||
|
@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
|
|||
prev = pos;
|
||||
|
||||
status = nfs_wait_client_init_complete(pos);
|
||||
if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
|
||||
nfs4_schedule_lease_recovery(pos);
|
||||
status = nfs4_wait_clnt_recover(pos);
|
||||
}
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
|
|||
*/
|
||||
if (!nfs4_match_client_owner_id(pos, new))
|
||||
continue;
|
||||
|
||||
found:
|
||||
atomic_inc(&pos->cl_count);
|
||||
*result = pos;
|
||||
status = 0;
|
||||
|
|
|
@ -901,6 +901,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
|
|||
if (!cinfo->atomic || cinfo->before != dir->i_version)
|
||||
nfs_force_lookup_revalidate(dir);
|
||||
dir->i_version = cinfo->after;
|
||||
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
|
||||
nfs_fscache_invalidate(dir);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
|
@ -1552,6 +1553,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
|
|||
|
||||
opendata->o_arg.open_flags = 0;
|
||||
opendata->o_arg.fmode = fmode;
|
||||
opendata->o_arg.share_access = nfs4_map_atomic_open_share(
|
||||
NFS_SB(opendata->dentry->d_sb),
|
||||
fmode, 0);
|
||||
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
|
||||
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
|
||||
nfs4_init_opendata_res(opendata);
|
||||
|
@ -2413,8 +2417,8 @@ static int _nfs4_do_open(struct inode *dir,
|
|||
opendata->o_res.f_attr, sattr,
|
||||
state, label, olabel);
|
||||
if (status == 0) {
|
||||
nfs_setattr_update_inode(state->inode, sattr);
|
||||
nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
|
||||
nfs_setattr_update_inode(state->inode, sattr,
|
||||
opendata->o_res.f_attr);
|
||||
nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
|
||||
}
|
||||
}
|
||||
|
@ -2651,7 +2655,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|||
case -NFS4ERR_BAD_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
if (!nfs4_stateid_match(&calldata->arg.stateid,
|
||||
&state->stateid)) {
|
||||
&state->open_stateid)) {
|
||||
rpc_restart_call_prepare(task);
|
||||
goto out_release;
|
||||
}
|
||||
|
@ -2687,7 +2691,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||
is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
|
||||
is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
|
||||
is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
|
||||
nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid);
|
||||
nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
|
||||
/* Calculate the change in open mode */
|
||||
calldata->arg.fmode = 0;
|
||||
if (state->n_rdwr == 0) {
|
||||
|
@ -3288,7 +3292,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
|
||||
status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
|
||||
if (status == 0) {
|
||||
nfs_setattr_update_inode(inode, sattr);
|
||||
nfs_setattr_update_inode(inode, sattr, fattr);
|
||||
nfs_setsecurity(inode, fattr, label);
|
||||
}
|
||||
nfs4_label_free(label);
|
||||
|
@ -4234,7 +4238,7 @@ static int nfs4_write_done_cb(struct rpc_task *task,
|
|||
}
|
||||
if (task->tk_status >= 0) {
|
||||
renew_lease(NFS_SERVER(inode), hdr->timestamp);
|
||||
nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr);
|
||||
nfs_writeback_update_inode(hdr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -6893,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
|
|||
|
||||
if (status == 0) {
|
||||
clp->cl_clientid = res.clientid;
|
||||
clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
|
||||
if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
|
||||
clp->cl_exchange_flags = res.flags;
|
||||
/* Client ID is not confirmed */
|
||||
if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
|
||||
clear_bit(NFS4_SESSION_ESTABLISHED,
|
||||
&clp->cl_session->session_state);
|
||||
clp->cl_seqid = res.seqid;
|
||||
}
|
||||
|
||||
kfree(clp->cl_serverowner);
|
||||
clp->cl_serverowner = res.server_owner;
|
||||
|
@ -7227,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session,
|
|||
struct nfs41_create_session_res *res)
|
||||
{
|
||||
nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
|
||||
/* Mark client id and session as being confirmed */
|
||||
session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
|
||||
set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
|
||||
session->flags = res->flags;
|
||||
memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
|
||||
if (res->flags & SESSION4_BACK_CHAN)
|
||||
|
@ -7322,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
|
|||
dprintk("--> nfs4_proc_destroy_session\n");
|
||||
|
||||
/* session is still being setup */
|
||||
if (session->clp->cl_cons_state != NFS_CS_READY)
|
||||
return status;
|
||||
if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
|
||||
return 0;
|
||||
|
||||
status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
|
||||
trace_nfs4_destroy_session(session->clp, status);
|
||||
|
|
|
@ -70,6 +70,7 @@ struct nfs4_session {
|
|||
|
||||
enum nfs4_session_state {
|
||||
NFS4_SESSION_INITING,
|
||||
NFS4_SESSION_ESTABLISHED,
|
||||
};
|
||||
|
||||
extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
|
||||
|
|
|
@ -346,9 +346,23 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
|
|||
status = nfs4_proc_exchange_id(clp, cred);
|
||||
if (status != NFS4_OK)
|
||||
return status;
|
||||
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||
|
||||
return nfs41_walk_client_list(clp, result, cred);
|
||||
status = nfs41_walk_client_list(clp, result, cred);
|
||||
if (status < 0)
|
||||
return status;
|
||||
if (clp != *result)
|
||||
return 0;
|
||||
|
||||
/* Purge state if the client id was established in a prior instance */
|
||||
if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
|
||||
set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
|
||||
else
|
||||
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||
nfs4_schedule_state_manager(clp);
|
||||
status = nfs_wait_client_init_complete(clp);
|
||||
if (status < 0)
|
||||
nfs_put_client(clp);
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
|
|
@ -139,7 +139,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
nfs_fattr_init(fattr);
|
||||
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
|
||||
if (status == 0)
|
||||
nfs_setattr_update_inode(inode, sattr);
|
||||
nfs_setattr_update_inode(inode, sattr, fattr);
|
||||
dprintk("NFS reply setattr: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
@ -609,10 +609,8 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,
|
|||
|
||||
static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
|
||||
{
|
||||
struct inode *inode = hdr->inode;
|
||||
|
||||
if (task->tk_status >= 0)
|
||||
nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
|
||||
nfs_writeback_update_inode(hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1377,6 +1377,36 @@ static int nfs_should_remove_suid(const struct inode *inode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
|
||||
struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_pgio_args *argp = &hdr->args;
|
||||
struct nfs_pgio_res *resp = &hdr->res;
|
||||
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
|
||||
return;
|
||||
if (argp->offset + resp->count != fattr->size)
|
||||
return;
|
||||
if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
|
||||
return;
|
||||
/* Set attribute barrier */
|
||||
nfs_fattr_set_barrier(fattr);
|
||||
}
|
||||
|
||||
void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
struct nfs_fattr *fattr = hdr->res.fattr;
|
||||
struct inode *inode = hdr->inode;
|
||||
|
||||
if (fattr == NULL)
|
||||
return;
|
||||
spin_lock(&inode->i_lock);
|
||||
nfs_writeback_check_extend(hdr, fattr);
|
||||
nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_writeback_update_inode);
|
||||
|
||||
/*
|
||||
* This function is called when the WRITE call is complete.
|
||||
*/
|
||||
|
|
|
@ -343,6 +343,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
|
|||
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
|
||||
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
|
||||
extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
|
||||
|
@ -355,8 +356,9 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
|
|||
extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
|
||||
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
|
||||
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
|
||||
extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
|
||||
extern int nfs_setattr(struct dentry *, struct iattr *);
|
||||
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
|
||||
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
|
||||
extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
|
||||
struct nfs4_label *label);
|
||||
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
|
||||
|
@ -369,6 +371,7 @@ extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ct
|
|||
extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
|
||||
extern u64 nfs_compat_user_ino64(u64 fileid);
|
||||
extern void nfs_fattr_init(struct nfs_fattr *fattr);
|
||||
extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr);
|
||||
extern unsigned long nfs_inc_attr_generation_counter(void);
|
||||
|
||||
extern struct nfs_fattr *nfs_alloc_fattr(void);
|
||||
|
|
|
@ -738,8 +738,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
|
|||
struct rpc_xprt *xprt = rep->rr_xprt;
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
|
||||
__be32 *iptr;
|
||||
int credits, rdmalen, status;
|
||||
int rdmalen, status;
|
||||
unsigned long cwnd;
|
||||
u32 credits;
|
||||
|
||||
/* Check status. If bad, signal disconnect and return rep to pool */
|
||||
if (rep->rr_len == ~0U) {
|
||||
|
|
|
@ -285,7 +285,7 @@ rpcr_to_rdmar(struct rpc_rqst *rqst)
|
|||
*/
|
||||
struct rpcrdma_buffer {
|
||||
spinlock_t rb_lock; /* protects indexes */
|
||||
int rb_max_requests;/* client max requests */
|
||||
u32 rb_max_requests;/* client max requests */
|
||||
struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */
|
||||
struct list_head rb_all;
|
||||
int rb_send_index;
|
||||
|
|
Loading…
Reference in a new issue