Commit dc914858 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull more nfsd updates from Chuck Lever:

 - filecache code clean-ups

* tag 'nfsd-6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  nfsd: rework hashtable handling in nfsd_do_file_acquire
  nfsd: fix nfsd_file_unhash_and_dispose
parents f721d24e 243a5263
Loading
Loading
Loading
Loading
+29 −59
Original line number Diff line number Diff line
@@ -405,22 +405,15 @@ nfsd_file_unhash(struct nfsd_file *nf)
	return false;
}

/*
 * Return true if the file was unhashed.
 */
static bool
static void
nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
{
	trace_nfsd_file_unhash_and_dispose(nf);
	if (!nfsd_file_unhash(nf))
		return false;
	/* keep final reference for nfsd_file_lru_dispose */
	if (refcount_dec_not_one(&nf->nf_ref))
		return true;

	if (nfsd_file_unhash(nf)) {
		/* caller must call nfsd_file_dispose_list() later */
		nfsd_file_lru_remove(nf);
		list_add(&nf->nf_lru, dispose);
	return true;
	}
}

static void
@@ -562,8 +555,6 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
 * @lock: LRU list lock (unused)
 * @arg: dispose list
 *
 * Note this can deadlock with nfsd_file_cache_purge.
 *
 * Return values:
 *   %LRU_REMOVED: @item was removed from the LRU
 *   %LRU_ROTATE: @item is to be moved to the LRU tail
@@ -748,8 +739,6 @@ nfsd_file_close_inode(struct inode *inode)
 *
 * Walk the LRU list and close any entries that have not been used since
 * the last scan.
 *
 * Note this can deadlock with nfsd_file_cache_purge.
 */
static void
nfsd_file_delayed_close(struct work_struct *work)
@@ -891,16 +880,12 @@ nfsd_file_cache_init(void)
	goto out;
}

/*
 * Note this can deadlock with nfsd_file_lru_cb.
 */
static void
__nfsd_file_cache_purge(struct net *net)
{
	struct rhashtable_iter iter;
	struct nfsd_file *nf;
	LIST_HEAD(dispose);
	bool del;

	rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);
	do {
@@ -910,14 +895,7 @@ __nfsd_file_cache_purge(struct net *net)
		while (!IS_ERR_OR_NULL(nf)) {
			if (net && nf->nf_net != net)
				continue;
			del = nfsd_file_unhash_and_dispose(nf, &dispose);

			/*
			 * Deadlock detected! Something marked this entry as
			 * unhased, but hasn't removed it from the hash list.
			 */
			WARN_ON_ONCE(!del);

			nfsd_file_unhash_and_dispose(nf, &dispose);
			nf = rhashtable_walk_next(&iter);
		}

@@ -1064,9 +1042,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
		.need	= may_flags & NFSD_FILE_MAY_MASK,
		.net	= SVC_NET(rqstp),
	};
	struct nfsd_file *nf, *new;
	bool retry = true;
	bool open_retry = true;
	struct nfsd_file *nf;
	__be32 status;
	int ret;

	status = fh_verify(rqstp, fhp, S_IFREG,
				may_flags|NFSD_MAY_OWNER_OVERRIDE);
@@ -1076,35 +1055,33 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
	key.cred = get_current_cred();

retry:
	/* Avoid allocation if the item is already in cache */
	nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,
	rcu_read_lock();
	nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
			       nfsd_file_rhash_params);
	if (nf)
		nf = nfsd_file_get(nf);
	rcu_read_unlock();
	if (nf)
		goto wait_for_construction;

	new = nfsd_file_alloc(&key, may_flags);
	if (!new) {
	nf = nfsd_file_alloc(&key, may_flags);
	if (!nf) {
		status = nfserr_jukebox;
		goto out_status;
	}

	nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl,
					      &key, &new->nf_rhash,
	ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl,
					   &key, &nf->nf_rhash,
					   nfsd_file_rhash_params);
	if (!nf) {
		nf = new;
		goto open_file;
	}
	if (IS_ERR(nf))
		goto insert_err;
	nf = nfsd_file_get(nf);
	if (nf == NULL) {
		nf = new;
	if (likely(ret == 0))
		goto open_file;
	}
	nfsd_file_slab_free(&new->nf_rcu);

	nfsd_file_slab_free(&nf->nf_rcu);
	if (ret == -EEXIST)
		goto retry;
	trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret);
	status = nfserr_jukebox;
	goto out_status;

wait_for_construction:
	wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);
@@ -1112,11 +1089,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
	/* Did construction of this file fail? */
	if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
		trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf);
		if (!retry) {
		if (!open_retry) {
			status = nfserr_jukebox;
			goto out;
		}
		retry = false;
		open_retry = false;
		nfsd_file_put_noref(nf);
		goto retry;
	}
@@ -1164,13 +1141,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
	smp_mb__after_atomic();
	wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
	goto out;

insert_err:
	nfsd_file_slab_free(&new->nf_rcu);
	trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, PTR_ERR(nf));
	nf = NULL;
	status = nfserr_jukebox;
	goto out_status;
}

/**