diff options
author | Benny Halevy <bhalevy@panasas.com> | 2011-05-19 22:14:47 -0400 |
---|---|---|
committer | Boaz Harrosh <bharrosh@panasas.com> | 2011-05-29 05:09:48 -0400 |
commit | a1eaecbc4c8307e27772d6584ef85a2e93250661 (patch) | |
tree | 940549d45db98a5bcfe22501de0bbe9c96de4c8e | |
parent | 45df3c8b0f3a58facb125d7631890426706c0bfa (diff) |
NFSv4.1: make deviceid cache global
Move deviceid cache from the pnfs files layout driver to the
generic layer in preparation for the objects layout driver.
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
-rw-r--r-- | fs/nfs/Makefile | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 10 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.h | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 104 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 17 | ||||
-rw-r--r-- | fs/nfs/pnfs_dev.c | 156 |
6 files changed, 194 insertions, 103 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 4776ff9e3814..7516a8aaa42e 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -15,7 +15,7 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
15 | delegation.o idmap.o \ | 15 | delegation.o idmap.o \ |
16 | callback.o callback_xdr.o callback_proc.o \ | 16 | callback.o callback_xdr.o callback_proc.o \ |
17 | nfs4namespace.o | 17 | nfs4namespace.o |
18 | nfs-$(CONFIG_NFS_V4_1) += pnfs.o | 18 | nfs-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o |
19 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 19 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
20 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o | 20 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
21 | 21 | ||
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 571c1b032e9d..4c67a6f6519d 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -421,6 +421,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, | |||
421 | struct nfs4_deviceid *id, | 421 | struct nfs4_deviceid *id, |
422 | gfp_t gfp_flags) | 422 | gfp_t gfp_flags) |
423 | { | 423 | { |
424 | struct nfs4_deviceid_node *d; | ||
424 | struct nfs4_file_layout_dsaddr *dsaddr; | 425 | struct nfs4_file_layout_dsaddr *dsaddr; |
425 | int status = -EINVAL; | 426 | int status = -EINVAL; |
426 | struct nfs_server *nfss = NFS_SERVER(lo->plh_inode); | 427 | struct nfs_server *nfss = NFS_SERVER(lo->plh_inode); |
@@ -440,12 +441,13 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, | |||
440 | } | 441 | } |
441 | 442 | ||
442 | /* find and reference the deviceid */ | 443 | /* find and reference the deviceid */ |
443 | dsaddr = nfs4_fl_find_get_deviceid(NFS_SERVER(lo->plh_inode)->nfs_client, id); | 444 | d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->nfs_client, id); |
444 | if (dsaddr == NULL) { | 445 | if (d == NULL) { |
445 | dsaddr = get_device_info(lo->plh_inode, id, gfp_flags); | 446 | dsaddr = get_device_info(lo->plh_inode, id, gfp_flags); |
446 | if (dsaddr == NULL) | 447 | if (dsaddr == NULL) |
447 | goto out; | 448 | goto out; |
448 | } | 449 | } else |
450 | dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node); | ||
449 | fl->dsaddr = dsaddr; | 451 | fl->dsaddr = dsaddr; |
450 | 452 | ||
451 | if (fl->first_stripe_index < 0 || | 453 | if (fl->first_stripe_index < 0 || |
@@ -535,7 +537,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, | |||
535 | 537 | ||
536 | memcpy(id, p, sizeof(*id)); | 538 | memcpy(id, p, sizeof(*id)); |
537 | p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); | 539 | p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); |
538 | print_deviceid(id); | 540 | nfs4_print_deviceid(id); |
539 | 541 | ||
540 | nfl_util = be32_to_cpup(p++); | 542 | nfl_util = be32_to_cpup(p++); |
541 | if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS) | 543 | if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS) |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 301b95568bd2..0ace0a2d6d7d 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -59,10 +59,7 @@ struct nfs4_pnfs_ds { | |||
59 | #define NFS4_DEVICE_ID_NEG_ENTRY 0x00000001 | 59 | #define NFS4_DEVICE_ID_NEG_ENTRY 0x00000001 |
60 | 60 | ||
61 | struct nfs4_file_layout_dsaddr { | 61 | struct nfs4_file_layout_dsaddr { |
62 | struct hlist_node node; | 62 | struct nfs4_deviceid_node id_node; |
63 | struct nfs_client *nfs_client; | ||
64 | struct nfs4_deviceid deviceid; | ||
65 | atomic_t ref; | ||
66 | unsigned long flags; | 63 | unsigned long flags; |
67 | u32 stripe_count; | 64 | u32 stripe_count; |
68 | u8 *stripe_indices; | 65 | u8 *stripe_indices; |
@@ -96,13 +93,10 @@ extern struct nfs_fh * | |||
96 | nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); | 93 | nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); |
97 | 94 | ||
98 | extern void print_ds(struct nfs4_pnfs_ds *ds); | 95 | extern void print_ds(struct nfs4_pnfs_ds *ds); |
99 | extern void print_deviceid(struct nfs4_deviceid *dev_id); | ||
100 | u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset); | 96 | u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset); |
101 | u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j); | 97 | u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j); |
102 | struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, | 98 | struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, |
103 | u32 ds_idx); | 99 | u32 ds_idx); |
104 | extern struct nfs4_file_layout_dsaddr * | ||
105 | nfs4_fl_find_get_deviceid(struct nfs_client *, struct nfs4_deviceid *dev_id); | ||
106 | extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); | 100 | extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); |
107 | struct nfs4_file_layout_dsaddr * | 101 | struct nfs4_file_layout_dsaddr * |
108 | get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); | 102 | get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 42e326637271..eda4527a57eb 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -37,30 +37,6 @@ | |||
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 | /* | ||
64 | * Data server cache | 40 | * Data server cache |
65 | * | 41 | * |
66 | * Data servers can be mapped to different device ids. | 42 | * Data servers can be mapped to different device ids. |
@@ -89,27 +65,6 @@ print_ds(struct nfs4_pnfs_ds *ds) | |||
89 | ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); | 65 | ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); |
90 | } | 66 | } |
91 | 67 | ||
92 | void | ||
93 | print_ds_list(struct nfs4_file_layout_dsaddr *dsaddr) | ||
94 | { | ||
95 | int i; | ||
96 | |||
97 | ifdebug(FACILITY) { | ||
98 | printk("%s dsaddr->ds_num %d\n", __func__, | ||
99 | dsaddr->ds_num); | ||
100 | for (i = 0; i < dsaddr->ds_num; i++) | ||
101 | print_ds(dsaddr->ds_list[i]); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | void print_deviceid(struct nfs4_deviceid *id) | ||
106 | { | ||
107 | u32 *p = (u32 *)id; | ||
108 | |||
109 | dprintk("%s: device id= [%x%x%x%x]\n", __func__, | ||
110 | p[0], p[1], p[2], p[3]); | ||
111 | } | ||
112 | |||
113 | /* nfs4_ds_cache_lock is held */ | 68 | /* nfs4_ds_cache_lock is held */ |
114 | static struct nfs4_pnfs_ds * | 69 | static struct nfs4_pnfs_ds * |
115 | _data_server_lookup_locked(u32 ip_addr, u32 port) | 70 | _data_server_lookup_locked(u32 ip_addr, u32 port) |
@@ -207,7 +162,7 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | |||
207 | struct nfs4_pnfs_ds *ds; | 162 | struct nfs4_pnfs_ds *ds; |
208 | int i; | 163 | int i; |
209 | 164 | ||
210 | print_deviceid(&dsaddr->deviceid); | 165 | nfs4_print_deviceid(&dsaddr->id_node.deviceid); |
211 | 166 | ||
212 | for (i = 0; i < dsaddr->ds_num; i++) { | 167 | for (i = 0; i < dsaddr->ds_num; i++) { |
213 | ds = dsaddr->ds_list[i]; | 168 | ds = dsaddr->ds_list[i]; |
@@ -431,8 +386,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
431 | dsaddr->stripe_indices = stripe_indices; | 386 | dsaddr->stripe_indices = stripe_indices; |
432 | stripe_indices = NULL; | 387 | stripe_indices = NULL; |
433 | dsaddr->ds_num = num; | 388 | dsaddr->ds_num = num; |
434 | dsaddr->nfs_client = NFS_SERVER(ino)->nfs_client; | 389 | nfs4_init_deviceid_node(&dsaddr->id_node, NFS_SERVER(ino)->nfs_client, |
435 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); | 390 | &pdev->dev_id); |
436 | 391 | ||
437 | for (i = 0; i < dsaddr->ds_num; i++) { | 392 | for (i = 0; i < dsaddr->ds_num; i++) { |
438 | int j; | 393 | int j; |
@@ -505,8 +460,8 @@ out_err: | |||
505 | static struct nfs4_file_layout_dsaddr * | 460 | static struct nfs4_file_layout_dsaddr * |
506 | decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags) | 461 | decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags) |
507 | { | 462 | { |
508 | struct nfs4_file_layout_dsaddr *d, *new; | 463 | struct nfs4_deviceid_node *d; |
509 | long hash; | 464 | struct nfs4_file_layout_dsaddr *n, *new; |
510 | 465 | ||
511 | new = decode_device(inode, dev, gfp_flags); | 466 | new = decode_device(inode, dev, gfp_flags); |
512 | if (!new) { | 467 | if (!new) { |
@@ -515,20 +470,13 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl | |||
515 | return NULL; | 470 | return NULL; |
516 | } | 471 | } |
517 | 472 | ||
518 | spin_lock(&filelayout_deviceid_lock); | 473 | d = nfs4_insert_deviceid_node(&new->id_node); |
519 | d = nfs4_fl_find_get_deviceid(new->nfs_client, &new->deviceid); | 474 | n = container_of(d, struct nfs4_file_layout_dsaddr, id_node); |
520 | if (d) { | 475 | if (n != new) { |
521 | spin_unlock(&filelayout_deviceid_lock); | ||
522 | nfs4_fl_free_deviceid(new); | 476 | nfs4_fl_free_deviceid(new); |
523 | return d; | 477 | return n; |
524 | } | 478 | } |
525 | 479 | ||
526 | INIT_HLIST_NODE(&new->node); | ||
527 | atomic_set(&new->ref, 1); | ||
528 | hash = nfs4_fl_deviceid_hash(&new->deviceid); | ||
529 | hlist_add_head_rcu(&new->node, &filelayout_deviceid_cache[hash]); | ||
530 | spin_unlock(&filelayout_deviceid_lock); | ||
531 | |||
532 | return new; | 480 | return new; |
533 | } | 481 | } |
534 | 482 | ||
@@ -600,34 +548,8 @@ out_free: | |||
600 | void | 548 | void |
601 | nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | 549 | nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) |
602 | { | 550 | { |
603 | if (atomic_dec_and_lock(&dsaddr->ref, &filelayout_deviceid_lock)) { | 551 | if (nfs4_put_deviceid_node(&dsaddr->id_node)) |
604 | hlist_del_rcu(&dsaddr->node); | ||
605 | spin_unlock(&filelayout_deviceid_lock); | ||
606 | |||
607 | synchronize_rcu(); | ||
608 | nfs4_fl_free_deviceid(dsaddr); | 552 | nfs4_fl_free_deviceid(dsaddr); |
609 | } | ||
610 | } | ||
611 | |||
612 | struct nfs4_file_layout_dsaddr * | ||
613 | nfs4_fl_find_get_deviceid(struct nfs_client *clp, struct nfs4_deviceid *id) | ||
614 | { | ||
615 | struct nfs4_file_layout_dsaddr *d; | ||
616 | struct hlist_node *n; | ||
617 | long hash = nfs4_fl_deviceid_hash(id); | ||
618 | |||
619 | rcu_read_lock(); | ||
620 | hlist_for_each_entry_rcu(d, n, &filelayout_deviceid_cache[hash], node) { | ||
621 | if (d->nfs_client == clp && !memcmp(&d->deviceid, id, sizeof(*id))) { | ||
622 | if (!atomic_inc_not_zero(&d->ref)) | ||
623 | goto fail; | ||
624 | rcu_read_unlock(); | ||
625 | return d; | ||
626 | } | ||
627 | } | ||
628 | fail: | ||
629 | rcu_read_unlock(); | ||
630 | return NULL; | ||
631 | } | 553 | } |
632 | 554 | ||
633 | /* | 555 | /* |
@@ -675,15 +597,15 @@ static void | |||
675 | filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr, | 597 | filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr, |
676 | int err, u32 ds_addr) | 598 | int err, u32 ds_addr) |
677 | { | 599 | { |
678 | u32 *p = (u32 *)&dsaddr->deviceid; | 600 | u32 *p = (u32 *)&dsaddr->id_node.deviceid; |
679 | 601 | ||
680 | printk(KERN_ERR "NFS: data server %x connection error %d." | 602 | printk(KERN_ERR "NFS: data server %x connection error %d." |
681 | " Deviceid [%x%x%x%x] marked out of use.\n", | 603 | " Deviceid [%x%x%x%x] marked out of use.\n", |
682 | ds_addr, err, p[0], p[1], p[2], p[3]); | 604 | ds_addr, err, p[0], p[1], p[2], p[3]); |
683 | 605 | ||
684 | spin_lock(&filelayout_deviceid_lock); | 606 | spin_lock(&nfs4_ds_cache_lock); |
685 | dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY; | 607 | dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY; |
686 | spin_unlock(&filelayout_deviceid_lock); | 608 | spin_unlock(&nfs4_ds_cache_lock); |
687 | } | 609 | } |
688 | 610 | ||
689 | struct nfs4_pnfs_ds * | 611 | struct nfs4_pnfs_ds * |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 720bb9da3f9b..3831ad04a231 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -157,6 +157,23 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier); | |||
157 | void pnfs_set_layoutcommit(struct nfs_write_data *wdata); | 157 | void pnfs_set_layoutcommit(struct nfs_write_data *wdata); |
158 | int pnfs_layoutcommit_inode(struct inode *inode, bool sync); | 158 | int pnfs_layoutcommit_inode(struct inode *inode, bool sync); |
159 | 159 | ||
160 | /* pnfs_dev.c */ | ||
161 | struct nfs4_deviceid_node { | ||
162 | struct hlist_node node; | ||
163 | const struct nfs_client *nfs_client; | ||
164 | struct nfs4_deviceid deviceid; | ||
165 | atomic_t ref; | ||
166 | }; | ||
167 | |||
168 | void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id); | ||
169 | struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct nfs_client *, const struct nfs4_deviceid *); | ||
170 | struct nfs4_deviceid_node *nfs4_unhash_put_deviceid(const struct nfs_client *, const struct nfs4_deviceid *); | ||
171 | void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, | ||
172 | const struct nfs_client *, | ||
173 | const struct nfs4_deviceid *); | ||
174 | struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *); | ||
175 | bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); | ||
176 | |||
160 | static inline int lo_fail_bit(u32 iomode) | 177 | static inline int lo_fail_bit(u32 iomode) |
161 | { | 178 | { |
162 | return iomode == IOMODE_RW ? | 179 | return iomode == IOMODE_RW ? |
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c new file mode 100644 index 000000000000..bf05189a7cbf --- /dev/null +++ b/fs/nfs/pnfs_dev.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Device operations for the pnfs client. | ||
3 | * | ||
4 | * Copyright (c) 2002 | ||
5 | * The Regents of the University of Michigan | ||
6 | * All Rights Reserved | ||
7 | * | ||
8 | * Dean Hildebrand <dhildebz@umich.edu> | ||
9 | * Garth Goodson <Garth.Goodson@netapp.com> | ||
10 | * | ||
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. | ||
19 | * | ||
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 | ||
28 | * such damages. | ||
29 | */ | ||
30 | |||
31 | #include "pnfs.h" | ||
32 | |||
33 | #define NFSDBG_FACILITY NFSDBG_PNFS | ||
34 | |||
35 | /* | ||
36 | * Device ID RCU cache. A device ID is unique per server and layout type. | ||
37 | */ | ||
38 | #define NFS4_DEVICE_ID_HASH_BITS 5 | ||
39 | #define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS) | ||
40 | #define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1) | ||
41 | |||
42 | static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE]; | ||
43 | static DEFINE_SPINLOCK(nfs4_deviceid_lock); | ||
44 | |||
45 | void | ||
46 | nfs4_print_deviceid(const struct nfs4_deviceid *id) | ||
47 | { | ||
48 | u32 *p = (u32 *)id; | ||
49 | |||
50 | dprintk("%s: device id= [%x%x%x%x]\n", __func__, | ||
51 | p[0], p[1], p[2], p[3]); | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(nfs4_print_deviceid); | ||
54 | |||
55 | static inline u32 | ||
56 | nfs4_deviceid_hash(const struct nfs4_deviceid *id) | ||
57 | { | ||
58 | unsigned char *cptr = (unsigned char *)id->data; | ||
59 | unsigned int nbytes = NFS4_DEVICEID4_SIZE; | ||
60 | u32 x = 0; | ||
61 | |||
62 | while (nbytes--) { | ||
63 | x *= 37; | ||
64 | x += *cptr++; | ||
65 | } | ||
66 | return x & NFS4_DEVICE_ID_HASH_MASK; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Lookup a deviceid in cache and get a reference count on it if found | ||
71 | * | ||
72 | * @clp nfs_client associated with deviceid | ||
73 | * @id deviceid to look up | ||
74 | */ | ||
75 | struct nfs4_deviceid_node * | ||
76 | nfs4_find_get_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id) | ||
77 | { | ||
78 | struct nfs4_deviceid_node *d; | ||
79 | struct hlist_node *n; | ||
80 | long hash = nfs4_deviceid_hash(id); | ||
81 | |||
82 | rcu_read_lock(); | ||
83 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) { | ||
84 | if (d->nfs_client == clp && !memcmp(&d->deviceid, id, sizeof(*id))) { | ||
85 | if (!atomic_inc_not_zero(&d->ref)) | ||
86 | goto fail; | ||
87 | rcu_read_unlock(); | ||
88 | return d; | ||
89 | } | ||
90 | } | ||
91 | fail: | ||
92 | rcu_read_unlock(); | ||
93 | return NULL; | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); | ||
96 | |||
97 | void | ||
98 | nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, | ||
99 | const struct nfs_client *nfs_client, | ||
100 | const struct nfs4_deviceid *id) | ||
101 | { | ||
102 | d->nfs_client = nfs_client; | ||
103 | d->deviceid = *id; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node); | ||
106 | |||
107 | /* | ||
108 | * Uniquely initialize and insert a deviceid node into cache | ||
109 | * | ||
110 | * @new new deviceid node | ||
111 | * Note that the caller must set up new->nfs_client and new->deviceid | ||
112 | * | ||
113 | * @ret the inserted node, if none found, otherwise, the found entry. | ||
114 | */ | ||
115 | struct nfs4_deviceid_node * | ||
116 | nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new) | ||
117 | { | ||
118 | struct nfs4_deviceid_node *d; | ||
119 | long hash; | ||
120 | |||
121 | spin_lock(&nfs4_deviceid_lock); | ||
122 | d = nfs4_find_get_deviceid(new->nfs_client, &new->deviceid); | ||
123 | if (d) { | ||
124 | spin_unlock(&nfs4_deviceid_lock); | ||
125 | return d; | ||
126 | } | ||
127 | |||
128 | INIT_HLIST_NODE(&new->node); | ||
129 | atomic_set(&new->ref, 1); | ||
130 | hash = nfs4_deviceid_hash(&new->deviceid); | ||
131 | hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]); | ||
132 | spin_unlock(&nfs4_deviceid_lock); | ||
133 | |||
134 | return new; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node); | ||
137 | |||
138 | /* | ||
139 | * Dereference a deviceid node and delete it when its reference count drops | ||
140 | * to zero. | ||
141 | * | ||
142 | * @d deviceid node to put | ||
143 | * | ||
144 | * @ret true iff the node was deleted | ||
145 | */ | ||
146 | bool | ||
147 | nfs4_put_deviceid_node(struct nfs4_deviceid_node *d) | ||
148 | { | ||
149 | if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock)) | ||
150 | return false; | ||
151 | hlist_del_init_rcu(&d->node); | ||
152 | spin_unlock(&nfs4_deviceid_lock); | ||
153 | synchronize_rcu(); | ||
154 | return true; | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node); | ||