diff options
Diffstat (limited to 'fs/nfs/objlayout/objlayout.c')
-rw-r--r-- | fs/nfs/objlayout/objlayout.c | 232 |
1 files changed, 231 insertions, 1 deletions
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 5157ef6d0041..f7caecff6b4d 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
@@ -50,6 +50,10 @@ objlayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) | |||
50 | struct objlayout *objlay; | 50 | struct objlayout *objlay; |
51 | 51 | ||
52 | objlay = kzalloc(sizeof(struct objlayout), gfp_flags); | 52 | objlay = kzalloc(sizeof(struct objlayout), gfp_flags); |
53 | if (objlay) { | ||
54 | spin_lock_init(&objlay->lock); | ||
55 | INIT_LIST_HEAD(&objlay->err_list); | ||
56 | } | ||
53 | dprintk("%s: Return %p\n", __func__, objlay); | 57 | dprintk("%s: Return %p\n", __func__, objlay); |
54 | return &objlay->pnfs_layout; | 58 | return &objlay->pnfs_layout; |
55 | } | 59 | } |
@@ -64,6 +68,7 @@ objlayout_free_layout_hdr(struct pnfs_layout_hdr *lo) | |||
64 | 68 | ||
65 | dprintk("%s: objlay %p\n", __func__, objlay); | 69 | dprintk("%s: objlay %p\n", __func__, objlay); |
66 | 70 | ||
71 | WARN_ON(!list_empty(&objlay->err_list)); | ||
67 | kfree(objlay); | 72 | kfree(objlay); |
68 | } | 73 | } |
69 | 74 | ||
@@ -183,6 +188,7 @@ objlayout_alloc_io_state(struct pnfs_layout_hdr *pnfs_layout_type, | |||
183 | pgbase &= ~PAGE_MASK; | 188 | pgbase &= ~PAGE_MASK; |
184 | } | 189 | } |
185 | 190 | ||
191 | INIT_LIST_HEAD(&state->err_list); | ||
186 | state->lseg = lseg; | 192 | state->lseg = lseg; |
187 | state->rpcdata = rpcdata; | 193 | state->rpcdata = rpcdata; |
188 | state->pages = pages; | 194 | state->pages = pages; |
@@ -213,7 +219,52 @@ objlayout_iodone(struct objlayout_io_state *state) | |||
213 | { | 219 | { |
214 | dprintk("%s: state %p status\n", __func__, state); | 220 | dprintk("%s: state %p status\n", __func__, state); |
215 | 221 | ||
216 | objlayout_free_io_state(state); | 222 | if (likely(state->status >= 0)) { |
223 | objlayout_free_io_state(state); | ||
224 | } else { | ||
225 | struct objlayout *objlay = OBJLAYOUT(state->lseg->pls_layout); | ||
226 | |||
227 | spin_lock(&objlay->lock); | ||
228 | list_add(&objlay->err_list, &state->err_list); | ||
229 | spin_unlock(&objlay->lock); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * objlayout_io_set_result - Set an osd_error code on a specific osd comp. | ||
235 | * | ||
236 | * The @index component IO failed (error returned from target). Register | ||
237 | * the error for later reporting at layout-return. | ||
238 | */ | ||
239 | void | ||
240 | objlayout_io_set_result(struct objlayout_io_state *state, unsigned index, | ||
241 | struct pnfs_osd_objid *pooid, int osd_error, | ||
242 | u64 offset, u64 length, bool is_write) | ||
243 | { | ||
244 | struct pnfs_osd_ioerr *ioerr = &state->ioerrs[index]; | ||
245 | |||
246 | BUG_ON(index >= state->num_comps); | ||
247 | if (osd_error) { | ||
248 | ioerr->oer_component = *pooid; | ||
249 | ioerr->oer_comp_offset = offset; | ||
250 | ioerr->oer_comp_length = length; | ||
251 | ioerr->oer_iswrite = is_write; | ||
252 | ioerr->oer_errno = osd_error; | ||
253 | |||
254 | dprintk("%s: err[%d]: errno=%d is_write=%d dev(%llx:%llx) " | ||
255 | "par=0x%llx obj=0x%llx offset=0x%llx length=0x%llx\n", | ||
256 | __func__, index, ioerr->oer_errno, | ||
257 | ioerr->oer_iswrite, | ||
258 | _DEVID_LO(&ioerr->oer_component.oid_device_id), | ||
259 | _DEVID_HI(&ioerr->oer_component.oid_device_id), | ||
260 | ioerr->oer_component.oid_partition_id, | ||
261 | ioerr->oer_component.oid_object_id, | ||
262 | ioerr->oer_comp_offset, | ||
263 | ioerr->oer_comp_length); | ||
264 | } else { | ||
265 | /* User need not call if no error is reported */ | ||
266 | ioerr->oer_errno = 0; | ||
267 | } | ||
217 | } | 268 | } |
218 | 269 | ||
219 | /* Function scheduled on rpc workqueue to call ->nfs_readlist_complete(). | 270 | /* Function scheduled on rpc workqueue to call ->nfs_readlist_complete(). |
@@ -382,6 +433,185 @@ objlayout_write_pagelist(struct nfs_write_data *wdata, | |||
382 | return PNFS_ATTEMPTED; | 433 | return PNFS_ATTEMPTED; |
383 | } | 434 | } |
384 | 435 | ||
436 | static int | ||
437 | err_prio(u32 oer_errno) | ||
438 | { | ||
439 | switch (oer_errno) { | ||
440 | case 0: | ||
441 | return 0; | ||
442 | |||
443 | case PNFS_OSD_ERR_RESOURCE: | ||
444 | return OSD_ERR_PRI_RESOURCE; | ||
445 | case PNFS_OSD_ERR_BAD_CRED: | ||
446 | return OSD_ERR_PRI_BAD_CRED; | ||
447 | case PNFS_OSD_ERR_NO_ACCESS: | ||
448 | return OSD_ERR_PRI_NO_ACCESS; | ||
449 | case PNFS_OSD_ERR_UNREACHABLE: | ||
450 | return OSD_ERR_PRI_UNREACHABLE; | ||
451 | case PNFS_OSD_ERR_NOT_FOUND: | ||
452 | return OSD_ERR_PRI_NOT_FOUND; | ||
453 | case PNFS_OSD_ERR_NO_SPACE: | ||
454 | return OSD_ERR_PRI_NO_SPACE; | ||
455 | default: | ||
456 | WARN_ON(1); | ||
457 | /* fallthrough */ | ||
458 | case PNFS_OSD_ERR_EIO: | ||
459 | return OSD_ERR_PRI_EIO; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | static void | ||
464 | merge_ioerr(struct pnfs_osd_ioerr *dest_err, | ||
465 | const struct pnfs_osd_ioerr *src_err) | ||
466 | { | ||
467 | u64 dest_end, src_end; | ||
468 | |||
469 | if (!dest_err->oer_errno) { | ||
470 | *dest_err = *src_err; | ||
471 | /* accumulated device must be blank */ | ||
472 | memset(&dest_err->oer_component.oid_device_id, 0, | ||
473 | sizeof(dest_err->oer_component.oid_device_id)); | ||
474 | |||
475 | return; | ||
476 | } | ||
477 | |||
478 | if (dest_err->oer_component.oid_partition_id != | ||
479 | src_err->oer_component.oid_partition_id) | ||
480 | dest_err->oer_component.oid_partition_id = 0; | ||
481 | |||
482 | if (dest_err->oer_component.oid_object_id != | ||
483 | src_err->oer_component.oid_object_id) | ||
484 | dest_err->oer_component.oid_object_id = 0; | ||
485 | |||
486 | if (dest_err->oer_comp_offset > src_err->oer_comp_offset) | ||
487 | dest_err->oer_comp_offset = src_err->oer_comp_offset; | ||
488 | |||
489 | dest_end = end_offset(dest_err->oer_comp_offset, | ||
490 | dest_err->oer_comp_length); | ||
491 | src_end = end_offset(src_err->oer_comp_offset, | ||
492 | src_err->oer_comp_length); | ||
493 | if (dest_end < src_end) | ||
494 | dest_end = src_end; | ||
495 | |||
496 | dest_err->oer_comp_length = dest_end - dest_err->oer_comp_offset; | ||
497 | |||
498 | if ((src_err->oer_iswrite == dest_err->oer_iswrite) && | ||
499 | (err_prio(src_err->oer_errno) > err_prio(dest_err->oer_errno))) { | ||
500 | dest_err->oer_errno = src_err->oer_errno; | ||
501 | } else if (src_err->oer_iswrite) { | ||
502 | dest_err->oer_iswrite = true; | ||
503 | dest_err->oer_errno = src_err->oer_errno; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | static void | ||
508 | encode_accumulated_error(struct objlayout *objlay, __be32 *p) | ||
509 | { | ||
510 | struct objlayout_io_state *state, *tmp; | ||
511 | struct pnfs_osd_ioerr accumulated_err = {.oer_errno = 0}; | ||
512 | |||
513 | list_for_each_entry_safe(state, tmp, &objlay->err_list, err_list) { | ||
514 | unsigned i; | ||
515 | |||
516 | for (i = 0; i < state->num_comps; i++) { | ||
517 | struct pnfs_osd_ioerr *ioerr = &state->ioerrs[i]; | ||
518 | |||
519 | if (!ioerr->oer_errno) | ||
520 | continue; | ||
521 | |||
522 | printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d " | ||
523 | "dev(%llx:%llx) par=0x%llx obj=0x%llx " | ||
524 | "offset=0x%llx length=0x%llx\n", | ||
525 | __func__, i, ioerr->oer_errno, | ||
526 | ioerr->oer_iswrite, | ||
527 | _DEVID_LO(&ioerr->oer_component.oid_device_id), | ||
528 | _DEVID_HI(&ioerr->oer_component.oid_device_id), | ||
529 | ioerr->oer_component.oid_partition_id, | ||
530 | ioerr->oer_component.oid_object_id, | ||
531 | ioerr->oer_comp_offset, | ||
532 | ioerr->oer_comp_length); | ||
533 | |||
534 | merge_ioerr(&accumulated_err, ioerr); | ||
535 | } | ||
536 | list_del(&state->err_list); | ||
537 | objlayout_free_io_state(state); | ||
538 | } | ||
539 | |||
540 | pnfs_osd_xdr_encode_ioerr(p, &accumulated_err); | ||
541 | } | ||
542 | |||
543 | void | ||
544 | objlayout_encode_layoutreturn(struct pnfs_layout_hdr *pnfslay, | ||
545 | struct xdr_stream *xdr, | ||
546 | const struct nfs4_layoutreturn_args *args) | ||
547 | { | ||
548 | struct objlayout *objlay = OBJLAYOUT(pnfslay); | ||
549 | struct objlayout_io_state *state, *tmp; | ||
550 | __be32 *start; | ||
551 | |||
552 | dprintk("%s: Begin\n", __func__); | ||
553 | start = xdr_reserve_space(xdr, 4); | ||
554 | BUG_ON(!start); | ||
555 | |||
556 | spin_lock(&objlay->lock); | ||
557 | |||
558 | list_for_each_entry_safe(state, tmp, &objlay->err_list, err_list) { | ||
559 | __be32 *last_xdr = NULL, *p; | ||
560 | unsigned i; | ||
561 | int res = 0; | ||
562 | |||
563 | for (i = 0; i < state->num_comps; i++) { | ||
564 | struct pnfs_osd_ioerr *ioerr = &state->ioerrs[i]; | ||
565 | |||
566 | if (!ioerr->oer_errno) | ||
567 | continue; | ||
568 | |||
569 | dprintk("%s: err[%d]: errno=%d is_write=%d " | ||
570 | "dev(%llx:%llx) par=0x%llx obj=0x%llx " | ||
571 | "offset=0x%llx length=0x%llx\n", | ||
572 | __func__, i, ioerr->oer_errno, | ||
573 | ioerr->oer_iswrite, | ||
574 | _DEVID_LO(&ioerr->oer_component.oid_device_id), | ||
575 | _DEVID_HI(&ioerr->oer_component.oid_device_id), | ||
576 | ioerr->oer_component.oid_partition_id, | ||
577 | ioerr->oer_component.oid_object_id, | ||
578 | ioerr->oer_comp_offset, | ||
579 | ioerr->oer_comp_length); | ||
580 | |||
581 | p = pnfs_osd_xdr_ioerr_reserve_space(xdr); | ||
582 | if (unlikely(!p)) { | ||
583 | res = -E2BIG; | ||
584 | break; /* accumulated_error */ | ||
585 | } | ||
586 | |||
587 | last_xdr = p; | ||
588 | pnfs_osd_xdr_encode_ioerr(p, &state->ioerrs[i]); | ||
589 | } | ||
590 | |||
591 | /* TODO: use xdr_write_pages */ | ||
592 | if (unlikely(res)) { | ||
593 | /* no space for even one error descriptor */ | ||
594 | BUG_ON(!last_xdr); | ||
595 | |||
596 | /* we've encountered a situation with lots and lots of | ||
597 | * errors and no space to encode them all. Use the last | ||
598 | * available slot to report the union of all the | ||
599 | * remaining errors. | ||
600 | */ | ||
601 | encode_accumulated_error(objlay, last_xdr); | ||
602 | goto loop_done; | ||
603 | } | ||
604 | list_del(&state->err_list); | ||
605 | objlayout_free_io_state(state); | ||
606 | } | ||
607 | loop_done: | ||
608 | spin_unlock(&objlay->lock); | ||
609 | |||
610 | *start = cpu_to_be32((xdr->p - start - 1) * 4); | ||
611 | dprintk("%s: Return\n", __func__); | ||
612 | } | ||
613 | |||
614 | |||
385 | /* | 615 | /* |
386 | * Get Device Info API for io engines | 616 | * Get Device Info API for io engines |
387 | */ | 617 | */ |