diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-02-28 20:34:21 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-11 15:38:43 -0500 |
commit | ea8eecdd11ee6becd09c095c8efa88aa7df95961 (patch) | |
tree | 4db9c584989d006790637e255657a010c8243cb9 /fs/nfs/nfs4filelayoutdev.c | |
parent | cbdabc7f8bf14ca1d40ab1cb86f64b3bc09716e8 (diff) |
NFSv4.1 move deviceid cache to filelayout driver
No need for generic cache with only one user.
Keep a simple hash of deviceids in the filelayout driver.
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Acked-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4filelayoutdev.c')
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 106 |
1 files changed, 77 insertions, 29 deletions
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index f466fed2f466..f594ca35a996 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -37,6 +37,30 @@ | |||
37 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 37 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * Device ID RCU cache. A device ID is unique per client ID and layout type. | ||
41 | */ | ||
42 | #define NFS4_FL_DEVICE_ID_HASH_BITS 5 | ||
43 | #define NFS4_FL_DEVICE_ID_HASH_SIZE (1 << NFS4_FL_DEVICE_ID_HASH_BITS) | ||
44 | #define NFS4_FL_DEVICE_ID_HASH_MASK (NFS4_FL_DEVICE_ID_HASH_SIZE - 1) | ||
45 | |||
46 | static inline u32 | ||
47 | nfs4_fl_deviceid_hash(struct nfs4_deviceid *id) | ||
48 | { | ||
49 | unsigned char *cptr = (unsigned char *)id->data; | ||
50 | unsigned int nbytes = NFS4_DEVICEID4_SIZE; | ||
51 | u32 x = 0; | ||
52 | |||
53 | while (nbytes--) { | ||
54 | x *= 37; | ||
55 | x += *cptr++; | ||
56 | } | ||
57 | return x & NFS4_FL_DEVICE_ID_HASH_MASK; | ||
58 | } | ||
59 | |||
60 | static struct hlist_head filelayout_deviceid_cache[NFS4_FL_DEVICE_ID_HASH_SIZE]; | ||
61 | static DEFINE_SPINLOCK(filelayout_deviceid_lock); | ||
62 | |||
63 | /* | ||
40 | * Data server cache | 64 | * Data server cache |
41 | * | 65 | * |
42 | * Data servers can be mapped to different device ids. | 66 | * Data servers can be mapped to different device ids. |
@@ -183,7 +207,7 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | |||
183 | struct nfs4_pnfs_ds *ds; | 207 | struct nfs4_pnfs_ds *ds; |
184 | int i; | 208 | int i; |
185 | 209 | ||
186 | print_deviceid(&dsaddr->deviceid.de_id); | 210 | print_deviceid(&dsaddr->deviceid); |
187 | 211 | ||
188 | for (i = 0; i < dsaddr->ds_num; i++) { | 212 | for (i = 0; i < dsaddr->ds_num; i++) { |
189 | ds = dsaddr->ds_list[i]; | 213 | ds = dsaddr->ds_list[i]; |
@@ -200,15 +224,6 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | |||
200 | kfree(dsaddr); | 224 | kfree(dsaddr); |
201 | } | 225 | } |
202 | 226 | ||
203 | void | ||
204 | nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *device) | ||
205 | { | ||
206 | struct nfs4_file_layout_dsaddr *dsaddr = | ||
207 | container_of(device, struct nfs4_file_layout_dsaddr, deviceid); | ||
208 | |||
209 | nfs4_fl_free_deviceid(dsaddr); | ||
210 | } | ||
211 | |||
212 | static struct nfs4_pnfs_ds * | 227 | static struct nfs4_pnfs_ds * |
213 | nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port) | 228 | nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port) |
214 | { | 229 | { |
@@ -361,7 +376,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev) | |||
361 | dsaddr->stripe_count = cnt; | 376 | dsaddr->stripe_count = cnt; |
362 | dsaddr->ds_num = num; | 377 | dsaddr->ds_num = num; |
363 | 378 | ||
364 | memcpy(&dsaddr->deviceid.de_id, &pdev->dev_id, sizeof(pdev->dev_id)); | 379 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); |
365 | 380 | ||
366 | /* Go back an read stripe indices */ | 381 | /* Go back an read stripe indices */ |
367 | p = indicesp; | 382 | p = indicesp; |
@@ -411,28 +426,37 @@ out_err: | |||
411 | } | 426 | } |
412 | 427 | ||
413 | /* | 428 | /* |
414 | * Decode the opaque device specified in 'dev' | 429 | * Decode the opaque device specified in 'dev' and add it to the cache of |
415 | * and add it to the list of available devices. | 430 | * available devices. |
416 | * If the deviceid is already cached, nfs4_add_deviceid will return | ||
417 | * a pointer to the cached struct and throw away the new. | ||
418 | */ | 431 | */ |
419 | static struct nfs4_file_layout_dsaddr* | 432 | static struct nfs4_file_layout_dsaddr * |
420 | decode_and_add_device(struct inode *inode, struct pnfs_device *dev) | 433 | decode_and_add_device(struct inode *inode, struct pnfs_device *dev) |
421 | { | 434 | { |
422 | struct nfs4_file_layout_dsaddr *dsaddr; | 435 | struct nfs4_file_layout_dsaddr *d, *new; |
423 | struct pnfs_deviceid_node *d; | 436 | long hash; |
424 | 437 | ||
425 | dsaddr = decode_device(inode, dev); | 438 | new = decode_device(inode, dev); |
426 | if (!dsaddr) { | 439 | if (!new) { |
427 | printk(KERN_WARNING "%s: Could not decode or add device\n", | 440 | printk(KERN_WARNING "%s: Could not decode or add device\n", |
428 | __func__); | 441 | __func__); |
429 | return NULL; | 442 | return NULL; |
430 | } | 443 | } |
431 | 444 | ||
432 | d = pnfs_add_deviceid(NFS_SERVER(inode)->nfs_client->cl_devid_cache, | 445 | spin_lock(&filelayout_deviceid_lock); |
433 | &dsaddr->deviceid); | 446 | d = nfs4_fl_find_get_deviceid(&new->deviceid); |
447 | if (d) { | ||
448 | spin_unlock(&filelayout_deviceid_lock); | ||
449 | nfs4_fl_free_deviceid(new); | ||
450 | return d; | ||
451 | } | ||
452 | |||
453 | INIT_HLIST_NODE(&new->node); | ||
454 | atomic_set(&new->ref, 1); | ||
455 | hash = nfs4_fl_deviceid_hash(&new->deviceid); | ||
456 | hlist_add_head_rcu(&new->node, &filelayout_deviceid_cache[hash]); | ||
457 | spin_unlock(&filelayout_deviceid_lock); | ||
434 | 458 | ||
435 | return container_of(d, struct nfs4_file_layout_dsaddr, deviceid); | 459 | return new; |
436 | } | 460 | } |
437 | 461 | ||
438 | /* | 462 | /* |
@@ -507,14 +531,38 @@ out_free: | |||
507 | return dsaddr; | 531 | return dsaddr; |
508 | } | 532 | } |
509 | 533 | ||
510 | struct nfs4_file_layout_dsaddr * | 534 | void |
511 | nfs4_fl_find_get_deviceid(struct nfs_client *clp, struct nfs4_deviceid *id) | 535 | nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) |
512 | { | 536 | { |
513 | struct pnfs_deviceid_node *d; | 537 | if (atomic_dec_and_lock(&dsaddr->ref, &filelayout_deviceid_lock)) { |
538 | hlist_del_rcu(&dsaddr->node); | ||
539 | spin_unlock(&filelayout_deviceid_lock); | ||
540 | |||
541 | synchronize_rcu(); | ||
542 | nfs4_fl_free_deviceid(dsaddr); | ||
543 | } | ||
544 | } | ||
514 | 545 | ||
515 | d = pnfs_find_get_deviceid(clp->cl_devid_cache, id); | 546 | struct nfs4_file_layout_dsaddr * |
516 | return (d == NULL) ? NULL : | 547 | nfs4_fl_find_get_deviceid(struct nfs4_deviceid *id) |
517 | container_of(d, struct nfs4_file_layout_dsaddr, deviceid); | 548 | { |
549 | struct nfs4_file_layout_dsaddr *d; | ||
550 | struct hlist_node *n; | ||
551 | long hash = nfs4_fl_deviceid_hash(id); | ||
552 | |||
553 | |||
554 | rcu_read_lock(); | ||
555 | hlist_for_each_entry_rcu(d, n, &filelayout_deviceid_cache[hash], node) { | ||
556 | if (!memcmp(&d->deviceid, id, sizeof(*id))) { | ||
557 | if (!atomic_inc_not_zero(&d->ref)) | ||
558 | goto fail; | ||
559 | rcu_read_unlock(); | ||
560 | return d; | ||
561 | } | ||
562 | } | ||
563 | fail: | ||
564 | rcu_read_unlock(); | ||
565 | return NULL; | ||
518 | } | 566 | } |
519 | 567 | ||
520 | /* | 568 | /* |