This reverts commit c17f0e92b492d51a339442d5e5626a4c0a1dd060. Signed-off-by: Mike Snitzer <snitzer@xxxxxxxxxx> --- fs/nfs_common/nfslocalio.c | 85 ++++++++++++-------------------------- 1 file changed, 27 insertions(+), 58 deletions(-) diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c index 1dd5a8cca064..49c59f0c78c6 100644 --- a/fs/nfs_common/nfslocalio.c +++ b/fs/nfs_common/nfslocalio.c @@ -151,7 +151,8 @@ EXPORT_SYMBOL_GPL(nfs_localio_enable_client); */ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid) { - struct nfs_file_localio *nfl; + LIST_HEAD(local_files); + struct nfs_file_localio *nfl, *tmp; spin_lock(&nfs_uuid->lock); if (unlikely(!rcu_access_pointer(nfs_uuid->net))) { @@ -165,49 +166,37 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid) nfs_uuid->dom = NULL; } + list_splice_init(&nfs_uuid->files, &local_files); + spin_unlock(&nfs_uuid->lock); + /* Walk list of files and ensure their last references dropped */ - - while ((nfl = list_first_entry_or_null(&nfs_uuid->files, - struct nfs_file_localio, - list)) != NULL) { + list_for_each_entry_safe(nfl, tmp, &local_files, list) { struct nfsd_file *ro_nf; struct nfsd_file *rw_nf; - /* If nfs_uuid is already NULL, nfs_close_local_fh is - * closing and we must wait, else we unlink and close. - */ - if (rcu_access_pointer(nfl->nfs_uuid) == NULL) { - /* nfs_close_local_fh() is doing the - * close and we must wait. until it unlinks - */ - wait_var_event_spinlock(nfl, - list_first_entry_or_null( - &nfs_uuid->files, - struct nfs_file_localio, - list) != nfl, - &nfs_uuid->lock); - continue; - } - ro_nf = unrcu_pointer(xchg(&nfl->ro_file, NULL)); rw_nf = unrcu_pointer(xchg(&nfl->rw_file, NULL)); + spin_lock(&nfs_uuid->lock); /* Remove nfl from nfs_uuid->files list */ list_del_init(&nfl->list); spin_unlock(&nfs_uuid->lock); + /* Now we can allow racing nfs_close_local_fh() to + * skip the locking. + */ + RCU_INIT_POINTER(nfl->nfs_uuid, NULL); + if (ro_nf) nfs_to_nfsd_file_put_local(ro_nf); if (rw_nf) nfs_to_nfsd_file_put_local(rw_nf); + cond_resched(); - spin_lock(&nfs_uuid->lock); - /* Now we can allow racing nfs_close_local_fh() to - * skip the locking. - */ - RCU_INIT_POINTER(nfl->nfs_uuid, NULL); - wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock); } + spin_lock(&nfs_uuid->lock); + BUG_ON(!list_empty(&nfs_uuid->files)); + /* Remove client from nn->local_clients */ if (nfs_uuid->list_lock) { spin_lock(nfs_uuid->list_lock); @@ -315,43 +304,23 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl) return; } - spin_lock(&nfs_uuid->lock); - if (!rcu_access_pointer(nfl->nfs_uuid)) { - /* nfs_uuid_put has finished here */ - spin_unlock(&nfs_uuid->lock); - rcu_read_unlock(); - return; - } - if (list_empty(&nfs_uuid->files)) { - /* nfs_uuid_put() has started closing files, wait for it - * to finished - */ - spin_unlock(&nfs_uuid->lock); - rcu_read_unlock(); - wait_var_event(&nfl->nfs_uuid, - rcu_access_pointer(nfl->nfs_uuid) == NULL); - return; - } - /* tell nfs_uuid_put() to wait for us */ - RCU_INIT_POINTER(nfl->nfs_uuid, NULL); - spin_unlock(&nfs_uuid->lock); - rcu_read_unlock(); - ro_nf = unrcu_pointer(xchg(&nfl->ro_file, NULL)); rw_nf = unrcu_pointer(xchg(&nfl->rw_file, NULL)); + + spin_lock(&nfs_uuid->lock); + /* Remove nfl from nfs_uuid->files list */ + list_del_init(&nfl->list); + spin_unlock(&nfs_uuid->lock); + rcu_read_unlock(); + /* Now we can allow racing nfs_close_local_fh() to + * skip the locking. + */ + RCU_INIT_POINTER(nfl->nfs_uuid, NULL); + if (ro_nf) nfs_to_nfsd_file_put_local(ro_nf); if (rw_nf) nfs_to_nfsd_file_put_local(rw_nf); - - /* Remove nfl from nfs_uuid->files list and signal nfs_uuid_put() - * that we are done. The moment we drop the spinlock the - * nfs_uuid could be freed. - */ - spin_lock(&nfs_uuid->lock); - list_del_init(&nfl->list); - wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock); - spin_unlock(&nfs_uuid->lock); } EXPORT_SYMBOL_GPL(nfs_close_local_fh); -- 2.44.0