18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Device operations for the pnfs client. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2002 58c2ecf20Sopenharmony_ci * The Regents of the University of Michigan 68c2ecf20Sopenharmony_ci * All Rights Reserved 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Dean Hildebrand <dhildebz@umich.edu> 98c2ecf20Sopenharmony_ci * Garth Goodson <Garth.Goodson@netapp.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Permission is granted to use, copy, create derivative works, and 128c2ecf20Sopenharmony_ci * redistribute this software and such derivative works for any purpose, 138c2ecf20Sopenharmony_ci * so long as the name of the University of Michigan is not used in 148c2ecf20Sopenharmony_ci * any advertising or publicity pertaining to the use or distribution 158c2ecf20Sopenharmony_ci * of this software without specific, written prior authorization. If 168c2ecf20Sopenharmony_ci * the above copyright notice or any other identification of the 178c2ecf20Sopenharmony_ci * University of Michigan is included in any copy of any portion of 188c2ecf20Sopenharmony_ci * this software, then the disclaimer below must also be included. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * This software is provided as is, without representation or warranty 218c2ecf20Sopenharmony_ci * of any kind either express or implied, including without limitation 228c2ecf20Sopenharmony_ci * the implied warranties of merchantability, fitness for a particular 238c2ecf20Sopenharmony_ci * purpose, or noninfringement. The Regents of the University of 248c2ecf20Sopenharmony_ci * Michigan shall not be liable for any damages, including special, 258c2ecf20Sopenharmony_ci * indirect, incidental, or consequential damages, with respect to any 268c2ecf20Sopenharmony_ci * claim arising out of or in connection with the use of the software, 278c2ecf20Sopenharmony_ci * even if it has been or is hereafter advised of the possibility of 288c2ecf20Sopenharmony_ci * such damages. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/export.h> 328c2ecf20Sopenharmony_ci#include <linux/nfs_fs.h> 338c2ecf20Sopenharmony_ci#include "nfs4session.h" 348c2ecf20Sopenharmony_ci#include "internal.h" 358c2ecf20Sopenharmony_ci#include "pnfs.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_PNFS 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Device ID RCU cache. A device ID is unique per server and layout type. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_BITS 5 438c2ecf20Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS) 448c2ecf20Sopenharmony_ci#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE]; 488c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(nfs4_deviceid_lock); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#ifdef NFS_DEBUG 518c2ecf20Sopenharmony_civoid 528c2ecf20Sopenharmony_cinfs4_print_deviceid(const struct nfs4_deviceid *id) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u32 *p = (u32 *)id; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci dprintk("%s: device id= [%x%x%x%x]\n", __func__, 578c2ecf20Sopenharmony_ci p[0], p[1], p[2], p[3]); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_print_deviceid); 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline u32 638c2ecf20Sopenharmony_cinfs4_deviceid_hash(const struct nfs4_deviceid *id) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned char *cptr = (unsigned char *)id->data; 668c2ecf20Sopenharmony_ci unsigned int nbytes = NFS4_DEVICEID4_SIZE; 678c2ecf20Sopenharmony_ci u32 x = 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci while (nbytes--) { 708c2ecf20Sopenharmony_ci x *= 37; 718c2ecf20Sopenharmony_ci x += *cptr++; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci return x & NFS4_DEVICE_ID_HASH_MASK; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct nfs4_deviceid_node * 778c2ecf20Sopenharmony_ci_lookup_deviceid(const struct pnfs_layoutdriver_type *ld, 788c2ecf20Sopenharmony_ci const struct nfs_client *clp, const struct nfs4_deviceid *id, 798c2ecf20Sopenharmony_ci long hash) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node) 848c2ecf20Sopenharmony_ci if (d->ld == ld && d->nfs_client == clp && 858c2ecf20Sopenharmony_ci !memcmp(&d->deviceid, id, sizeof(*id))) { 868c2ecf20Sopenharmony_ci if (atomic_read(&d->ref)) 878c2ecf20Sopenharmony_ci return d; 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci continue; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci return NULL; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic struct nfs4_deviceid_node * 958c2ecf20Sopenharmony_cinfs4_get_device_info(struct nfs_server *server, 968c2ecf20Sopenharmony_ci const struct nfs4_deviceid *dev_id, 978c2ecf20Sopenharmony_ci const struct cred *cred, gfp_t gfp_flags) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d = NULL; 1008c2ecf20Sopenharmony_ci struct pnfs_device *pdev = NULL; 1018c2ecf20Sopenharmony_ci struct page **pages = NULL; 1028c2ecf20Sopenharmony_ci u32 max_resp_sz; 1038c2ecf20Sopenharmony_ci int max_pages; 1048c2ecf20Sopenharmony_ci int rc, i; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Use the session max response size as the basis for setting 1088c2ecf20Sopenharmony_ci * GETDEVICEINFO's maxcount 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; 1118c2ecf20Sopenharmony_ci if (server->pnfs_curr_ld->max_deviceinfo_size && 1128c2ecf20Sopenharmony_ci server->pnfs_curr_ld->max_deviceinfo_size < max_resp_sz) 1138c2ecf20Sopenharmony_ci max_resp_sz = server->pnfs_curr_ld->max_deviceinfo_size; 1148c2ecf20Sopenharmony_ci max_pages = nfs_page_array_len(0, max_resp_sz); 1158c2ecf20Sopenharmony_ci dprintk("%s: server %p max_resp_sz %u max_pages %d\n", 1168c2ecf20Sopenharmony_ci __func__, server, max_resp_sz, max_pages); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci pdev = kzalloc(sizeof(*pdev), gfp_flags); 1198c2ecf20Sopenharmony_ci if (!pdev) 1208c2ecf20Sopenharmony_ci return NULL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); 1238c2ecf20Sopenharmony_ci if (!pages) 1248c2ecf20Sopenharmony_ci goto out_free_pdev; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci for (i = 0; i < max_pages; i++) { 1278c2ecf20Sopenharmony_ci pages[i] = alloc_page(gfp_flags); 1288c2ecf20Sopenharmony_ci if (!pages[i]) 1298c2ecf20Sopenharmony_ci goto out_free_pages; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); 1338c2ecf20Sopenharmony_ci pdev->layout_type = server->pnfs_curr_ld->id; 1348c2ecf20Sopenharmony_ci pdev->pages = pages; 1358c2ecf20Sopenharmony_ci pdev->pgbase = 0; 1368c2ecf20Sopenharmony_ci pdev->pglen = max_resp_sz; 1378c2ecf20Sopenharmony_ci pdev->mincount = 0; 1388c2ecf20Sopenharmony_ci pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci rc = nfs4_proc_getdeviceinfo(server, pdev, cred); 1418c2ecf20Sopenharmony_ci dprintk("%s getdevice info returns %d\n", __func__, rc); 1428c2ecf20Sopenharmony_ci if (rc) 1438c2ecf20Sopenharmony_ci goto out_free_pages; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * Found new device, need to decode it and then add it to the 1478c2ecf20Sopenharmony_ci * list of known devices for this mountpoint. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci d = server->pnfs_curr_ld->alloc_deviceid_node(server, pdev, 1508c2ecf20Sopenharmony_ci gfp_flags); 1518c2ecf20Sopenharmony_ci if (d && pdev->nocache) 1528c2ecf20Sopenharmony_ci set_bit(NFS_DEVICEID_NOCACHE, &d->flags); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciout_free_pages: 1558c2ecf20Sopenharmony_ci while (--i >= 0) 1568c2ecf20Sopenharmony_ci __free_page(pages[i]); 1578c2ecf20Sopenharmony_ci kfree(pages); 1588c2ecf20Sopenharmony_ciout_free_pdev: 1598c2ecf20Sopenharmony_ci kfree(pdev); 1608c2ecf20Sopenharmony_ci dprintk("<-- %s d %p\n", __func__, d); 1618c2ecf20Sopenharmony_ci return d; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * Lookup a deviceid in cache and get a reference count on it if found 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * @clp nfs_client associated with deviceid 1688c2ecf20Sopenharmony_ci * @id deviceid to look up 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistatic struct nfs4_deviceid_node * 1718c2ecf20Sopenharmony_ci__nfs4_find_get_deviceid(struct nfs_server *server, 1728c2ecf20Sopenharmony_ci const struct nfs4_deviceid *id, long hash) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci rcu_read_lock(); 1778c2ecf20Sopenharmony_ci d = _lookup_deviceid(server->pnfs_curr_ld, server->nfs_client, id, 1788c2ecf20Sopenharmony_ci hash); 1798c2ecf20Sopenharmony_ci if (d != NULL && !atomic_inc_not_zero(&d->ref)) 1808c2ecf20Sopenharmony_ci d = NULL; 1818c2ecf20Sopenharmony_ci rcu_read_unlock(); 1828c2ecf20Sopenharmony_ci return d; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistruct nfs4_deviceid_node * 1868c2ecf20Sopenharmony_cinfs4_find_get_deviceid(struct nfs_server *server, 1878c2ecf20Sopenharmony_ci const struct nfs4_deviceid *id, const struct cred *cred, 1888c2ecf20Sopenharmony_ci gfp_t gfp_mask) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci long hash = nfs4_deviceid_hash(id); 1918c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d, *new; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci d = __nfs4_find_get_deviceid(server, id, hash); 1948c2ecf20Sopenharmony_ci if (d) 1958c2ecf20Sopenharmony_ci return d; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci new = nfs4_get_device_info(server, id, cred, gfp_mask); 1988c2ecf20Sopenharmony_ci if (!new) 1998c2ecf20Sopenharmony_ci return new; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci spin_lock(&nfs4_deviceid_lock); 2028c2ecf20Sopenharmony_ci d = __nfs4_find_get_deviceid(server, id, hash); 2038c2ecf20Sopenharmony_ci if (d) { 2048c2ecf20Sopenharmony_ci spin_unlock(&nfs4_deviceid_lock); 2058c2ecf20Sopenharmony_ci server->pnfs_curr_ld->free_deviceid_node(new); 2068c2ecf20Sopenharmony_ci return d; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]); 2098c2ecf20Sopenharmony_ci atomic_inc(&new->ref); 2108c2ecf20Sopenharmony_ci spin_unlock(&nfs4_deviceid_lock); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return new; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * Remove a deviceid from cache 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * @clp nfs_client associated with deviceid 2208c2ecf20Sopenharmony_ci * @id the deviceid to unhash 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_civoid 2258c2ecf20Sopenharmony_cinfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, 2268c2ecf20Sopenharmony_ci const struct nfs_client *clp, const struct nfs4_deviceid *id) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci spin_lock(&nfs4_deviceid_lock); 2318c2ecf20Sopenharmony_ci rcu_read_lock(); 2328c2ecf20Sopenharmony_ci d = _lookup_deviceid(ld, clp, id, nfs4_deviceid_hash(id)); 2338c2ecf20Sopenharmony_ci rcu_read_unlock(); 2348c2ecf20Sopenharmony_ci if (!d) { 2358c2ecf20Sopenharmony_ci spin_unlock(&nfs4_deviceid_lock); 2368c2ecf20Sopenharmony_ci return; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci hlist_del_init_rcu(&d->node); 2398c2ecf20Sopenharmony_ci clear_bit(NFS_DEVICEID_NOCACHE, &d->flags); 2408c2ecf20Sopenharmony_ci spin_unlock(&nfs4_deviceid_lock); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* balance the initial ref set in pnfs_insert_deviceid */ 2438c2ecf20Sopenharmony_ci nfs4_put_deviceid_node(d); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_delete_deviceid); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_civoid 2488c2ecf20Sopenharmony_cinfs4_init_deviceid_node(struct nfs4_deviceid_node *d, struct nfs_server *server, 2498c2ecf20Sopenharmony_ci const struct nfs4_deviceid *id) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&d->node); 2528c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&d->tmpnode); 2538c2ecf20Sopenharmony_ci d->ld = server->pnfs_curr_ld; 2548c2ecf20Sopenharmony_ci d->nfs_client = server->nfs_client; 2558c2ecf20Sopenharmony_ci d->flags = 0; 2568c2ecf20Sopenharmony_ci d->deviceid = *id; 2578c2ecf20Sopenharmony_ci atomic_set(&d->ref, 1); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_init_deviceid_node); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* 2628c2ecf20Sopenharmony_ci * Dereference a deviceid node and delete it when its reference count drops 2638c2ecf20Sopenharmony_ci * to zero. 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * @d deviceid node to put 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * return true iff the node was deleted 2688c2ecf20Sopenharmony_ci * Note that since the test for d->ref == 0 is sufficient to establish 2698c2ecf20Sopenharmony_ci * that the node is no longer hashed in the global device id cache. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cibool 2728c2ecf20Sopenharmony_cinfs4_put_deviceid_node(struct nfs4_deviceid_node *d) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (test_bit(NFS_DEVICEID_NOCACHE, &d->flags)) { 2758c2ecf20Sopenharmony_ci if (atomic_add_unless(&d->ref, -1, 2)) 2768c2ecf20Sopenharmony_ci return false; 2778c2ecf20Sopenharmony_ci nfs4_delete_deviceid(d->ld, d->nfs_client, &d->deviceid); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&d->ref)) 2808c2ecf20Sopenharmony_ci return false; 2818c2ecf20Sopenharmony_ci d->ld->free_deviceid_node(d); 2828c2ecf20Sopenharmony_ci return true; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_put_deviceid_node); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_civoid 2878c2ecf20Sopenharmony_cinfs4_mark_deviceid_available(struct nfs4_deviceid_node *node) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) { 2908c2ecf20Sopenharmony_ci clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags); 2918c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_mark_deviceid_available); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_civoid 2978c2ecf20Sopenharmony_cinfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci node->timestamp_unavailable = jiffies; 3008c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 3018c2ecf20Sopenharmony_ci set_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags); 3028c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cibool 3078c2ecf20Sopenharmony_cinfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) { 3108c2ecf20Sopenharmony_ci unsigned long start, end; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci end = jiffies; 3138c2ecf20Sopenharmony_ci start = end - PNFS_DEVICE_RETRY_TIMEOUT; 3148c2ecf20Sopenharmony_ci if (time_in_range(node->timestamp_unavailable, start, end)) 3158c2ecf20Sopenharmony_ci return true; 3168c2ecf20Sopenharmony_ci clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags); 3178c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci return false; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void 3248c2ecf20Sopenharmony_ci_deviceid_purge_client(const struct nfs_client *clp, long hash) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d; 3278c2ecf20Sopenharmony_ci HLIST_HEAD(tmp); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci spin_lock(&nfs4_deviceid_lock); 3308c2ecf20Sopenharmony_ci rcu_read_lock(); 3318c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node) 3328c2ecf20Sopenharmony_ci if (d->nfs_client == clp && atomic_read(&d->ref)) { 3338c2ecf20Sopenharmony_ci hlist_del_init_rcu(&d->node); 3348c2ecf20Sopenharmony_ci hlist_add_head(&d->tmpnode, &tmp); 3358c2ecf20Sopenharmony_ci clear_bit(NFS_DEVICEID_NOCACHE, &d->flags); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci rcu_read_unlock(); 3388c2ecf20Sopenharmony_ci spin_unlock(&nfs4_deviceid_lock); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (hlist_empty(&tmp)) 3418c2ecf20Sopenharmony_ci return; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci while (!hlist_empty(&tmp)) { 3448c2ecf20Sopenharmony_ci d = hlist_entry(tmp.first, struct nfs4_deviceid_node, tmpnode); 3458c2ecf20Sopenharmony_ci hlist_del(&d->tmpnode); 3468c2ecf20Sopenharmony_ci nfs4_put_deviceid_node(d); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_civoid 3518c2ecf20Sopenharmony_cinfs4_deviceid_purge_client(const struct nfs_client *clp) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci long h; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!(clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_MDS)) 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++) 3588c2ecf20Sopenharmony_ci _deviceid_purge_client(clp, h); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/* 3628c2ecf20Sopenharmony_ci * Stop use of all deviceids associated with an nfs_client 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_civoid 3658c2ecf20Sopenharmony_cinfs4_deviceid_mark_client_invalid(struct nfs_client *clp) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct nfs4_deviceid_node *d; 3688c2ecf20Sopenharmony_ci int i; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci rcu_read_lock(); 3718c2ecf20Sopenharmony_ci for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){ 3728c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[i], node) 3738c2ecf20Sopenharmony_ci if (d->nfs_client == clp) 3748c2ecf20Sopenharmony_ci set_bit(NFS_DEVICEID_INVALID, &d->flags); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci rcu_read_unlock(); 3778c2ecf20Sopenharmony_ci} 378