Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b1bd561 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
  ...
parents 99aedde0 e11259f9
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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)
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)
int nfs_wait_client_init_complete(const struct nfs_client *clp)
+34 −11
Original line number Original line Diff line number Diff line
@@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
			clear_bit(NFS_DELEGATION_NEED_RECLAIM,
			clear_bit(NFS_DELEGATION_NEED_RECLAIM,
				  &delegation->flags);
				  &delegation->flags);
			spin_unlock(&delegation->lock);
			spin_unlock(&delegation->lock);
			put_rpccred(oldcred);
			rcu_read_unlock();
			rcu_read_unlock();
			put_rpccred(oldcred);
			trace_nfs4_reclaim_delegation(inode, res->delegation_type);
			trace_nfs4_reclaim_delegation(inode, res->delegation_type);
		} else {
		} else {
			/* We appear to have raced with a delegation return. */
			/* We appear to have raced with a delegation return. */
@@ -370,6 +370,9 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
			delegation = NULL;
			delegation = NULL;
			goto out;
			goto out;
		}
		}
		if (test_and_set_bit(NFS_DELEGATION_RETURNING,
					&old_delegation->flags))
			goto out;
		freeme = nfs_detach_delegation_locked(nfsi,
		freeme = nfs_detach_delegation_locked(nfsi,
				old_delegation, clp);
				old_delegation, clp);
		if (freeme == NULL)
		if (freeme == NULL)
@@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
{
{
	bool ret = false;
	bool ret = false;


	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		goto out;
	if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
	if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
		ret = true;
		ret = true;
	if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
	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;
			ret = true;
		spin_unlock(&delegation->lock);
		spin_unlock(&delegation->lock);
	}
	}
out:
	return ret;
	return ret;
}
}


@@ -471,14 +477,20 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp)
								super_list) {
								super_list) {
			if (!nfs_delegation_need_return(delegation))
			if (!nfs_delegation_need_return(delegation))
				continue;
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (!nfs_sb_active(server->super))
			if (inode == NULL)
				continue;
				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));
			delegation = nfs_start_delegation_return_locked(NFS_I(inode));
			rcu_read_unlock();
			rcu_read_unlock();


			err = nfs_end_delegation_return(inode, delegation, 0);
			err = nfs_end_delegation_return(inode, delegation, 0);
			iput(inode);
			iput(inode);
			nfs_sb_deactive(server->super);
			if (!err)
			if (!err)
				goto restart;
				goto restart;
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
@@ -809,19 +821,30 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
								super_list) {
			if (test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags))
				continue;
			if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
			if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
						&delegation->flags) == 0)
						&delegation->flags) == 0)
				continue;
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (!nfs_sb_active(server->super))
			if (inode == NULL)
				continue;
				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();
			if (delegation != NULL) {
				delegation = nfs_detach_delegation(NFS_I(inode),
				delegation = nfs_detach_delegation(NFS_I(inode),
					delegation, server);
					delegation, server);
			rcu_read_unlock();

				if (delegation != NULL)
				if (delegation != NULL)
					nfs_free_delegation(delegation);
					nfs_free_delegation(delegation);
			}
			iput(inode);
			iput(inode);
			nfs_sb_deactive(server->super);
			goto restart;
			goto restart;
		}
		}
	}
	}
+19 −3
Original line number Original line Diff line number Diff line
@@ -408,13 +408,21 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
	return 0;
	return 0;
}
}


/* Match file and dirent using either filehandle or fileid
 * Note: caller is responsible for checking the fsid
 */
static
static
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
{
{
	struct nfs_inode *nfsi;

	if (dentry->d_inode == NULL)
	if (dentry->d_inode == NULL)
		goto different;
		goto different;
	if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)

		goto different;
	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;
		return 1;
different:
different:
	return 0;
	return 0;
@@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
	struct inode *inode;
	struct inode *inode;
	int status;
	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.name[0] == '.') {
		if (filename.len == 1)
		if (filename.len == 1)
			return;
			return;
@@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)


	dentry = d_lookup(parent, &filename);
	dentry = d_lookup(parent, &filename);
	if (dentry != NULL) {
	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)) {
		if (nfs_same_file(dentry, entry)) {
			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
			status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
			status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
+9 −2
Original line number Original line Diff line number Diff line
@@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
		iocb->ki_filp,
		iocb->ki_filp,
		iov_iter_count(to), (unsigned long) iocb->ki_pos);
		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) {
	if (!result) {
		result = generic_file_read_iter(iocb, to);
		result = generic_file_read_iter(iocb, to);
		if (result > 0)
		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",
	dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
		filp, (unsigned long) count, (unsigned long long) *ppos);
		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) {
	if (!res) {
		res = generic_file_splice_read(filp, ppos, pipe, count, flags);
		res = generic_file_splice_read(filp, ppos, pipe, count, flags);
		if (res > 0)
		if (res > 0)
@@ -372,6 +372,10 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
				 nfs_wait_bit_killable, TASK_KILLABLE);
				 nfs_wait_bit_killable, TASK_KILLABLE);
	if (ret)
	if (ret)
		return ret;
		return ret;
	/*
	 * Wait for O_DIRECT to complete
	 */
	nfs_inode_dio_wait(mapping->host);


	page = grab_cache_page_write_begin(mapping, index, flags);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
	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 */
	/* make sure the cache has finished storing the page */
	nfs_fscache_wait_on_page_write(NFS_I(inode), 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);
	lock_page(page);
	mapping = page_file_mapping(page);
	mapping = page_file_mapping(page);
	if (mapping != inode->i_mapping)
	if (mapping != inode->i_mapping)
