aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pnfs_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/pnfs_dev.c')
-rw-r--r--fs/nfs/pnfs_dev.c95
1 files changed, 81 insertions, 14 deletions
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
index 64a4b85c7dbc..8fd3839df299 100644
--- a/fs/nfs/pnfs_dev.c
+++ b/fs/nfs/pnfs_dev.c
@@ -66,6 +66,23 @@ nfs4_deviceid_hash(const struct nfs4_deviceid *id)
66 return x & NFS4_DEVICE_ID_HASH_MASK; 66 return x & NFS4_DEVICE_ID_HASH_MASK;
67} 67}
68 68
69static struct nfs4_deviceid_node *
70_lookup_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id,
71 long hash)
72{
73 struct nfs4_deviceid_node *d;
74 struct hlist_node *n;
75
76 hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node)
77 if (d->nfs_client == clp && !memcmp(&d->deviceid, id, sizeof(*id))) {
78 if (atomic_read(&d->ref))
79 return d;
80 else
81 continue;
82 }
83 return NULL;
84}
85
69/* 86/*
70 * Lookup a deviceid in cache and get a reference count on it if found 87 * Lookup a deviceid in cache and get a reference count on it if found
71 * 88 *
@@ -73,26 +90,76 @@ nfs4_deviceid_hash(const struct nfs4_deviceid *id)
73 * @id deviceid to look up 90 * @id deviceid to look up
74 */ 91 */
75struct nfs4_deviceid_node * 92struct nfs4_deviceid_node *
93_find_get_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id,
94 long hash)
95{
96 struct nfs4_deviceid_node *d;
97
98 rcu_read_lock();
99 d = _lookup_deviceid(clp, id, hash);
100 if (d && !atomic_inc_not_zero(&d->ref))
101 d = NULL;
102 rcu_read_unlock();
103 return d;
104}
105
106struct nfs4_deviceid_node *
76nfs4_find_get_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id) 107nfs4_find_get_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id)
77{ 108{
109 return _find_get_deviceid(clp, id, nfs4_deviceid_hash(id));
110}
111EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
112
113/*
114 * Unhash and put deviceid
115 *
116 * @clp nfs_client associated with deviceid
117 * @id the deviceid to unhash
118 *
119 * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
120 */
121struct nfs4_deviceid_node *
122nfs4_unhash_put_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id)
123{
78 struct nfs4_deviceid_node *d; 124 struct nfs4_deviceid_node *d;
79 struct hlist_node *n;
80 long hash = nfs4_deviceid_hash(id);
81 125
126 spin_lock(&nfs4_deviceid_lock);
82 rcu_read_lock(); 127 rcu_read_lock();
83 hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) { 128 d = _lookup_deviceid(clp, id, nfs4_deviceid_hash(id));
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 }
91fail:
92 rcu_read_unlock(); 129 rcu_read_unlock();
130 if (!d) {
131 spin_unlock(&nfs4_deviceid_lock);
132 return NULL;
133 }
134 hlist_del_init_rcu(&d->node);
135 spin_unlock(&nfs4_deviceid_lock);
136 synchronize_rcu();
137
138 /* balance the initial ref set in pnfs_insert_deviceid */
139 if (atomic_dec_and_test(&d->ref))
140 return d;
141
93 return NULL; 142 return NULL;
94} 143}
95EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); 144EXPORT_SYMBOL_GPL(nfs4_unhash_put_deviceid);
145
146/*
147 * Delete a deviceid from cache
148 *
149 * @clp struct nfs_client qualifying the deviceid
150 * @id deviceid to delete
151 */
152void
153nfs4_delete_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id)
154{
155 struct nfs4_deviceid_node *d;
156
157 d = nfs4_unhash_put_deviceid(clp, id);
158 if (!d)
159 return;
160 d->ld->free_deviceid_node(d);
161}
162EXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
96 163
97void 164void
98nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, 165nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
@@ -126,13 +193,13 @@ nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new)
126 long hash; 193 long hash;
127 194
128 spin_lock(&nfs4_deviceid_lock); 195 spin_lock(&nfs4_deviceid_lock);
129 d = nfs4_find_get_deviceid(new->nfs_client, &new->deviceid); 196 hash = nfs4_deviceid_hash(&new->deviceid);
197 d = _find_get_deviceid(new->nfs_client, &new->deviceid, hash);
130 if (d) { 198 if (d) {
131 spin_unlock(&nfs4_deviceid_lock); 199 spin_unlock(&nfs4_deviceid_lock);
132 return d; 200 return d;
133 } 201 }
134 202
135 hash = nfs4_deviceid_hash(&new->deviceid);
136 hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]); 203 hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
137 spin_unlock(&nfs4_deviceid_lock); 204 spin_unlock(&nfs4_deviceid_lock);
138 205