| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2016 CNEX Labs |
|---|
| 3 | 4 | * Initial release: Javier Gonzalez <javier@cnexlabs.com> |
|---|
| .. | .. |
|---|
| 16 | 17 | */ |
|---|
| 17 | 18 | |
|---|
| 18 | 19 | #include "pblk.h" |
|---|
| 20 | +#include "pblk-trace.h" |
|---|
| 19 | 21 | |
|---|
| 20 | 22 | static unsigned long pblk_end_w_bio(struct pblk *pblk, struct nvm_rq *rqd, |
|---|
| 21 | 23 | struct pblk_c_ctx *c_ctx) |
|---|
| .. | .. |
|---|
| 81 | 83 | #ifdef CONFIG_NVM_PBLK_DEBUG |
|---|
| 82 | 84 | atomic_long_sub(c_ctx->nr_valid, &pblk->inflight_writes); |
|---|
| 83 | 85 | #endif |
|---|
| 84 | | - |
|---|
| 85 | | - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); |
|---|
| 86 | + pblk_up_rq(pblk, c_ctx->lun_bitmap); |
|---|
| 86 | 87 | |
|---|
| 87 | 88 | pos = pblk_rb_sync_init(&pblk->rwb, &flags); |
|---|
| 88 | 89 | if (pos == c_ctx->sentry) { |
|---|
| .. | .. |
|---|
| 104 | 105 | } |
|---|
| 105 | 106 | |
|---|
| 106 | 107 | /* Map remaining sectors in chunk, starting from ppa */ |
|---|
| 107 | | -static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) |
|---|
| 108 | +static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa, |
|---|
| 109 | + int rqd_ppas) |
|---|
| 108 | 110 | { |
|---|
| 109 | | - struct nvm_tgt_dev *dev = pblk->dev; |
|---|
| 110 | | - struct nvm_geo *geo = &dev->geo; |
|---|
| 111 | 111 | struct pblk_line *line; |
|---|
| 112 | 112 | struct ppa_addr map_ppa = *ppa; |
|---|
| 113 | + __le64 addr_empty = cpu_to_le64(ADDR_EMPTY); |
|---|
| 114 | + __le64 *lba_list; |
|---|
| 113 | 115 | u64 paddr; |
|---|
| 114 | 116 | int done = 0; |
|---|
| 117 | + int n = 0; |
|---|
| 115 | 118 | |
|---|
| 116 | | - line = &pblk->lines[pblk_ppa_to_line(*ppa)]; |
|---|
| 119 | + line = pblk_ppa_to_line(pblk, *ppa); |
|---|
| 120 | + lba_list = emeta_to_lbas(pblk, line->emeta->buf); |
|---|
| 121 | + |
|---|
| 117 | 122 | spin_lock(&line->lock); |
|---|
| 118 | 123 | |
|---|
| 119 | 124 | while (!done) { |
|---|
| .. | .. |
|---|
| 122 | 127 | if (!test_and_set_bit(paddr, line->map_bitmap)) |
|---|
| 123 | 128 | line->left_msecs--; |
|---|
| 124 | 129 | |
|---|
| 130 | + if (n < rqd_ppas && lba_list[paddr] != addr_empty) |
|---|
| 131 | + line->nr_valid_lbas--; |
|---|
| 132 | + |
|---|
| 133 | + lba_list[paddr] = addr_empty; |
|---|
| 134 | + |
|---|
| 125 | 135 | if (!test_and_set_bit(paddr, line->invalid_bitmap)) |
|---|
| 126 | 136 | le32_add_cpu(line->vsc, -1); |
|---|
| 127 | 137 | |
|---|
| 128 | | - if (geo->version == NVM_OCSSD_SPEC_12) { |
|---|
| 129 | | - map_ppa.ppa++; |
|---|
| 130 | | - if (map_ppa.g.pg == geo->num_pg) |
|---|
| 131 | | - done = 1; |
|---|
| 132 | | - } else { |
|---|
| 133 | | - map_ppa.m.sec++; |
|---|
| 134 | | - if (map_ppa.m.sec == geo->clba) |
|---|
| 135 | | - done = 1; |
|---|
| 136 | | - } |
|---|
| 138 | + done = nvm_next_ppa_in_chk(pblk->dev, &map_ppa); |
|---|
| 139 | + |
|---|
| 140 | + n++; |
|---|
| 137 | 141 | } |
|---|
| 138 | 142 | |
|---|
| 139 | 143 | line->w_err_gc->has_write_err = 1; |
|---|
| .. | .. |
|---|
| 149 | 153 | struct pblk_w_ctx *w_ctx; |
|---|
| 150 | 154 | struct ppa_addr ppa_l2p; |
|---|
| 151 | 155 | int flags; |
|---|
| 152 | | - unsigned int pos, i; |
|---|
| 156 | + unsigned int i; |
|---|
| 153 | 157 | |
|---|
| 154 | 158 | spin_lock(&pblk->trans_lock); |
|---|
| 155 | | - pos = sentry; |
|---|
| 156 | 159 | for (i = 0; i < nr_entries; i++) { |
|---|
| 157 | | - entry = &rb->entries[pos]; |
|---|
| 160 | + entry = &rb->entries[pblk_rb_ptr_wrap(rb, sentry, i)]; |
|---|
| 158 | 161 | w_ctx = &entry->w_ctx; |
|---|
| 159 | 162 | |
|---|
| 160 | 163 | /* Check if the lba has been overwritten */ |
|---|
| .. | .. |
|---|
| 170 | 173 | /* Release flags on write context. Protect from writes */ |
|---|
| 171 | 174 | smp_store_release(&w_ctx->flags, flags); |
|---|
| 172 | 175 | |
|---|
| 173 | | - /* Decrese the reference count to the line as we will |
|---|
| 176 | + /* Decrease the reference count to the line as we will |
|---|
| 174 | 177 | * re-map these entries |
|---|
| 175 | 178 | */ |
|---|
| 176 | | - line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)]; |
|---|
| 179 | + line = pblk_ppa_to_line(pblk, w_ctx->ppa); |
|---|
| 180 | + atomic_dec(&line->sec_to_update); |
|---|
| 177 | 181 | kref_put(&line->ref, pblk_line_put); |
|---|
| 178 | | - |
|---|
| 179 | | - pos = (pos + 1) & (rb->nr_entries - 1); |
|---|
| 180 | 182 | } |
|---|
| 181 | 183 | spin_unlock(&pblk->trans_lock); |
|---|
| 182 | 184 | } |
|---|
| .. | .. |
|---|
| 210 | 212 | struct pblk *pblk = recovery->pblk; |
|---|
| 211 | 213 | struct nvm_rq *rqd = recovery->rqd; |
|---|
| 212 | 214 | struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); |
|---|
| 213 | | - struct ppa_addr *ppa_list; |
|---|
| 215 | + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); |
|---|
| 214 | 216 | |
|---|
| 215 | 217 | pblk_log_write_err(pblk, rqd); |
|---|
| 216 | 218 | |
|---|
| 217 | | - if (rqd->nr_ppas == 1) |
|---|
| 218 | | - ppa_list = &rqd->ppa_addr; |
|---|
| 219 | | - else |
|---|
| 220 | | - ppa_list = rqd->ppa_list; |
|---|
| 221 | | - |
|---|
| 222 | | - pblk_map_remaining(pblk, ppa_list); |
|---|
| 219 | + pblk_map_remaining(pblk, ppa_list, rqd->nr_ppas); |
|---|
| 223 | 220 | pblk_queue_resubmit(pblk, c_ctx); |
|---|
| 224 | 221 | |
|---|
| 225 | | - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); |
|---|
| 222 | + pblk_up_rq(pblk, c_ctx->lun_bitmap); |
|---|
| 226 | 223 | if (c_ctx->nr_padded) |
|---|
| 227 | 224 | pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid, |
|---|
| 228 | 225 | c_ctx->nr_padded); |
|---|
| .. | .. |
|---|
| 231 | 228 | mempool_free(recovery, &pblk->rec_pool); |
|---|
| 232 | 229 | |
|---|
| 233 | 230 | atomic_dec(&pblk->inflight_io); |
|---|
| 231 | + pblk_write_kick(pblk); |
|---|
| 234 | 232 | } |
|---|
| 235 | 233 | |
|---|
| 236 | 234 | |
|---|
| .. | .. |
|---|
| 259 | 257 | if (rqd->error) { |
|---|
| 260 | 258 | pblk_end_w_fail(pblk, rqd); |
|---|
| 261 | 259 | return; |
|---|
| 262 | | - } |
|---|
| 260 | + } else { |
|---|
| 261 | + if (trace_pblk_chunk_state_enabled()) |
|---|
| 262 | + pblk_check_chunk_state_update(pblk, rqd); |
|---|
| 263 | 263 | #ifdef CONFIG_NVM_PBLK_DEBUG |
|---|
| 264 | | - else |
|---|
| 265 | 264 | WARN_ONCE(rqd->bio->bi_status, "pblk: corrupted write error\n"); |
|---|
| 266 | 265 | #endif |
|---|
| 266 | + } |
|---|
| 267 | 267 | |
|---|
| 268 | 268 | pblk_complete_write(pblk, rqd, c_ctx); |
|---|
| 269 | 269 | atomic_dec(&pblk->inflight_io); |
|---|
| .. | .. |
|---|
| 275 | 275 | struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd); |
|---|
| 276 | 276 | struct pblk_line *line = m_ctx->private; |
|---|
| 277 | 277 | struct pblk_emeta *emeta = line->emeta; |
|---|
| 278 | + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); |
|---|
| 278 | 279 | int sync; |
|---|
| 279 | 280 | |
|---|
| 280 | | - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
|---|
| 281 | + pblk_up_chunk(pblk, ppa_list[0]); |
|---|
| 281 | 282 | |
|---|
| 282 | 283 | if (rqd->error) { |
|---|
| 283 | 284 | pblk_log_write_err(pblk, rqd); |
|---|
| 284 | 285 | pblk_err(pblk, "metadata I/O failed. Line %d\n", line->id); |
|---|
| 285 | 286 | line->w_err_gc->has_write_err = 1; |
|---|
| 287 | + } else { |
|---|
| 288 | + if (trace_pblk_chunk_state_enabled()) |
|---|
| 289 | + pblk_check_chunk_state_update(pblk, rqd); |
|---|
| 286 | 290 | } |
|---|
| 287 | 291 | |
|---|
| 288 | 292 | sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); |
|---|
| .. | .. |
|---|
| 296 | 300 | } |
|---|
| 297 | 301 | |
|---|
| 298 | 302 | static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd, |
|---|
| 299 | | - unsigned int nr_secs, |
|---|
| 300 | | - nvm_end_io_fn(*end_io)) |
|---|
| 303 | + unsigned int nr_secs, nvm_end_io_fn(*end_io)) |
|---|
| 301 | 304 | { |
|---|
| 302 | | - struct nvm_tgt_dev *dev = pblk->dev; |
|---|
| 303 | | - |
|---|
| 304 | 305 | /* Setup write request */ |
|---|
| 305 | 306 | rqd->opcode = NVM_OP_PWRITE; |
|---|
| 306 | 307 | rqd->nr_ppas = nr_secs; |
|---|
| 307 | | - rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE); |
|---|
| 308 | + rqd->is_seq = 1; |
|---|
| 308 | 309 | rqd->private = pblk; |
|---|
| 309 | 310 | rqd->end_io = end_io; |
|---|
| 310 | 311 | |
|---|
| 311 | | - rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, |
|---|
| 312 | | - &rqd->dma_meta_list); |
|---|
| 313 | | - if (!rqd->meta_list) |
|---|
| 314 | | - return -ENOMEM; |
|---|
| 315 | | - |
|---|
| 316 | | - rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; |
|---|
| 317 | | - rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; |
|---|
| 318 | | - |
|---|
| 319 | | - return 0; |
|---|
| 312 | + return pblk_alloc_rqd_meta(pblk, rqd); |
|---|
| 320 | 313 | } |
|---|
| 321 | 314 | |
|---|
| 322 | 315 | static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, |
|---|
| .. | .. |
|---|
| 343 | 336 | } |
|---|
| 344 | 337 | |
|---|
| 345 | 338 | if (likely(!e_line || !atomic_read(&e_line->left_eblks))) |
|---|
| 346 | | - pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, valid, 0); |
|---|
| 339 | + ret = pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
|---|
| 340 | + valid, 0); |
|---|
| 347 | 341 | else |
|---|
| 348 | | - pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
|---|
| 342 | + ret = pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
|---|
| 349 | 343 | valid, erase_ppa); |
|---|
| 350 | 344 | |
|---|
| 351 | | - return 0; |
|---|
| 345 | + return ret; |
|---|
| 352 | 346 | } |
|---|
| 353 | 347 | |
|---|
| 354 | 348 | static int pblk_calc_secs_to_sync(struct pblk *pblk, unsigned int secs_avail, |
|---|
| .. | .. |
|---|
| 356 | 350 | { |
|---|
| 357 | 351 | int secs_to_sync; |
|---|
| 358 | 352 | |
|---|
| 359 | | - secs_to_sync = pblk_calc_secs(pblk, secs_avail, secs_to_flush); |
|---|
| 353 | + secs_to_sync = pblk_calc_secs(pblk, secs_avail, secs_to_flush, true); |
|---|
| 360 | 354 | |
|---|
| 361 | 355 | #ifdef CONFIG_NVM_PBLK_DEBUG |
|---|
| 362 | 356 | if ((!secs_to_sync && secs_to_flush) |
|---|
| .. | .. |
|---|
| 377 | 371 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
|---|
| 378 | 372 | struct pblk_line_meta *lm = &pblk->lm; |
|---|
| 379 | 373 | struct pblk_emeta *emeta = meta_line->emeta; |
|---|
| 374 | + struct ppa_addr *ppa_list; |
|---|
| 380 | 375 | struct pblk_g_ctx *m_ctx; |
|---|
| 381 | | - struct bio *bio; |
|---|
| 382 | 376 | struct nvm_rq *rqd; |
|---|
| 383 | 377 | void *data; |
|---|
| 384 | 378 | u64 paddr; |
|---|
| .. | .. |
|---|
| 396 | 390 | rq_len = rq_ppas * geo->csecs; |
|---|
| 397 | 391 | data = ((void *)emeta->buf) + emeta->mem; |
|---|
| 398 | 392 | |
|---|
| 399 | | - bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, |
|---|
| 400 | | - l_mg->emeta_alloc_type, GFP_KERNEL); |
|---|
| 401 | | - if (IS_ERR(bio)) { |
|---|
| 402 | | - pblk_err(pblk, "failed to map emeta io"); |
|---|
| 403 | | - ret = PTR_ERR(bio); |
|---|
| 404 | | - goto fail_free_rqd; |
|---|
| 405 | | - } |
|---|
| 406 | | - bio->bi_iter.bi_sector = 0; /* internal bio */ |
|---|
| 407 | | - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); |
|---|
| 408 | | - rqd->bio = bio; |
|---|
| 409 | | - |
|---|
| 410 | 393 | ret = pblk_alloc_w_rq(pblk, rqd, rq_ppas, pblk_end_io_write_meta); |
|---|
| 411 | 394 | if (ret) |
|---|
| 412 | | - goto fail_free_bio; |
|---|
| 395 | + goto fail_free_rqd; |
|---|
| 413 | 396 | |
|---|
| 397 | + ppa_list = nvm_rq_to_ppa_list(rqd); |
|---|
| 414 | 398 | for (i = 0; i < rqd->nr_ppas; ) { |
|---|
| 415 | 399 | spin_lock(&meta_line->lock); |
|---|
| 416 | 400 | paddr = __pblk_alloc_page(pblk, meta_line, rq_ppas); |
|---|
| 417 | 401 | spin_unlock(&meta_line->lock); |
|---|
| 418 | 402 | for (j = 0; j < rq_ppas; j++, i++, paddr++) |
|---|
| 419 | | - rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); |
|---|
| 403 | + ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); |
|---|
| 420 | 404 | } |
|---|
| 421 | 405 | |
|---|
| 422 | 406 | spin_lock(&l_mg->close_lock); |
|---|
| .. | .. |
|---|
| 425 | 409 | list_del(&meta_line->list); |
|---|
| 426 | 410 | spin_unlock(&l_mg->close_lock); |
|---|
| 427 | 411 | |
|---|
| 428 | | - pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
|---|
| 412 | + pblk_down_chunk(pblk, ppa_list[0]); |
|---|
| 429 | 413 | |
|---|
| 430 | | - ret = pblk_submit_io(pblk, rqd); |
|---|
| 414 | + ret = pblk_submit_io(pblk, rqd, data); |
|---|
| 431 | 415 | if (ret) { |
|---|
| 432 | 416 | pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); |
|---|
| 433 | 417 | goto fail_rollback; |
|---|
| .. | .. |
|---|
| 436 | 420 | return NVM_IO_OK; |
|---|
| 437 | 421 | |
|---|
| 438 | 422 | fail_rollback: |
|---|
| 439 | | - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
|---|
| 423 | + pblk_up_chunk(pblk, ppa_list[0]); |
|---|
| 440 | 424 | spin_lock(&l_mg->close_lock); |
|---|
| 441 | 425 | pblk_dealloc_page(pblk, meta_line, rq_ppas); |
|---|
| 442 | 426 | list_add(&meta_line->list, &meta_line->list); |
|---|
| 443 | 427 | spin_unlock(&l_mg->close_lock); |
|---|
| 444 | | -fail_free_bio: |
|---|
| 445 | | - bio_put(bio); |
|---|
| 446 | 428 | fail_free_rqd: |
|---|
| 447 | 429 | pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); |
|---|
| 448 | 430 | return ret; |
|---|
| .. | .. |
|---|
| 527 | 509 | meta_line = pblk_should_submit_meta_io(pblk, rqd); |
|---|
| 528 | 510 | |
|---|
| 529 | 511 | /* Submit data write for current data line */ |
|---|
| 530 | | - err = pblk_submit_io(pblk, rqd); |
|---|
| 512 | + err = pblk_submit_io(pblk, rqd, NULL); |
|---|
| 531 | 513 | if (err) { |
|---|
| 532 | 514 | pblk_err(pblk, "data I/O submission failed: %d\n", err); |
|---|
| 533 | 515 | return NVM_IO_ERR; |
|---|
| .. | .. |
|---|
| 570 | 552 | c_ctx->nr_padded); |
|---|
| 571 | 553 | } |
|---|
| 572 | 554 | |
|---|
| 573 | | -static int pblk_submit_write(struct pblk *pblk) |
|---|
| 555 | +static int pblk_submit_write(struct pblk *pblk, int *secs_left) |
|---|
| 574 | 556 | { |
|---|
| 575 | 557 | struct bio *bio; |
|---|
| 576 | 558 | struct nvm_rq *rqd; |
|---|
| 577 | 559 | unsigned int secs_avail, secs_to_sync, secs_to_com; |
|---|
| 578 | | - unsigned int secs_to_flush; |
|---|
| 560 | + unsigned int secs_to_flush, packed_meta_pgs; |
|---|
| 579 | 561 | unsigned long pos; |
|---|
| 580 | 562 | unsigned int resubmit; |
|---|
| 563 | + |
|---|
| 564 | + *secs_left = 0; |
|---|
| 581 | 565 | |
|---|
| 582 | 566 | spin_lock(&pblk->resubmit_lock); |
|---|
| 583 | 567 | resubmit = !list_empty(&pblk->resubmit_list); |
|---|
| .. | .. |
|---|
| 608 | 592 | */ |
|---|
| 609 | 593 | secs_avail = pblk_rb_read_count(&pblk->rwb); |
|---|
| 610 | 594 | if (!secs_avail) |
|---|
| 611 | | - return 1; |
|---|
| 595 | + return 0; |
|---|
| 612 | 596 | |
|---|
| 613 | 597 | secs_to_flush = pblk_rb_flush_point_count(&pblk->rwb); |
|---|
| 614 | | - if (!secs_to_flush && secs_avail < pblk->min_write_pgs) |
|---|
| 615 | | - return 1; |
|---|
| 598 | + if (!secs_to_flush && secs_avail < pblk->min_write_pgs_data) |
|---|
| 599 | + return 0; |
|---|
| 616 | 600 | |
|---|
| 617 | 601 | secs_to_sync = pblk_calc_secs_to_sync(pblk, secs_avail, |
|---|
| 618 | 602 | secs_to_flush); |
|---|
| 619 | 603 | if (secs_to_sync > pblk->max_write_pgs) { |
|---|
| 620 | 604 | pblk_err(pblk, "bad buffer sync calculation\n"); |
|---|
| 621 | | - return 1; |
|---|
| 605 | + return 0; |
|---|
| 622 | 606 | } |
|---|
| 623 | 607 | |
|---|
| 624 | 608 | secs_to_com = (secs_to_sync > secs_avail) ? |
|---|
| .. | .. |
|---|
| 626 | 610 | pos = pblk_rb_read_commit(&pblk->rwb, secs_to_com); |
|---|
| 627 | 611 | } |
|---|
| 628 | 612 | |
|---|
| 629 | | - bio = bio_alloc(GFP_KERNEL, secs_to_sync); |
|---|
| 613 | + packed_meta_pgs = (pblk->min_write_pgs - pblk->min_write_pgs_data); |
|---|
| 614 | + bio = bio_alloc(GFP_KERNEL, secs_to_sync + packed_meta_pgs); |
|---|
| 630 | 615 | |
|---|
| 631 | 616 | bio->bi_iter.bi_sector = 0; /* internal bio */ |
|---|
| 632 | 617 | bio_set_op_attrs(bio, REQ_OP_WRITE, 0); |
|---|
| .. | .. |
|---|
| 647 | 632 | atomic_long_add(secs_to_sync, &pblk->sub_writes); |
|---|
| 648 | 633 | #endif |
|---|
| 649 | 634 | |
|---|
| 635 | + *secs_left = 1; |
|---|
| 650 | 636 | return 0; |
|---|
| 651 | 637 | |
|---|
| 652 | 638 | fail_free_bio: |
|---|
| .. | .. |
|---|
| 655 | 641 | bio_put(bio); |
|---|
| 656 | 642 | pblk_free_rqd(pblk, rqd, PBLK_WRITE); |
|---|
| 657 | 643 | |
|---|
| 658 | | - return 1; |
|---|
| 644 | + return -EINTR; |
|---|
| 659 | 645 | } |
|---|
| 660 | 646 | |
|---|
| 661 | 647 | int pblk_write_ts(void *data) |
|---|
| 662 | 648 | { |
|---|
| 663 | 649 | struct pblk *pblk = data; |
|---|
| 650 | + int secs_left; |
|---|
| 651 | + int write_failure = 0; |
|---|
| 664 | 652 | |
|---|
| 665 | 653 | while (!kthread_should_stop()) { |
|---|
| 666 | | - if (!pblk_submit_write(pblk)) |
|---|
| 667 | | - continue; |
|---|
| 654 | + if (!write_failure) { |
|---|
| 655 | + write_failure = pblk_submit_write(pblk, &secs_left); |
|---|
| 656 | + |
|---|
| 657 | + if (secs_left) |
|---|
| 658 | + continue; |
|---|
| 659 | + } |
|---|
| 668 | 660 | set_current_state(TASK_INTERRUPTIBLE); |
|---|
| 669 | 661 | io_schedule(); |
|---|
| 670 | 662 | } |
|---|