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