diff options
Diffstat (limited to 'fs/nfs/pnfs_dev.c')
-rw-r--r-- | fs/nfs/pnfs_dev.c | 150 |
1 files changed, 104 insertions, 46 deletions
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c index 6da209bd9408..aa2ec0015183 100644 --- a/fs/nfs/pnfs_dev.c +++ b/fs/nfs/pnfs_dev.c | |||
@@ -29,6 +29,9 @@ | |||
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/export.h> | 31 | #include <linux/export.h> |
32 | #include <linux/nfs_fs.h> | ||
33 | #include "nfs4session.h" | ||
34 | #include "internal.h" | ||
32 | #include "pnfs.h" | 35 | #include "pnfs.h" |
33 | 36 | ||
34 | #define NFSDBG_FACILITY NFSDBG_PNFS | 37 | #define NFSDBG_FACILITY NFSDBG_PNFS |
@@ -89,6 +92,74 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
89 | return NULL; | 92 | return NULL; |
90 | } | 93 | } |
91 | 94 | ||
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) | ||
99 | { | ||
100 | struct nfs4_deviceid_node *d = NULL; | ||
101 | struct pnfs_device *pdev = NULL; | ||
102 | struct page **pages = NULL; | ||
103 | u32 max_resp_sz; | ||
104 | int max_pages; | ||
105 | int rc, i; | ||
106 | |||
107 | /* | ||
108 | * Use the session max response size as the basis for setting | ||
109 | * GETDEVICEINFO's maxcount | ||
110 | */ | ||
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); | ||
118 | |||
119 | pdev = kzalloc(sizeof(*pdev), gfp_flags); | ||
120 | if (!pdev) | ||
121 | return NULL; | ||
122 | |||
123 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); | ||
124 | if (!pages) | ||
125 | goto out_free_pdev; | ||
126 | |||
127 | for (i = 0; i < max_pages; i++) { | ||
128 | pages[i] = alloc_page(gfp_flags); | ||
129 | if (!pages[i]) | ||
130 | goto out_free_pages; | ||
131 | } | ||
132 | |||
133 | memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); | ||
134 | pdev->layout_type = server->pnfs_curr_ld->id; | ||
135 | pdev->pages = pages; | ||
136 | pdev->pgbase = 0; | ||
137 | pdev->pglen = max_resp_sz; | ||
138 | pdev->mincount = 0; | ||
139 | pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead; | ||
140 | |||
141 | rc = nfs4_proc_getdeviceinfo(server, pdev, cred); | ||
142 | dprintk("%s getdevice info returns %d\n", __func__, rc); | ||
143 | if (rc) | ||
144 | goto out_free_pages; | ||
145 | |||
146 | /* | ||
147 | * Found new device, need to decode it and then add it to the | ||
148 | * list of known devices for this mountpoint. | ||
149 | */ | ||
150 | d = server->pnfs_curr_ld->alloc_deviceid_node(server, pdev, | ||
151 | gfp_flags); | ||
152 | |||
153 | out_free_pages: | ||
154 | for (i = 0; i < max_pages; i++) | ||
155 | __free_page(pages[i]); | ||
156 | kfree(pages); | ||
157 | out_free_pdev: | ||
158 | kfree(pdev); | ||
159 | dprintk("<-- %s d %p\n", __func__, d); | ||
160 | return d; | ||
161 | } | ||
162 | |||
92 | /* | 163 | /* |
93 | * Lookup a deviceid in cache and get a reference count on it if found | 164 | * Lookup a deviceid in cache and get a reference count on it if found |
94 | * | 165 | * |
@@ -96,14 +167,14 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
96 | * @id deviceid to look up | 167 | * @id deviceid to look up |
97 | */ | 168 | */ |
98 | static struct nfs4_deviceid_node * | 169 | static struct nfs4_deviceid_node * |
99 | _find_get_deviceid(const struct pnfs_layoutdriver_type *ld, | 170 | __nfs4_find_get_deviceid(struct nfs_server *server, |
100 | const struct nfs_client *clp, const struct nfs4_deviceid *id, | 171 | const struct nfs4_deviceid *id, long hash) |
101 | long hash) | ||
102 | { | 172 | { |
103 | struct nfs4_deviceid_node *d; | 173 | struct nfs4_deviceid_node *d; |
104 | 174 | ||
105 | rcu_read_lock(); | 175 | rcu_read_lock(); |
106 | d = _lookup_deviceid(ld, clp, id, hash); | 176 | d = _lookup_deviceid(server->pnfs_curr_ld, server->nfs_client, id, |
177 | hash); | ||
107 | if (d != NULL) | 178 | if (d != NULL) |
108 | atomic_inc(&d->ref); | 179 | atomic_inc(&d->ref); |
109 | rcu_read_unlock(); | 180 | rcu_read_unlock(); |
@@ -111,10 +182,33 @@ _find_get_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
111 | } | 182 | } |
112 | 183 | ||
113 | struct nfs4_deviceid_node * | 184 | struct nfs4_deviceid_node * |
114 | nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld, | 185 | nfs4_find_get_deviceid(struct nfs_server *server, |
115 | const struct nfs_client *clp, const struct nfs4_deviceid *id) | 186 | const struct nfs4_deviceid *id, struct rpc_cred *cred, |
187 | gfp_t gfp_mask) | ||
116 | { | 188 | { |
117 | return _find_get_deviceid(ld, clp, id, nfs4_deviceid_hash(id)); | 189 | long hash = nfs4_deviceid_hash(id); |
190 | struct nfs4_deviceid_node *d, *new; | ||
191 | |||
192 | d = __nfs4_find_get_deviceid(server, id, hash); | ||
193 | if (d) | ||
194 | return d; | ||
195 | |||
196 | new = nfs4_get_device_info(server, id, cred, gfp_mask); | ||
197 | if (!new) | ||
198 | return new; | ||
199 | |||
200 | spin_lock(&nfs4_deviceid_lock); | ||
201 | d = __nfs4_find_get_deviceid(server, id, hash); | ||
202 | if (d) { | ||
203 | spin_unlock(&nfs4_deviceid_lock); | ||
204 | server->pnfs_curr_ld->free_deviceid_node(new); | ||
205 | return d; | ||
206 | } | ||
207 | hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]); | ||
208 | atomic_inc(&new->ref); | ||
209 | spin_unlock(&nfs4_deviceid_lock); | ||
210 | |||
211 | return new; | ||
118 | } | 212 | } |
119 | EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); | 213 | EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); |
120 | 214 | ||
@@ -151,15 +245,13 @@ nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
151 | EXPORT_SYMBOL_GPL(nfs4_delete_deviceid); | 245 | EXPORT_SYMBOL_GPL(nfs4_delete_deviceid); |
152 | 246 | ||
153 | void | 247 | void |
154 | nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, | 248 | nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, struct nfs_server *server, |
155 | const struct pnfs_layoutdriver_type *ld, | ||
156 | const struct nfs_client *nfs_client, | ||
157 | const struct nfs4_deviceid *id) | 249 | const struct nfs4_deviceid *id) |
158 | { | 250 | { |
159 | INIT_HLIST_NODE(&d->node); | 251 | INIT_HLIST_NODE(&d->node); |
160 | INIT_HLIST_NODE(&d->tmpnode); | 252 | INIT_HLIST_NODE(&d->tmpnode); |
161 | d->ld = ld; | 253 | d->ld = server->pnfs_curr_ld; |
162 | d->nfs_client = nfs_client; | 254 | d->nfs_client = server->nfs_client; |
163 | d->flags = 0; | 255 | d->flags = 0; |
164 | d->deviceid = *id; | 256 | d->deviceid = *id; |
165 | atomic_set(&d->ref, 1); | 257 | atomic_set(&d->ref, 1); |
@@ -167,39 +259,6 @@ nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, | |||
167 | EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node); | 259 | EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node); |
168 | 260 | ||
169 | /* | 261 | /* |
170 | * Uniquely initialize and insert a deviceid node into cache | ||
171 | * | ||
172 | * @new new deviceid node | ||
173 | * Note that the caller must set up the following members: | ||
174 | * new->ld | ||
175 | * new->nfs_client | ||
176 | * new->deviceid | ||
177 | * | ||
178 | * @ret the inserted node, if none found, otherwise, the found entry. | ||
179 | */ | ||
180 | struct nfs4_deviceid_node * | ||
181 | nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new) | ||
182 | { | ||
183 | struct nfs4_deviceid_node *d; | ||
184 | long hash; | ||
185 | |||
186 | spin_lock(&nfs4_deviceid_lock); | ||
187 | hash = nfs4_deviceid_hash(&new->deviceid); | ||
188 | d = _find_get_deviceid(new->ld, new->nfs_client, &new->deviceid, hash); | ||
189 | if (d) { | ||
190 | spin_unlock(&nfs4_deviceid_lock); | ||
191 | return d; | ||
192 | } | ||
193 | |||
194 | hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]); | ||
195 | spin_unlock(&nfs4_deviceid_lock); | ||
196 | atomic_inc(&new->ref); | ||
197 | |||
198 | return new; | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node); | ||
201 | |||
202 | /* | ||
203 | * Dereference a deviceid node and delete it when its reference count drops | 262 | * Dereference a deviceid node and delete it when its reference count drops |
204 | * to zero. | 263 | * to zero. |
205 | * | 264 | * |
@@ -299,4 +358,3 @@ nfs4_deviceid_mark_client_invalid(struct nfs_client *clp) | |||
299 | } | 358 | } |
300 | rcu_read_unlock(); | 359 | rcu_read_unlock(); |
301 | } | 360 | } |
302 | |||