+92 −19
Original line number Original line Diff line number Diff line
@@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
 * This is a copy of the common vmtruncate, but with the locking
 * This is a copy of the common vmtruncate, but with the locking
 * corrected to take into account the fact that NFS requires
 * corrected to take into account the fact that NFS requires
 * inode->i_size to be updated under the inode->i_lock.
 * 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)
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)
	if (err)
		goto out;
		goto out;


	spin_lock(&inode->i_lock);
	i_size_write(inode, offset);
	i_size_write(inode, offset);
	/* Optimisation */
	/* Optimisation */
	if (offset == 0)
	if (offset == 0)
		NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
		NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
	spin_unlock(&inode->i_lock);


	spin_unlock(&inode->i_lock);
	truncate_pagecache(inode, offset);
	truncate_pagecache(inode, offset);
	spin_lock(&inode->i_lock);
out:
out:
	return err;
	return err;
}
}
@@ -585,10 +586,15 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
 * Note: we do this in the *proc.c in order to ensure that
 * Note: we do this in the *proc.c in order to ensure that
 *       it works for things like exclusive creates too.
 *       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)
{
{
	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
	/* Barrier: bump the attribute generation count. */
	nfs_fattr_set_barrier(fattr);

	spin_lock(&inode->i_lock);
	spin_lock(&inode->i_lock);
	NFS_I(inode)->attr_gencount = fattr->gencount;
	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
		if ((attr->ia_valid & ATTR_MODE) != 0) {
		if ((attr->ia_valid & ATTR_MODE) != 0) {
			int mode = attr->ia_mode & S_IALLUGO;
			int mode = attr->ia_mode & S_IALLUGO;
			mode |= inode->i_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;
			inode->i_gid = attr->ia_gid;
		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
				| NFS_INO_INVALID_ACL);
				| NFS_INO_INVALID_ACL);
		spin_unlock(&inode->i_lock);
	}
	}
	if ((attr->ia_valid & ATTR_SIZE) != 0) {
	if ((attr->ia_valid & ATTR_SIZE) != 0) {
		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
		nfs_vmtruncate(inode, attr->ia_size);
		nfs_vmtruncate(inode, attr->ia_size);
	}
	}
	nfs_update_inode(inode, fattr);
	spin_unlock(&inode->i_lock);
}
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
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 (mapping->nrpages != 0) {
		if (S_ISREG(inode->i_mode)) {
		if (S_ISREG(inode->i_mode)) {
			unmap_mapping_range(mapping, 0, 0, 0);
			ret = nfs_sync_mapping(mapping);
			ret = nfs_sync_mapping(mapping);
			if (ret < 0)
			if (ret < 0)
				return ret;
				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
 * @inode - pointer to host inode
 * @mapping - pointer to mapping
 * @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);
	struct nfs_inode *nfsi = NFS_I(inode);
	unsigned long *bitlock = &nfsi->flags;
	unsigned long *bitlock = &nfsi->flags;
@@ -1113,6 +1124,11 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
	nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
	nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
	spin_unlock(&inode->i_lock);
	spin_unlock(&inode->i_lock);
	trace_nfs_invalidate_mapping_enter(inode);
	trace_nfs_invalidate_mapping_enter(inode);
	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);
		ret = nfs_invalidate_mapping(inode, mapping);
	trace_nfs_invalidate_mapping_exit(inode, ret);
	trace_nfs_invalidate_mapping_exit(inode, ret);


@@ -1123,6 +1139,29 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
	return ret;
	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)
static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
{
	struct nfs_inode *nfsi = NFS_I(inode);
	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;
	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 atomic_long_t nfs_attr_generation_counter;


static unsigned long nfs_read_attr_generation_counter(void)
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);
	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)
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);
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 *nfs_alloc_fattr(void)
{
{
	struct nfs_fattr *fattr;
	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 ||
	return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
		nfs_ctime_need_update(inode, fattr) ||
		nfs_ctime_need_update(inode, fattr) ||
		nfs_size_need_update(inode, fattr) ||
		((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
		((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;
	int status;


	spin_lock(&inode->i_lock);
	spin_lock(&inode->i_lock);
	nfs_fattr_set_barrier(fattr);
	status = nfs_post_op_update_inode_locked(inode, fattr);
	status = nfs_post_op_update_inode_locked(inode, fattr);
	spin_unlock(&inode->i_lock);
	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);
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
 * @inode - pointer to inode
 * @fattr - updated attributes
 * @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.
 * 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;
	int status;


	spin_lock(&inode->i_lock);
	/* Don't do a WCC update if these attributes are already stale */
	/* Don't do a WCC update if these attributes are already stale */
	if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
	if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
			!nfs_inode_attrs_need_update(inode, fattr)) {
			!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:
out_noforce:
	status = nfs_post_op_update_inode_locked(inode, fattr);
	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);
	spin_unlock(&inode->i_lock);
	return status;
	return status;
}
}
@@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
		nfsi->attrtimeo_timestamp = now;
		nfsi->attrtimeo_timestamp = now;
		/* Set barrier to be more recent than all outstanding updates */
		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
	} else {
	} else {
		if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
		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 = NFS_MAXATTRTIMEO(inode);
			nfsi->attrtimeo_timestamp = now;
			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;
	invalid &= ~NFS_INO_INVALID_ATTR;
	/* Don't invalidate the data if we were to blame */
	/* Don't invalidate the data if we were to blame */
Loading