diff options
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 46 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.h | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 106 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 147 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 48 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 1 |
6 files changed, 92 insertions, 264 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 6a424c19abea..a922e75af42e 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -42,32 +42,6 @@ MODULE_DESCRIPTION("The NFSv4 file layout driver"); | |||
42 | 42 | ||
43 | #define FILELAYOUT_POLL_RETRY_MAX (15*HZ) | 43 | #define FILELAYOUT_POLL_RETRY_MAX (15*HZ) |
44 | 44 | ||
45 | static int | ||
46 | filelayout_set_layoutdriver(struct nfs_server *nfss) | ||
47 | { | ||
48 | int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client, | ||
49 | nfs4_fl_free_deviceid_callback); | ||
50 | if (status) { | ||
51 | printk(KERN_WARNING "%s: deviceid cache could not be " | ||
52 | "initialized\n", __func__); | ||
53 | return status; | ||
54 | } | ||
55 | dprintk("%s: deviceid cache has been initialized successfully\n", | ||
56 | __func__); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* Clear out the layout by destroying its device list */ | ||
61 | static int | ||
62 | filelayout_clear_layoutdriver(struct nfs_server *nfss) | ||
63 | { | ||
64 | dprintk("--> %s\n", __func__); | ||
65 | |||
66 | if (nfss->nfs_client->cl_devid_cache) | ||
67 | pnfs_put_deviceid_cache(nfss->nfs_client); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static loff_t | 45 | static loff_t |
72 | filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg, | 46 | filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg, |
73 | loff_t offset) | 47 | loff_t offset) |
@@ -295,7 +269,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, | |||
295 | } | 269 | } |
296 | 270 | ||
297 | /* find and reference the deviceid */ | 271 | /* find and reference the deviceid */ |
298 | dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id); | 272 | dsaddr = nfs4_fl_find_get_deviceid(id); |
299 | if (dsaddr == NULL) { | 273 | if (dsaddr == NULL) { |
300 | dsaddr = get_device_info(lo->plh_inode, id); | 274 | dsaddr = get_device_info(lo->plh_inode, id); |
301 | if (dsaddr == NULL) | 275 | if (dsaddr == NULL) |
@@ -330,7 +304,7 @@ out: | |||
330 | dprintk("--> %s returns %d\n", __func__, status); | 304 | dprintk("--> %s returns %d\n", __func__, status); |
331 | return status; | 305 | return status; |
332 | out_put: | 306 | out_put: |
333 | pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid); | 307 | nfs4_fl_put_deviceid(dsaddr); |
334 | goto out; | 308 | goto out; |
335 | } | 309 | } |
336 | 310 | ||
@@ -439,12 +413,10 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | |||
439 | static void | 413 | static void |
440 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) | 414 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) |
441 | { | 415 | { |
442 | struct nfs_server *nfss = NFS_SERVER(lseg->pls_layout->plh_inode); | ||
443 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 416 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
444 | 417 | ||
445 | dprintk("--> %s\n", __func__); | 418 | dprintk("--> %s\n", __func__); |
446 | pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, | 419 | nfs4_fl_put_deviceid(fl->dsaddr); |
447 | &fl->dsaddr->deviceid); | ||
448 | _filelayout_free_lseg(fl); | 420 | _filelayout_free_lseg(fl); |
449 | } | 421 | } |
450 | 422 | ||
@@ -474,13 +446,11 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
474 | } | 446 | } |
475 | 447 | ||
476 | static struct pnfs_layoutdriver_type filelayout_type = { | 448 | static struct pnfs_layoutdriver_type filelayout_type = { |
477 | .id = LAYOUT_NFSV4_1_FILES, | 449 | .id = LAYOUT_NFSV4_1_FILES, |
478 | .name = "LAYOUT_NFSV4_1_FILES", | 450 | .name = "LAYOUT_NFSV4_1_FILES", |
479 | .owner = THIS_MODULE, | 451 | .owner = THIS_MODULE, |
480 | .set_layoutdriver = filelayout_set_layoutdriver, | 452 | .alloc_lseg = filelayout_alloc_lseg, |
481 | .clear_layoutdriver = filelayout_clear_layoutdriver, | 453 | .free_lseg = filelayout_free_lseg, |
482 | .alloc_lseg = filelayout_alloc_lseg, | ||
483 | .free_lseg = filelayout_free_lseg, | ||
484 | .pg_test = filelayout_pg_test, | 454 | .pg_test = filelayout_pg_test, |
485 | .read_pagelist = filelayout_read_pagelist, | 455 | .read_pagelist = filelayout_read_pagelist, |
486 | }; | 456 | }; |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 9fef76e04936..23f1e1e2a0f5 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -56,7 +56,9 @@ struct nfs4_pnfs_ds { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct nfs4_file_layout_dsaddr { | 58 | struct nfs4_file_layout_dsaddr { |
59 | struct pnfs_deviceid_node deviceid; | 59 | struct hlist_node node; |
60 | struct nfs4_deviceid deviceid; | ||
61 | atomic_t ref; | ||
60 | u32 stripe_count; | 62 | u32 stripe_count; |
61 | u8 *stripe_indices; | 63 | u8 *stripe_indices; |
62 | u32 ds_num; | 64 | u32 ds_num; |
@@ -86,7 +88,6 @@ FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) | |||
86 | extern struct nfs_fh * | 88 | extern struct nfs_fh * |
87 | nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); | 89 | nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); |
88 | 90 | ||
89 | extern void nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *); | ||
90 | extern void print_ds(struct nfs4_pnfs_ds *ds); | 91 | extern void print_ds(struct nfs4_pnfs_ds *ds); |
91 | extern void print_deviceid(struct nfs4_deviceid *dev_id); | 92 | extern void print_deviceid(struct nfs4_deviceid *dev_id); |
92 | u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset); | 93 | u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset); |
@@ -94,7 +95,8 @@ u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j); | |||
94 | struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, | 95 | struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, |
95 | u32 ds_idx); | 96 | u32 ds_idx); |
96 | extern struct nfs4_file_layout_dsaddr * | 97 | extern struct nfs4_file_layout_dsaddr * |
97 | nfs4_fl_find_get_deviceid(struct nfs_client *, struct nfs4_deviceid *dev_id); | 98 | nfs4_fl_find_get_deviceid(struct nfs4_deviceid *dev_id); |
99 | extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); | ||
98 | struct nfs4_file_layout_dsaddr * | 100 | struct nfs4_file_layout_dsaddr * |
99 | get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id); | 101 | get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id); |
100 | 102 | ||
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 | /* |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 86c154bad5db..1f4c153441a1 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -75,10 +75,8 @@ find_pnfs_driver(u32 id) | |||
75 | void | 75 | void |
76 | unset_pnfs_layoutdriver(struct nfs_server *nfss) | 76 | unset_pnfs_layoutdriver(struct nfs_server *nfss) |
77 | { | 77 | { |
78 | if (nfss->pnfs_curr_ld) { | 78 | if (nfss->pnfs_curr_ld) |
79 | nfss->pnfs_curr_ld->clear_layoutdriver(nfss); | ||
80 | module_put(nfss->pnfs_curr_ld->owner); | 79 | module_put(nfss->pnfs_curr_ld->owner); |
81 | } | ||
82 | nfss->pnfs_curr_ld = NULL; | 80 | nfss->pnfs_curr_ld = NULL; |
83 | } | 81 | } |
84 | 82 | ||
@@ -116,13 +114,7 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id) | |||
116 | goto out_no_driver; | 114 | goto out_no_driver; |
117 | } | 115 | } |
118 | server->pnfs_curr_ld = ld_type; | 116 | server->pnfs_curr_ld = ld_type; |
119 | if (ld_type->set_layoutdriver(server)) { | 117 | |
120 | printk(KERN_ERR | ||
121 | "%s: Error initializing mount point for layout driver %u.\n", | ||
122 | __func__, id); | ||
123 | module_put(ld_type->owner); | ||
124 | goto out_no_driver; | ||
125 | } | ||
126 | dprintk("%s: pNFS module for %u set\n", __func__, id); | 118 | dprintk("%s: pNFS module for %u set\n", __func__, id); |
127 | return; | 119 | return; |
128 | 120 | ||
@@ -906,138 +898,3 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, | |||
906 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 898 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
907 | return trypnfs; | 899 | return trypnfs; |
908 | } | 900 | } |
909 | |||
910 | /* | ||
911 | * Device ID cache. Currently supports one layout type per struct nfs_client. | ||
912 | * Add layout type to the lookup key to expand to support multiple types. | ||
913 | */ | ||
914 | int | ||
915 | pnfs_alloc_init_deviceid_cache(struct nfs_client *clp, | ||
916 | void (*free_callback)(struct pnfs_deviceid_node *)) | ||
917 | { | ||
918 | struct pnfs_deviceid_cache *c; | ||
919 | |||
920 | c = kzalloc(sizeof(struct pnfs_deviceid_cache), GFP_KERNEL); | ||
921 | if (!c) | ||
922 | return -ENOMEM; | ||
923 | spin_lock(&clp->cl_lock); | ||
924 | if (clp->cl_devid_cache != NULL) { | ||
925 | atomic_inc(&clp->cl_devid_cache->dc_ref); | ||
926 | dprintk("%s [kref [%d]]\n", __func__, | ||
927 | atomic_read(&clp->cl_devid_cache->dc_ref)); | ||
928 | kfree(c); | ||
929 | } else { | ||
930 | /* kzalloc initializes hlists */ | ||
931 | spin_lock_init(&c->dc_lock); | ||
932 | atomic_set(&c->dc_ref, 1); | ||
933 | c->dc_free_callback = free_callback; | ||
934 | clp->cl_devid_cache = c; | ||
935 | dprintk("%s [new]\n", __func__); | ||
936 | } | ||
937 | spin_unlock(&clp->cl_lock); | ||
938 | return 0; | ||
939 | } | ||
940 | EXPORT_SYMBOL_GPL(pnfs_alloc_init_deviceid_cache); | ||
941 | |||
942 | /* | ||
943 | * Called from pnfs_layoutdriver_type->free_lseg | ||
944 | * last layout segment reference frees deviceid | ||
945 | */ | ||
946 | void | ||
947 | pnfs_put_deviceid(struct pnfs_deviceid_cache *c, | ||
948 | struct pnfs_deviceid_node *devid) | ||
949 | { | ||
950 | struct nfs4_deviceid *id = &devid->de_id; | ||
951 | struct pnfs_deviceid_node *d; | ||
952 | struct hlist_node *n; | ||
953 | long h = nfs4_deviceid_hash(id); | ||
954 | |||
955 | dprintk("%s [%d]\n", __func__, atomic_read(&devid->de_ref)); | ||
956 | if (!atomic_dec_and_lock(&devid->de_ref, &c->dc_lock)) | ||
957 | return; | ||
958 | |||
959 | hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[h], de_node) | ||
960 | if (!memcmp(&d->de_id, id, sizeof(*id))) { | ||
961 | hlist_del_rcu(&d->de_node); | ||
962 | spin_unlock(&c->dc_lock); | ||
963 | synchronize_rcu(); | ||
964 | c->dc_free_callback(devid); | ||
965 | return; | ||
966 | } | ||
967 | spin_unlock(&c->dc_lock); | ||
968 | /* Why wasn't it found in the list? */ | ||
969 | BUG(); | ||
970 | } | ||
971 | EXPORT_SYMBOL_GPL(pnfs_put_deviceid); | ||
972 | |||
973 | /* Find and reference a deviceid */ | ||
974 | struct pnfs_deviceid_node * | ||
975 | pnfs_find_get_deviceid(struct pnfs_deviceid_cache *c, struct nfs4_deviceid *id) | ||
976 | { | ||
977 | struct pnfs_deviceid_node *d; | ||
978 | struct hlist_node *n; | ||
979 | long hash = nfs4_deviceid_hash(id); | ||
980 | |||
981 | dprintk("--> %s hash %ld\n", __func__, hash); | ||
982 | rcu_read_lock(); | ||
983 | hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) { | ||
984 | if (!memcmp(&d->de_id, id, sizeof(*id))) { | ||
985 | if (!atomic_inc_not_zero(&d->de_ref)) { | ||
986 | goto fail; | ||
987 | } else { | ||
988 | rcu_read_unlock(); | ||
989 | return d; | ||
990 | } | ||
991 | } | ||
992 | } | ||
993 | fail: | ||
994 | rcu_read_unlock(); | ||
995 | return NULL; | ||
996 | } | ||
997 | EXPORT_SYMBOL_GPL(pnfs_find_get_deviceid); | ||
998 | |||
999 | /* | ||
1000 | * Add a deviceid to the cache. | ||
1001 | * GETDEVICEINFOs for same deviceid can race. If deviceid is found, discard new | ||
1002 | */ | ||
1003 | struct pnfs_deviceid_node * | ||
1004 | pnfs_add_deviceid(struct pnfs_deviceid_cache *c, struct pnfs_deviceid_node *new) | ||
1005 | { | ||
1006 | struct pnfs_deviceid_node *d; | ||
1007 | long hash = nfs4_deviceid_hash(&new->de_id); | ||
1008 | |||
1009 | dprintk("--> %s hash %ld\n", __func__, hash); | ||
1010 | spin_lock(&c->dc_lock); | ||
1011 | d = pnfs_find_get_deviceid(c, &new->de_id); | ||
1012 | if (d) { | ||
1013 | spin_unlock(&c->dc_lock); | ||
1014 | dprintk("%s [discard]\n", __func__); | ||
1015 | c->dc_free_callback(new); | ||
1016 | return d; | ||
1017 | } | ||
1018 | INIT_HLIST_NODE(&new->de_node); | ||
1019 | atomic_set(&new->de_ref, 1); | ||
1020 | hlist_add_head_rcu(&new->de_node, &c->dc_deviceids[hash]); | ||
1021 | spin_unlock(&c->dc_lock); | ||
1022 | dprintk("%s [new]\n", __func__); | ||
1023 | return new; | ||
1024 | } | ||
1025 | EXPORT_SYMBOL_GPL(pnfs_add_deviceid); | ||
1026 | |||
1027 | void | ||
1028 | pnfs_put_deviceid_cache(struct nfs_client *clp) | ||
1029 | { | ||
1030 | struct pnfs_deviceid_cache *local = clp->cl_devid_cache; | ||
1031 | |||
1032 | dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref)); | ||
1033 | if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) { | ||
1034 | int i; | ||
1035 | /* Verify cache is empty */ | ||
1036 | for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++) | ||
1037 | BUG_ON(!hlist_empty(&local->dc_deviceids[i])); | ||
1038 | clp->cl_devid_cache = NULL; | ||
1039 | spin_unlock(&clp->cl_lock); | ||
1040 | kfree(local); | ||
1041 | } | ||
1042 | } | ||
1043 | EXPORT_SYMBOL_GPL(pnfs_put_deviceid_cache); | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 585023fabb55..acbb77802075 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -68,8 +68,6 @@ struct pnfs_layoutdriver_type { | |||
68 | const u32 id; | 68 | const u32 id; |
69 | const char *name; | 69 | const char *name; |
70 | struct module *owner; | 70 | struct module *owner; |
71 | int (*set_layoutdriver) (struct nfs_server *); | ||
72 | int (*clear_layoutdriver) (struct nfs_server *); | ||
73 | struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr); | 71 | struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr); |
74 | void (*free_lseg) (struct pnfs_layout_segment *lseg); | 72 | void (*free_lseg) (struct pnfs_layout_segment *lseg); |
75 | 73 | ||
@@ -106,52 +104,6 @@ struct pnfs_device { | |||
106 | unsigned int pglen; | 104 | unsigned int pglen; |
107 | }; | 105 | }; |
108 | 106 | ||
109 | /* | ||
110 | * Device ID RCU cache. A device ID is unique per client ID and layout type. | ||
111 | */ | ||
112 | #define NFS4_DEVICE_ID_HASH_BITS 5 | ||
113 | #define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS) | ||
114 | #define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1) | ||
115 | |||
116 | static inline u32 | ||
117 | nfs4_deviceid_hash(struct nfs4_deviceid *id) | ||
118 | { | ||
119 | unsigned char *cptr = (unsigned char *)id->data; | ||
120 | unsigned int nbytes = NFS4_DEVICEID4_SIZE; | ||
121 | u32 x = 0; | ||
122 | |||
123 | while (nbytes--) { | ||
124 | x *= 37; | ||
125 | x += *cptr++; | ||
126 | } | ||
127 | return x & NFS4_DEVICE_ID_HASH_MASK; | ||
128 | } | ||
129 | |||
130 | struct pnfs_deviceid_node { | ||
131 | struct hlist_node de_node; | ||
132 | struct nfs4_deviceid de_id; | ||
133 | atomic_t de_ref; | ||
134 | }; | ||
135 | |||
136 | struct pnfs_deviceid_cache { | ||
137 | spinlock_t dc_lock; | ||
138 | atomic_t dc_ref; | ||
139 | void (*dc_free_callback)(struct pnfs_deviceid_node *); | ||
140 | struct hlist_head dc_deviceids[NFS4_DEVICE_ID_HASH_SIZE]; | ||
141 | }; | ||
142 | |||
143 | extern int pnfs_alloc_init_deviceid_cache(struct nfs_client *, | ||
144 | void (*free_callback)(struct pnfs_deviceid_node *)); | ||
145 | extern void pnfs_put_deviceid_cache(struct nfs_client *); | ||
146 | extern struct pnfs_deviceid_node *pnfs_find_get_deviceid( | ||
147 | struct pnfs_deviceid_cache *, | ||
148 | struct nfs4_deviceid *); | ||
149 | extern struct pnfs_deviceid_node *pnfs_add_deviceid( | ||
150 | struct pnfs_deviceid_cache *, | ||
151 | struct pnfs_deviceid_node *); | ||
152 | extern void pnfs_put_deviceid(struct pnfs_deviceid_cache *c, | ||
153 | struct pnfs_deviceid_node *devid); | ||
154 | |||
155 | extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); | 107 | extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); |
156 | extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); | 108 | extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); |
157 | 109 | ||
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index c00d4ec47ec3..0cbf109a4056 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -77,7 +77,6 @@ struct nfs_client { | |||
77 | u32 cl_exchange_flags; | 77 | u32 cl_exchange_flags; |
78 | struct nfs4_session *cl_session; /* sharred session */ | 78 | struct nfs4_session *cl_session; /* sharred session */ |
79 | struct list_head cl_layouts; | 79 | struct list_head cl_layouts; |
80 | struct pnfs_deviceid_cache *cl_devid_cache; /* pNFS deviceid cache */ | ||
81 | #endif /* CONFIG_NFS_V4 */ | 80 | #endif /* CONFIG_NFS_V4 */ |
82 | 81 | ||
83 | #ifdef CONFIG_NFS_FSCACHE | 82 | #ifdef CONFIG_NFS_FSCACHE |