Commit dc914858 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

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
...@@ -405,22 +405,15 @@ nfsd_file_unhash(struct nfsd_file *nf) ...@@ -405,22 +405,15 @@ nfsd_file_unhash(struct nfsd_file *nf)
return false; return false;
} }
/* static void
* Return true if the file was unhashed.
*/
static bool
nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose) nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
{ {
trace_nfsd_file_unhash_and_dispose(nf); trace_nfsd_file_unhash_and_dispose(nf);
if (!nfsd_file_unhash(nf)) if (nfsd_file_unhash(nf)) {
return false; /* caller must call nfsd_file_dispose_list() later */
/* keep final reference for nfsd_file_lru_dispose */ nfsd_file_lru_remove(nf);
if (refcount_dec_not_one(&nf->nf_ref)) list_add(&nf->nf_lru, dispose);
return true; }
nfsd_file_lru_remove(nf);
list_add(&nf->nf_lru, dispose);
return true;
} }
static void static void
...@@ -562,8 +555,6 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose) ...@@ -562,8 +555,6 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
* @lock: LRU list lock (unused) * @lock: LRU list lock (unused)
* @arg: dispose list * @arg: dispose list
* *
* Note this can deadlock with nfsd_file_cache_purge.
*
* Return values: * Return values:
* %LRU_REMOVED: @item was removed from the LRU * %LRU_REMOVED: @item was removed from the LRU
* %LRU_ROTATE: @item is to be moved to the LRU tail * %LRU_ROTATE: @item is to be moved to the LRU tail
...@@ -748,8 +739,6 @@ nfsd_file_close_inode(struct inode *inode) ...@@ -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 * Walk the LRU list and close any entries that have not been used since
* the last scan. * the last scan.
*
* Note this can deadlock with nfsd_file_cache_purge.
*/ */
static void static void
nfsd_file_delayed_close(struct work_struct *work) nfsd_file_delayed_close(struct work_struct *work)
...@@ -891,16 +880,12 @@ nfsd_file_cache_init(void) ...@@ -891,16 +880,12 @@ nfsd_file_cache_init(void)
goto out; goto out;
} }
/*
* Note this can deadlock with nfsd_file_lru_cb.
*/
static void static void
__nfsd_file_cache_purge(struct net *net) __nfsd_file_cache_purge(struct net *net)
{ {
struct rhashtable_iter iter; struct rhashtable_iter iter;
struct nfsd_file *nf; struct nfsd_file *nf;
LIST_HEAD(dispose); LIST_HEAD(dispose);
bool del;
rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter); rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);
do { do {
...@@ -910,14 +895,7 @@ __nfsd_file_cache_purge(struct net *net) ...@@ -910,14 +895,7 @@ __nfsd_file_cache_purge(struct net *net)
while (!IS_ERR_OR_NULL(nf)) { while (!IS_ERR_OR_NULL(nf)) {
if (net && nf->nf_net != net) if (net && nf->nf_net != net)
continue; continue;
del = nfsd_file_unhash_and_dispose(nf, &dispose); 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);
nf = rhashtable_walk_next(&iter); nf = rhashtable_walk_next(&iter);
} }
...@@ -1064,9 +1042,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1064,9 +1042,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
.need = may_flags & NFSD_FILE_MAY_MASK, .need = may_flags & NFSD_FILE_MAY_MASK,
.net = SVC_NET(rqstp), .net = SVC_NET(rqstp),
}; };
struct nfsd_file *nf, *new; bool open_retry = true;
bool retry = true; struct nfsd_file *nf;
__be32 status; __be32 status;
int ret;
status = fh_verify(rqstp, fhp, S_IFREG, status = fh_verify(rqstp, fhp, S_IFREG,
may_flags|NFSD_MAY_OWNER_OVERRIDE); may_flags|NFSD_MAY_OWNER_OVERRIDE);
...@@ -1076,35 +1055,33 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1076,35 +1055,33 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
key.cred = get_current_cred(); key.cred = get_current_cred();
retry: retry:
/* Avoid allocation if the item is already in cache */ rcu_read_lock();
nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key, nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
nfsd_file_rhash_params); nfsd_file_rhash_params);
if (nf) if (nf)
nf = nfsd_file_get(nf); nf = nfsd_file_get(nf);
rcu_read_unlock();
if (nf) if (nf)
goto wait_for_construction; goto wait_for_construction;
new = nfsd_file_alloc(&key, may_flags); nf = nfsd_file_alloc(&key, may_flags);
if (!new) { if (!nf) {
status = nfserr_jukebox; status = nfserr_jukebox;
goto out_status; goto out_status;
} }
nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl, ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl,
&key, &new->nf_rhash, &key, &nf->nf_rhash,
nfsd_file_rhash_params); nfsd_file_rhash_params);
if (!nf) { if (likely(ret == 0))
nf = new;
goto open_file;
}
if (IS_ERR(nf))
goto insert_err;
nf = nfsd_file_get(nf);
if (nf == NULL) {
nf = new;
goto open_file; 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_for_construction:
wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE); 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, ...@@ -1112,11 +1089,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
/* Did construction of this file fail? */ /* Did construction of this file fail? */
if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf); trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf);
if (!retry) { if (!open_retry) {
status = nfserr_jukebox; status = nfserr_jukebox;
goto out; goto out;
} }
retry = false; open_retry = false;
nfsd_file_put_noref(nf); nfsd_file_put_noref(nf);
goto retry; goto retry;
} }
...@@ -1164,13 +1141,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1164,13 +1141,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
smp_mb__after_atomic(); smp_mb__after_atomic();
wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
goto out; 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;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment