xref: /kernel/linux/linux-6.6/fs/nfs/pnfs_dev.c (revision 62306a36)
162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  Device operations for the pnfs client.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (c) 2002
562306a36Sopenharmony_ci *  The Regents of the University of Michigan
662306a36Sopenharmony_ci *  All Rights Reserved
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Dean Hildebrand <dhildebz@umich.edu>
962306a36Sopenharmony_ci *  Garth Goodson   <Garth.Goodson@netapp.com>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  Permission is granted to use, copy, create derivative works, and
1262306a36Sopenharmony_ci *  redistribute this software and such derivative works for any purpose,
1362306a36Sopenharmony_ci *  so long as the name of the University of Michigan is not used in
1462306a36Sopenharmony_ci *  any advertising or publicity pertaining to the use or distribution
1562306a36Sopenharmony_ci *  of this software without specific, written prior authorization. If
1662306a36Sopenharmony_ci *  the above copyright notice or any other identification of the
1762306a36Sopenharmony_ci *  University of Michigan is included in any copy of any portion of
1862306a36Sopenharmony_ci *  this software, then the disclaimer below must also be included.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  This software is provided as is, without representation or warranty
2162306a36Sopenharmony_ci *  of any kind either express or implied, including without limitation
2262306a36Sopenharmony_ci *  the implied warranties of merchantability, fitness for a particular
2362306a36Sopenharmony_ci *  purpose, or noninfringement.  The Regents of the University of
2462306a36Sopenharmony_ci *  Michigan shall not be liable for any damages, including special,
2562306a36Sopenharmony_ci *  indirect, incidental, or consequential damages, with respect to any
2662306a36Sopenharmony_ci *  claim arising out of or in connection with the use of the software,
2762306a36Sopenharmony_ci *  even if it has been or is hereafter advised of the possibility of
2862306a36Sopenharmony_ci *  such damages.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <linux/export.h>
3262306a36Sopenharmony_ci#include <linux/nfs_fs.h>
3362306a36Sopenharmony_ci#include "nfs4session.h"
3462306a36Sopenharmony_ci#include "internal.h"
3562306a36Sopenharmony_ci#include "pnfs.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "nfs4trace.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define NFSDBG_FACILITY		NFSDBG_PNFS
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Device ID RCU cache. A device ID is unique per server and layout type.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_BITS	5
4562306a36Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_SIZE	(1 << NFS4_DEVICE_ID_HASH_BITS)
4662306a36Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_MASK	(NFS4_DEVICE_ID_HASH_SIZE - 1)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
5062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(nfs4_deviceid_lock);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#ifdef NFS_DEBUG
5362306a36Sopenharmony_civoid
5462306a36Sopenharmony_cinfs4_print_deviceid(const struct nfs4_deviceid *id)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	u32 *p = (u32 *)id;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	dprintk("%s: device id= [%x%x%x%x]\n", __func__,
5962306a36Sopenharmony_ci		p[0], p[1], p[2], p[3]);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_print_deviceid);
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline u32
6562306a36Sopenharmony_cinfs4_deviceid_hash(const struct nfs4_deviceid *id)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	unsigned char *cptr = (unsigned char *)id->data;
6862306a36Sopenharmony_ci	unsigned int nbytes = NFS4_DEVICEID4_SIZE;
6962306a36Sopenharmony_ci	u32 x = 0;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	while (nbytes--) {
7262306a36Sopenharmony_ci		x *= 37;
7362306a36Sopenharmony_ci		x += *cptr++;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	return x & NFS4_DEVICE_ID_HASH_MASK;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct nfs4_deviceid_node *
7962306a36Sopenharmony_ci_lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
8062306a36Sopenharmony_ci		 const struct nfs_client *clp, const struct nfs4_deviceid *id,
8162306a36Sopenharmony_ci		 long hash)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct nfs4_deviceid_node *d;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node)
8662306a36Sopenharmony_ci		if (d->ld == ld && d->nfs_client == clp &&
8762306a36Sopenharmony_ci		    !memcmp(&d->deviceid, id, sizeof(*id))) {
8862306a36Sopenharmony_ci			if (atomic_read(&d->ref))
8962306a36Sopenharmony_ci				return d;
9062306a36Sopenharmony_ci			else
9162306a36Sopenharmony_ci				continue;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci	return NULL;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic struct nfs4_deviceid_node *
9762306a36Sopenharmony_cinfs4_get_device_info(struct nfs_server *server,
9862306a36Sopenharmony_ci		const struct nfs4_deviceid *dev_id,
9962306a36Sopenharmony_ci		const struct cred *cred, gfp_t gfp_flags)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct nfs4_deviceid_node *d = NULL;
10262306a36Sopenharmony_ci	struct pnfs_device *pdev = NULL;
10362306a36Sopenharmony_ci	struct page **pages = NULL;
10462306a36Sopenharmony_ci	u32 max_resp_sz;
10562306a36Sopenharmony_ci	int max_pages;
10662306a36Sopenharmony_ci	int rc, i;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/*
10962306a36Sopenharmony_ci	 * Use the session max response size as the basis for setting
11062306a36Sopenharmony_ci	 * GETDEVICEINFO's maxcount
11162306a36Sopenharmony_ci	 */
11262306a36Sopenharmony_ci	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
11362306a36Sopenharmony_ci	if (server->pnfs_curr_ld->max_deviceinfo_size &&
11462306a36Sopenharmony_ci	    server->pnfs_curr_ld->max_deviceinfo_size < max_resp_sz)
11562306a36Sopenharmony_ci		max_resp_sz = server->pnfs_curr_ld->max_deviceinfo_size;
11662306a36Sopenharmony_ci	max_pages = nfs_page_array_len(0, max_resp_sz);
11762306a36Sopenharmony_ci	dprintk("%s: server %p max_resp_sz %u max_pages %d\n",
11862306a36Sopenharmony_ci		__func__, server, max_resp_sz, max_pages);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	pdev = kzalloc(sizeof(*pdev), gfp_flags);
12162306a36Sopenharmony_ci	if (!pdev)
12262306a36Sopenharmony_ci		return NULL;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
12562306a36Sopenharmony_ci	if (!pages)
12662306a36Sopenharmony_ci		goto out_free_pdev;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	for (i = 0; i < max_pages; i++) {
12962306a36Sopenharmony_ci		pages[i] = alloc_page(gfp_flags);
13062306a36Sopenharmony_ci		if (!pages[i])
13162306a36Sopenharmony_ci			goto out_free_pages;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
13562306a36Sopenharmony_ci	pdev->layout_type = server->pnfs_curr_ld->id;
13662306a36Sopenharmony_ci	pdev->pages = pages;
13762306a36Sopenharmony_ci	pdev->pgbase = 0;
13862306a36Sopenharmony_ci	pdev->pglen = max_resp_sz;
13962306a36Sopenharmony_ci	pdev->mincount = 0;
14062306a36Sopenharmony_ci	pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	rc = nfs4_proc_getdeviceinfo(server, pdev, cred);
14362306a36Sopenharmony_ci	dprintk("%s getdevice info returns %d\n", __func__, rc);
14462306a36Sopenharmony_ci	if (rc)
14562306a36Sopenharmony_ci		goto out_free_pages;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * Found new device, need to decode it and then add it to the
14962306a36Sopenharmony_ci	 * list of known devices for this mountpoint.
15062306a36Sopenharmony_ci	 */
15162306a36Sopenharmony_ci	d = server->pnfs_curr_ld->alloc_deviceid_node(server, pdev,
15262306a36Sopenharmony_ci			gfp_flags);
15362306a36Sopenharmony_ci	if (d && pdev->nocache)
15462306a36Sopenharmony_ci		set_bit(NFS_DEVICEID_NOCACHE, &d->flags);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciout_free_pages:
15762306a36Sopenharmony_ci	while (--i >= 0)
15862306a36Sopenharmony_ci		__free_page(pages[i]);
15962306a36Sopenharmony_ci	kfree(pages);
16062306a36Sopenharmony_ciout_free_pdev:
16162306a36Sopenharmony_ci	kfree(pdev);
16262306a36Sopenharmony_ci	dprintk("<-- %s d %p\n", __func__, d);
16362306a36Sopenharmony_ci	return d;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/*
16762306a36Sopenharmony_ci * Lookup a deviceid in cache and get a reference count on it if found
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * @clp nfs_client associated with deviceid
17062306a36Sopenharmony_ci * @id deviceid to look up
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_cistatic struct nfs4_deviceid_node *
17362306a36Sopenharmony_ci__nfs4_find_get_deviceid(struct nfs_server *server,
17462306a36Sopenharmony_ci		const struct nfs4_deviceid *id, long hash)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct nfs4_deviceid_node *d;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	rcu_read_lock();
17962306a36Sopenharmony_ci	d = _lookup_deviceid(server->pnfs_curr_ld, server->nfs_client, id,
18062306a36Sopenharmony_ci			hash);
18162306a36Sopenharmony_ci	if (d != NULL && !atomic_inc_not_zero(&d->ref))
18262306a36Sopenharmony_ci		d = NULL;
18362306a36Sopenharmony_ci	rcu_read_unlock();
18462306a36Sopenharmony_ci	return d;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistruct nfs4_deviceid_node *
18862306a36Sopenharmony_cinfs4_find_get_deviceid(struct nfs_server *server,
18962306a36Sopenharmony_ci		const struct nfs4_deviceid *id, const struct cred *cred,
19062306a36Sopenharmony_ci		gfp_t gfp_mask)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	long hash = nfs4_deviceid_hash(id);
19362306a36Sopenharmony_ci	struct nfs4_deviceid_node *d, *new;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	d = __nfs4_find_get_deviceid(server, id, hash);
19662306a36Sopenharmony_ci	if (d)
19762306a36Sopenharmony_ci		goto found;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	new = nfs4_get_device_info(server, id, cred, gfp_mask);
20062306a36Sopenharmony_ci	if (!new) {
20162306a36Sopenharmony_ci		trace_nfs4_find_deviceid(server, id, -ENOENT);
20262306a36Sopenharmony_ci		return new;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	spin_lock(&nfs4_deviceid_lock);
20662306a36Sopenharmony_ci	d = __nfs4_find_get_deviceid(server, id, hash);
20762306a36Sopenharmony_ci	if (d) {
20862306a36Sopenharmony_ci		spin_unlock(&nfs4_deviceid_lock);
20962306a36Sopenharmony_ci		server->pnfs_curr_ld->free_deviceid_node(new);
21062306a36Sopenharmony_ci	} else {
21162306a36Sopenharmony_ci		atomic_inc(&new->ref);
21262306a36Sopenharmony_ci		hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
21362306a36Sopenharmony_ci		spin_unlock(&nfs4_deviceid_lock);
21462306a36Sopenharmony_ci		d = new;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_cifound:
21762306a36Sopenharmony_ci	trace_nfs4_find_deviceid(server, id, 0);
21862306a36Sopenharmony_ci	return d;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci * Remove a deviceid from cache
22462306a36Sopenharmony_ci *
22562306a36Sopenharmony_ci * @clp nfs_client associated with deviceid
22662306a36Sopenharmony_ci * @id the deviceid to unhash
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_civoid
23162306a36Sopenharmony_cinfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
23262306a36Sopenharmony_ci			 const struct nfs_client *clp, const struct nfs4_deviceid *id)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct nfs4_deviceid_node *d;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	spin_lock(&nfs4_deviceid_lock);
23762306a36Sopenharmony_ci	rcu_read_lock();
23862306a36Sopenharmony_ci	d = _lookup_deviceid(ld, clp, id, nfs4_deviceid_hash(id));
23962306a36Sopenharmony_ci	rcu_read_unlock();
24062306a36Sopenharmony_ci	if (!d) {
24162306a36Sopenharmony_ci		spin_unlock(&nfs4_deviceid_lock);
24262306a36Sopenharmony_ci		return;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	hlist_del_init_rcu(&d->node);
24562306a36Sopenharmony_ci	clear_bit(NFS_DEVICEID_NOCACHE, &d->flags);
24662306a36Sopenharmony_ci	spin_unlock(&nfs4_deviceid_lock);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* balance the initial ref set in pnfs_insert_deviceid */
24962306a36Sopenharmony_ci	nfs4_put_deviceid_node(d);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_civoid
25462306a36Sopenharmony_cinfs4_init_deviceid_node(struct nfs4_deviceid_node *d, struct nfs_server *server,
25562306a36Sopenharmony_ci			const struct nfs4_deviceid *id)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	INIT_HLIST_NODE(&d->node);
25862306a36Sopenharmony_ci	INIT_HLIST_NODE(&d->tmpnode);
25962306a36Sopenharmony_ci	d->ld = server->pnfs_curr_ld;
26062306a36Sopenharmony_ci	d->nfs_client = server->nfs_client;
26162306a36Sopenharmony_ci	d->flags = 0;
26262306a36Sopenharmony_ci	d->deviceid = *id;
26362306a36Sopenharmony_ci	atomic_set(&d->ref, 1);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_init_deviceid_node);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * Dereference a deviceid node and delete it when its reference count drops
26962306a36Sopenharmony_ci * to zero.
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * @d deviceid node to put
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * return true iff the node was deleted
27462306a36Sopenharmony_ci * Note that since the test for d->ref == 0 is sufficient to establish
27562306a36Sopenharmony_ci * that the node is no longer hashed in the global device id cache.
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_cibool
27862306a36Sopenharmony_cinfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	if (test_bit(NFS_DEVICEID_NOCACHE, &d->flags)) {
28162306a36Sopenharmony_ci		if (atomic_add_unless(&d->ref, -1, 2))
28262306a36Sopenharmony_ci			return false;
28362306a36Sopenharmony_ci		nfs4_delete_deviceid(d->ld, d->nfs_client, &d->deviceid);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	if (!atomic_dec_and_test(&d->ref))
28662306a36Sopenharmony_ci		return false;
28762306a36Sopenharmony_ci	trace_nfs4_deviceid_free(d->nfs_client, &d->deviceid);
28862306a36Sopenharmony_ci	d->ld->free_deviceid_node(d);
28962306a36Sopenharmony_ci	return true;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_civoid
29462306a36Sopenharmony_cinfs4_mark_deviceid_available(struct nfs4_deviceid_node *node)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
29762306a36Sopenharmony_ci		clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
29862306a36Sopenharmony_ci		smp_mb__after_atomic();
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_mark_deviceid_available);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_civoid
30462306a36Sopenharmony_cinfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	node->timestamp_unavailable = jiffies;
30762306a36Sopenharmony_ci	smp_mb__before_atomic();
30862306a36Sopenharmony_ci	set_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
30962306a36Sopenharmony_ci	smp_mb__after_atomic();
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cibool
31462306a36Sopenharmony_cinfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
31762306a36Sopenharmony_ci		unsigned long start, end;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		end = jiffies;
32062306a36Sopenharmony_ci		start = end - PNFS_DEVICE_RETRY_TIMEOUT;
32162306a36Sopenharmony_ci		if (time_in_range(node->timestamp_unavailable, start, end))
32262306a36Sopenharmony_ci			return true;
32362306a36Sopenharmony_ci		clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
32462306a36Sopenharmony_ci		smp_mb__after_atomic();
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci	return false;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic void
33162306a36Sopenharmony_ci_deviceid_purge_client(const struct nfs_client *clp, long hash)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct nfs4_deviceid_node *d;
33462306a36Sopenharmony_ci	HLIST_HEAD(tmp);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	spin_lock(&nfs4_deviceid_lock);
33762306a36Sopenharmony_ci	rcu_read_lock();
33862306a36Sopenharmony_ci	hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node)
33962306a36Sopenharmony_ci		if (d->nfs_client == clp && atomic_read(&d->ref)) {
34062306a36Sopenharmony_ci			hlist_del_init_rcu(&d->node);
34162306a36Sopenharmony_ci			hlist_add_head(&d->tmpnode, &tmp);
34262306a36Sopenharmony_ci			clear_bit(NFS_DEVICEID_NOCACHE, &d->flags);
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci	rcu_read_unlock();
34562306a36Sopenharmony_ci	spin_unlock(&nfs4_deviceid_lock);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (hlist_empty(&tmp))
34862306a36Sopenharmony_ci		return;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	while (!hlist_empty(&tmp)) {
35162306a36Sopenharmony_ci		d = hlist_entry(tmp.first, struct nfs4_deviceid_node, tmpnode);
35262306a36Sopenharmony_ci		hlist_del(&d->tmpnode);
35362306a36Sopenharmony_ci		nfs4_put_deviceid_node(d);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_civoid
35862306a36Sopenharmony_cinfs4_deviceid_purge_client(const struct nfs_client *clp)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	long h;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!(clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_MDS))
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci	for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++)
36562306a36Sopenharmony_ci		_deviceid_purge_client(clp, h);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/*
36962306a36Sopenharmony_ci * Stop use of all deviceids associated with an nfs_client
37062306a36Sopenharmony_ci */
37162306a36Sopenharmony_civoid
37262306a36Sopenharmony_cinfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct nfs4_deviceid_node *d;
37562306a36Sopenharmony_ci	int i;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	rcu_read_lock();
37862306a36Sopenharmony_ci	for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){
37962306a36Sopenharmony_ci		hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[i], node)
38062306a36Sopenharmony_ci			if (d->nfs_client == clp)
38162306a36Sopenharmony_ci				set_bit(NFS_DEVICEID_INVALID, &d->flags);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci	rcu_read_unlock();
38462306a36Sopenharmony_ci}
385