diff options
author | Andy Adamson <andros@netapp.com> | 2010-10-20 00:18:02 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-10-24 18:07:10 -0400 |
commit | 974cec8ca0352eb5d281535b714cf194a606e98f (patch) | |
tree | 0e71706c3091fc785bab0be8edc5de36816685ff /fs/nfs/pnfs.c | |
parent | e5e940170b2136ad4d5483ef293ae284b9cc8d53 (diff) |
NFS: client needs to maintain list of inodes with active layouts
In particular, server reboot will invalidate all layouts.
Note that in order to have an active layout, we must get a successful response
from the server. To avoid adding that machinery, this patch just includes a
stub that fakes up a successful return. Since the layout is never referenced
for io, this is not a problem.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Dean Hildebrand <dhildebz@umich.edu>
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 160 |
1 files changed, 157 insertions, 3 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c0cd954855b9..891a0c36f992 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/nfs_fs.h> | 30 | #include <linux/nfs_fs.h> |
31 | #include "internal.h" | ||
31 | #include "pnfs.h" | 32 | #include "pnfs.h" |
32 | 33 | ||
33 | #define NFSDBG_FACILITY NFSDBG_PNFS | 34 | #define NFSDBG_FACILITY NFSDBG_PNFS |
@@ -183,38 +184,189 @@ put_layout_hdr_locked(struct pnfs_layout_hdr *lo) | |||
183 | lo->refcount--; | 184 | lo->refcount--; |
184 | if (!lo->refcount) { | 185 | if (!lo->refcount) { |
185 | dprintk("%s: freeing layout cache %p\n", __func__, lo); | 186 | dprintk("%s: freeing layout cache %p\n", __func__, lo); |
187 | BUG_ON(!list_empty(&lo->layouts)); | ||
186 | NFS_I(lo->inode)->layout = NULL; | 188 | NFS_I(lo->inode)->layout = NULL; |
187 | kfree(lo); | 189 | kfree(lo); |
188 | } | 190 | } |
189 | } | 191 | } |
190 | 192 | ||
193 | static void | ||
194 | put_layout_hdr(struct inode *inode) | ||
195 | { | ||
196 | spin_lock(&inode->i_lock); | ||
197 | put_layout_hdr_locked(NFS_I(inode)->layout); | ||
198 | spin_unlock(&inode->i_lock); | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg) | ||
203 | { | ||
204 | INIT_LIST_HEAD(&lseg->fi_list); | ||
205 | kref_init(&lseg->kref); | ||
206 | lseg->layout = lo; | ||
207 | } | ||
208 | |||
209 | /* Called without i_lock held, as the free_lseg call may sleep */ | ||
210 | static void | ||
211 | destroy_lseg(struct kref *kref) | ||
212 | { | ||
213 | struct pnfs_layout_segment *lseg = | ||
214 | container_of(kref, struct pnfs_layout_segment, kref); | ||
215 | struct inode *ino = lseg->layout->inode; | ||
216 | |||
217 | dprintk("--> %s\n", __func__); | ||
218 | kfree(lseg); | ||
219 | /* Matched by get_layout_hdr_locked in pnfs_insert_layout */ | ||
220 | put_layout_hdr(ino); | ||
221 | } | ||
222 | |||
223 | static void | ||
224 | put_lseg(struct pnfs_layout_segment *lseg) | ||
225 | { | ||
226 | if (!lseg) | ||
227 | return; | ||
228 | |||
229 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, | ||
230 | atomic_read(&lseg->kref.refcount)); | ||
231 | kref_put(&lseg->kref, destroy_lseg); | ||
232 | } | ||
233 | |||
234 | static void | ||
235 | pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list) | ||
236 | { | ||
237 | struct pnfs_layout_segment *lseg, *next; | ||
238 | struct nfs_client *clp; | ||
239 | |||
240 | dprintk("%s:Begin lo %p\n", __func__, lo); | ||
241 | |||
242 | assert_spin_locked(&lo->inode->i_lock); | ||
243 | list_for_each_entry_safe(lseg, next, &lo->segs, fi_list) { | ||
244 | dprintk("%s: freeing lseg %p\n", __func__, lseg); | ||
245 | list_move(&lseg->fi_list, tmp_list); | ||
246 | } | ||
247 | clp = NFS_SERVER(lo->inode)->nfs_client; | ||
248 | spin_lock(&clp->cl_lock); | ||
249 | /* List does not take a reference, so no need for put here */ | ||
250 | list_del_init(&lo->layouts); | ||
251 | spin_unlock(&clp->cl_lock); | ||
252 | |||
253 | dprintk("%s:Return\n", __func__); | ||
254 | } | ||
255 | |||
256 | static void | ||
257 | pnfs_free_lseg_list(struct list_head *tmp_list) | ||
258 | { | ||
259 | struct pnfs_layout_segment *lseg; | ||
260 | |||
261 | while (!list_empty(tmp_list)) { | ||
262 | lseg = list_entry(tmp_list->next, struct pnfs_layout_segment, | ||
263 | fi_list); | ||
264 | dprintk("%s calling put_lseg on %p\n", __func__, lseg); | ||
265 | list_del(&lseg->fi_list); | ||
266 | put_lseg(lseg); | ||
267 | } | ||
268 | } | ||
269 | |||
191 | void | 270 | void |
192 | pnfs_destroy_layout(struct nfs_inode *nfsi) | 271 | pnfs_destroy_layout(struct nfs_inode *nfsi) |
193 | { | 272 | { |
194 | struct pnfs_layout_hdr *lo; | 273 | struct pnfs_layout_hdr *lo; |
274 | LIST_HEAD(tmp_list); | ||
195 | 275 | ||
196 | spin_lock(&nfsi->vfs_inode.i_lock); | 276 | spin_lock(&nfsi->vfs_inode.i_lock); |
197 | lo = nfsi->layout; | 277 | lo = nfsi->layout; |
198 | if (lo) { | 278 | if (lo) { |
279 | pnfs_clear_lseg_list(lo, &tmp_list); | ||
199 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ | 280 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ |
200 | put_layout_hdr_locked(lo); | 281 | put_layout_hdr_locked(lo); |
201 | } | 282 | } |
202 | spin_unlock(&nfsi->vfs_inode.i_lock); | 283 | spin_unlock(&nfsi->vfs_inode.i_lock); |
284 | pnfs_free_lseg_list(&tmp_list); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Called by the state manger to remove all layouts established under an | ||
289 | * expired lease. | ||
290 | */ | ||
291 | void | ||
292 | pnfs_destroy_all_layouts(struct nfs_client *clp) | ||
293 | { | ||
294 | struct pnfs_layout_hdr *lo; | ||
295 | LIST_HEAD(tmp_list); | ||
296 | |||
297 | spin_lock(&clp->cl_lock); | ||
298 | list_splice_init(&clp->cl_layouts, &tmp_list); | ||
299 | spin_unlock(&clp->cl_lock); | ||
300 | |||
301 | while (!list_empty(&tmp_list)) { | ||
302 | lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, | ||
303 | layouts); | ||
304 | dprintk("%s freeing layout for inode %lu\n", __func__, | ||
305 | lo->inode->i_ino); | ||
306 | pnfs_destroy_layout(NFS_I(lo->inode)); | ||
307 | } | ||
203 | } | 308 | } |
204 | 309 | ||
205 | /* STUB - pretend LAYOUTGET to server failed */ | 310 | static void pnfs_insert_layout(struct pnfs_layout_hdr *lo, |
311 | struct pnfs_layout_segment *lseg); | ||
312 | |||
313 | /* Get layout from server. */ | ||
206 | static struct pnfs_layout_segment * | 314 | static struct pnfs_layout_segment * |
207 | send_layoutget(struct pnfs_layout_hdr *lo, | 315 | send_layoutget(struct pnfs_layout_hdr *lo, |
208 | struct nfs_open_context *ctx, | 316 | struct nfs_open_context *ctx, |
209 | u32 iomode) | 317 | u32 iomode) |
210 | { | 318 | { |
211 | struct inode *ino = lo->inode; | 319 | struct inode *ino = lo->inode; |
320 | struct pnfs_layout_segment *lseg; | ||
212 | 321 | ||
213 | set_bit(lo_fail_bit(iomode), &lo->state); | 322 | /* Lets pretend we sent LAYOUTGET and got a response */ |
323 | lseg = kzalloc(sizeof(*lseg), GFP_KERNEL); | ||
324 | if (!lseg) { | ||
325 | set_bit(lo_fail_bit(iomode), &lo->state); | ||
326 | spin_lock(&ino->i_lock); | ||
327 | put_layout_hdr_locked(lo); | ||
328 | spin_unlock(&ino->i_lock); | ||
329 | return NULL; | ||
330 | } | ||
331 | init_lseg(lo, lseg); | ||
332 | lseg->iomode = IOMODE_RW; | ||
214 | spin_lock(&ino->i_lock); | 333 | spin_lock(&ino->i_lock); |
334 | pnfs_insert_layout(lo, lseg); | ||
215 | put_layout_hdr_locked(lo); | 335 | put_layout_hdr_locked(lo); |
216 | spin_unlock(&ino->i_lock); | 336 | spin_unlock(&ino->i_lock); |
217 | return NULL; | 337 | return lseg; |
338 | } | ||
339 | |||
340 | static void | ||
341 | pnfs_insert_layout(struct pnfs_layout_hdr *lo, | ||
342 | struct pnfs_layout_segment *lseg) | ||
343 | { | ||
344 | dprintk("%s:Begin\n", __func__); | ||
345 | |||
346 | assert_spin_locked(&lo->inode->i_lock); | ||
347 | if (list_empty(&lo->segs)) { | ||
348 | struct nfs_client *clp = NFS_SERVER(lo->inode)->nfs_client; | ||
349 | |||
350 | spin_lock(&clp->cl_lock); | ||
351 | BUG_ON(!list_empty(&lo->layouts)); | ||
352 | list_add_tail(&lo->layouts, &clp->cl_layouts); | ||
353 | spin_unlock(&clp->cl_lock); | ||
354 | } | ||
355 | get_layout_hdr_locked(lo); | ||
356 | /* STUB - add the constructed lseg if necessary */ | ||
357 | if (list_empty(&lo->segs)) { | ||
358 | list_add_tail(&lseg->fi_list, &lo->segs); | ||
359 | dprintk("%s: inserted lseg %p iomode %d at tail\n", | ||
360 | __func__, lseg, lseg->iomode); | ||
361 | } else { | ||
362 | /* There is no harm for the moment in calling this | ||
363 | * with the lock held, and the call will be removed | ||
364 | * with the STUB. | ||
365 | */ | ||
366 | put_lseg(lseg); | ||
367 | } | ||
368 | |||
369 | dprintk("%s:Return\n", __func__); | ||
218 | } | 370 | } |
219 | 371 | ||
220 | static struct pnfs_layout_hdr * | 372 | static struct pnfs_layout_hdr * |
@@ -226,6 +378,8 @@ alloc_init_layout_hdr(struct inode *ino) | |||
226 | if (!lo) | 378 | if (!lo) |
227 | return NULL; | 379 | return NULL; |
228 | lo->refcount = 1; | 380 | lo->refcount = 1; |
381 | INIT_LIST_HEAD(&lo->layouts); | ||
382 | INIT_LIST_HEAD(&lo->segs); | ||
229 | lo->inode = ino; | 383 | lo->inode = ino; |
230 | return lo; | 384 | return lo; |
231 | } | 385 | } |