2 * Device operations for the pnfs client.
5 * The Regents of the University of Michigan
8 * Dean Hildebrand <dhildebz@umich.edu>
9 * Garth Goodson <Garth.Goodson@netapp.com>
11 * Permission is granted to use, copy, create derivative works, and
12 * redistribute this software and such derivative works for any purpose,
13 * so long as the name of the University of Michigan is not used in
14 * any advertising or publicity pertaining to the use or distribution
15 * of this software without specific, written prior authorization. If
16 * the above copyright notice or any other identification of the
17 * University of Michigan is included in any copy of any portion of
18 * this software, then the disclaimer below must also be included.
20 * This software is provided as is, without representation or warranty
21 * of any kind either express or implied, including without limitation
22 * the implied warranties of merchantability, fitness for a particular
23 * purpose, or noninfringement. The Regents of the University of
24 * Michigan shall not be liable for any damages, including special,
25 * indirect, incidental, or consequential damages, with respect to any
26 * claim arising out of or in connection with the use of the software,
27 * even if it has been or is hereafter advised of the possibility of
31 #include <linux/export.h>
32 #include <linux/nfs_fs.h>
33 #include "nfs4session.h"
37 #define NFSDBG_FACILITY NFSDBG_PNFS
40 * Device ID RCU cache. A device ID is unique per server and layout type.
42 #define NFS4_DEVICE_ID_HASH_BITS 5
43 #define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS)
44 #define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1)
46 #define PNFS_DEVICE_RETRY_TIMEOUT (120*HZ)
48 static struct hlist_head nfs4_deviceid_cache
[NFS4_DEVICE_ID_HASH_SIZE
];
49 static DEFINE_SPINLOCK(nfs4_deviceid_lock
);
53 nfs4_print_deviceid(const struct nfs4_deviceid
*id
)
57 dprintk("%s: device id= [%x%x%x%x]\n", __func__
,
58 p
[0], p
[1], p
[2], p
[3]);
60 EXPORT_SYMBOL_GPL(nfs4_print_deviceid
);
64 nfs4_deviceid_hash(const struct nfs4_deviceid
*id
)
66 unsigned char *cptr
= (unsigned char *)id
->data
;
67 unsigned int nbytes
= NFS4_DEVICEID4_SIZE
;
74 return x
& NFS4_DEVICE_ID_HASH_MASK
;
77 static struct nfs4_deviceid_node
*
78 _lookup_deviceid(const struct pnfs_layoutdriver_type
*ld
,
79 const struct nfs_client
*clp
, const struct nfs4_deviceid
*id
,
82 struct nfs4_deviceid_node
*d
;
84 hlist_for_each_entry_rcu(d
, &nfs4_deviceid_cache
[hash
], node
)
85 if (d
->ld
== ld
&& d
->nfs_client
== clp
&&
86 !memcmp(&d
->deviceid
, id
, sizeof(*id
))) {
87 if (atomic_read(&d
->ref
))
95 static struct nfs4_deviceid_node
*
96 nfs4_get_device_info(struct nfs_server
*server
,
97 const struct nfs4_deviceid
*dev_id
,
98 struct rpc_cred
*cred
, gfp_t gfp_flags
)
100 struct nfs4_deviceid_node
*d
= NULL
;
101 struct pnfs_device
*pdev
= NULL
;
102 struct page
**pages
= NULL
;
108 * Use the session max response size as the basis for setting
109 * GETDEVICEINFO's maxcount
111 max_resp_sz
= server
->nfs_client
->cl_session
->fc_attrs
.max_resp_sz
;
112 if (server
->pnfs_curr_ld
->max_deviceinfo_size
&&
113 server
->pnfs_curr_ld
->max_deviceinfo_size
< max_resp_sz
)
114 max_resp_sz
= server
->pnfs_curr_ld
->max_deviceinfo_size
;
115 max_pages
= nfs_page_array_len(0, max_resp_sz
);
116 dprintk("%s: server %p max_resp_sz %u max_pages %d\n",
117 __func__
, server
, max_resp_sz
, max_pages
);
119 pdev
= kzalloc(sizeof(*pdev
), gfp_flags
);
123 pages
= kcalloc(max_pages
, sizeof(struct page
*), gfp_flags
);
127 for (i
= 0; i
< max_pages
; i
++) {
128 pages
[i
] = alloc_page(gfp_flags
);
133 memcpy(&pdev
->dev_id
, dev_id
, sizeof(*dev_id
));
134 pdev
->layout_type
= server
->pnfs_curr_ld
->id
;
137 pdev
->pglen
= max_resp_sz
;
139 pdev
->maxcount
= max_resp_sz
- nfs41_maxgetdevinfo_overhead
;
141 rc
= nfs4_proc_getdeviceinfo(server
, pdev
, cred
);
142 dprintk("%s getdevice info returns %d\n", __func__
, rc
);
147 * Found new device, need to decode it and then add it to the
148 * list of known devices for this mountpoint.
150 d
= server
->pnfs_curr_ld
->alloc_deviceid_node(server
, pdev
,
152 if (d
&& pdev
->nocache
)
153 set_bit(NFS_DEVICEID_NOCACHE
, &d
->flags
);
156 for (i
= 0; i
< max_pages
; i
++)
157 __free_page(pages
[i
]);
161 dprintk("<-- %s d %p\n", __func__
, d
);
166 * Lookup a deviceid in cache and get a reference count on it if found
168 * @clp nfs_client associated with deviceid
169 * @id deviceid to look up
171 static struct nfs4_deviceid_node
*
172 __nfs4_find_get_deviceid(struct nfs_server
*server
,
173 const struct nfs4_deviceid
*id
, long hash
)
175 struct nfs4_deviceid_node
*d
;
178 d
= _lookup_deviceid(server
->pnfs_curr_ld
, server
->nfs_client
, id
,
180 if (d
!= NULL
&& !atomic_inc_not_zero(&d
->ref
))
186 struct nfs4_deviceid_node
*
187 nfs4_find_get_deviceid(struct nfs_server
*server
,
188 const struct nfs4_deviceid
*id
, struct rpc_cred
*cred
,
191 long hash
= nfs4_deviceid_hash(id
);
192 struct nfs4_deviceid_node
*d
, *new;
194 d
= __nfs4_find_get_deviceid(server
, id
, hash
);
198 new = nfs4_get_device_info(server
, id
, cred
, gfp_mask
);
202 spin_lock(&nfs4_deviceid_lock
);
203 d
= __nfs4_find_get_deviceid(server
, id
, hash
);
205 spin_unlock(&nfs4_deviceid_lock
);
206 server
->pnfs_curr_ld
->free_deviceid_node(new);
209 hlist_add_head_rcu(&new->node
, &nfs4_deviceid_cache
[hash
]);
210 atomic_inc(&new->ref
);
211 spin_unlock(&nfs4_deviceid_lock
);
215 EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid
);
218 * Remove a deviceid from cache
220 * @clp nfs_client associated with deviceid
221 * @id the deviceid to unhash
223 * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
226 nfs4_delete_deviceid(const struct pnfs_layoutdriver_type
*ld
,
227 const struct nfs_client
*clp
, const struct nfs4_deviceid
*id
)
229 struct nfs4_deviceid_node
*d
;
231 spin_lock(&nfs4_deviceid_lock
);
233 d
= _lookup_deviceid(ld
, clp
, id
, nfs4_deviceid_hash(id
));
236 spin_unlock(&nfs4_deviceid_lock
);
239 hlist_del_init_rcu(&d
->node
);
240 clear_bit(NFS_DEVICEID_NOCACHE
, &d
->flags
);
241 spin_unlock(&nfs4_deviceid_lock
);
243 /* balance the initial ref set in pnfs_insert_deviceid */
244 nfs4_put_deviceid_node(d
);
246 EXPORT_SYMBOL_GPL(nfs4_delete_deviceid
);
249 nfs4_init_deviceid_node(struct nfs4_deviceid_node
*d
, struct nfs_server
*server
,
250 const struct nfs4_deviceid
*id
)
252 INIT_HLIST_NODE(&d
->node
);
253 INIT_HLIST_NODE(&d
->tmpnode
);
254 d
->ld
= server
->pnfs_curr_ld
;
255 d
->nfs_client
= server
->nfs_client
;
258 atomic_set(&d
->ref
, 1);
260 EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node
);
263 * Dereference a deviceid node and delete it when its reference count drops
266 * @d deviceid node to put
268 * return true iff the node was deleted
269 * Note that since the test for d->ref == 0 is sufficient to establish
270 * that the node is no longer hashed in the global device id cache.
273 nfs4_put_deviceid_node(struct nfs4_deviceid_node
*d
)
275 if (test_bit(NFS_DEVICEID_NOCACHE
, &d
->flags
)) {
276 if (atomic_add_unless(&d
->ref
, -1, 2))
278 nfs4_delete_deviceid(d
->ld
, d
->nfs_client
, &d
->deviceid
);
280 if (!atomic_dec_and_test(&d
->ref
))
282 d
->ld
->free_deviceid_node(d
);
285 EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node
);
288 nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node
*node
)
290 node
->timestamp_unavailable
= jiffies
;
291 set_bit(NFS_DEVICEID_UNAVAILABLE
, &node
->flags
);
293 EXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable
);
296 nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node
*node
)
298 if (test_bit(NFS_DEVICEID_UNAVAILABLE
, &node
->flags
)) {
299 unsigned long start
, end
;
302 start
= end
- PNFS_DEVICE_RETRY_TIMEOUT
;
303 if (time_in_range(node
->timestamp_unavailable
, start
, end
))
305 clear_bit(NFS_DEVICEID_UNAVAILABLE
, &node
->flags
);
309 EXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable
);
312 _deviceid_purge_client(const struct nfs_client
*clp
, long hash
)
314 struct nfs4_deviceid_node
*d
;
317 spin_lock(&nfs4_deviceid_lock
);
319 hlist_for_each_entry_rcu(d
, &nfs4_deviceid_cache
[hash
], node
)
320 if (d
->nfs_client
== clp
&& atomic_read(&d
->ref
)) {
321 hlist_del_init_rcu(&d
->node
);
322 hlist_add_head(&d
->tmpnode
, &tmp
);
323 clear_bit(NFS_DEVICEID_NOCACHE
, &d
->flags
);
326 spin_unlock(&nfs4_deviceid_lock
);
328 if (hlist_empty(&tmp
))
331 while (!hlist_empty(&tmp
)) {
332 d
= hlist_entry(tmp
.first
, struct nfs4_deviceid_node
, tmpnode
);
333 hlist_del(&d
->tmpnode
);
334 nfs4_put_deviceid_node(d
);
339 nfs4_deviceid_purge_client(const struct nfs_client
*clp
)
343 if (!(clp
->cl_exchange_flags
& EXCHGID4_FLAG_USE_PNFS_MDS
))
345 for (h
= 0; h
< NFS4_DEVICE_ID_HASH_SIZE
; h
++)
346 _deviceid_purge_client(clp
, h
);
350 * Stop use of all deviceids associated with an nfs_client
353 nfs4_deviceid_mark_client_invalid(struct nfs_client
*clp
)
355 struct nfs4_deviceid_node
*d
;
359 for (i
= 0; i
< NFS4_DEVICE_ID_HASH_SIZE
; i
++){
360 hlist_for_each_entry_rcu(d
, &nfs4_deviceid_cache
[i
], node
)
361 if (d
->nfs_client
== clp
)
362 set_bit(NFS_DEVICEID_INVALID
, &d
->flags
);