18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 CNEX Labs 48c2ecf20Sopenharmony_ci * Initial release: Javier Gonzalez <javier@cnexlabs.com> 58c2ecf20Sopenharmony_ci * Matias Bjorling <matias@cnexlabs.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 98c2ecf20Sopenharmony_ci * 2 as published by the Free Software Foundation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 128c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 148c2ecf20Sopenharmony_ci * General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * pblk-cache.c - pblk's write cache 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "pblk.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_civoid pblk_write_to_cache(struct pblk *pblk, struct bio *bio, 228c2ecf20Sopenharmony_ci unsigned long flags) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct pblk_w_ctx w_ctx; 258c2ecf20Sopenharmony_ci sector_t lba = pblk_get_lba(bio); 268c2ecf20Sopenharmony_ci unsigned long start_time; 278c2ecf20Sopenharmony_ci unsigned int bpos, pos; 288c2ecf20Sopenharmony_ci int nr_entries = pblk_get_secs(bio); 298c2ecf20Sopenharmony_ci int i, ret; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci start_time = bio_start_io_acct(bio); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* Update the write buffer head (mem) with the entries that we can 348c2ecf20Sopenharmony_ci * write. The write in itself cannot fail, so there is no need to 358c2ecf20Sopenharmony_ci * rollback from here on. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ciretry: 388c2ecf20Sopenharmony_ci ret = pblk_rb_may_write_user(&pblk->rwb, bio, nr_entries, &bpos); 398c2ecf20Sopenharmony_ci switch (ret) { 408c2ecf20Sopenharmony_ci case NVM_IO_REQUEUE: 418c2ecf20Sopenharmony_ci io_schedule(); 428c2ecf20Sopenharmony_ci goto retry; 438c2ecf20Sopenharmony_ci case NVM_IO_ERR: 448c2ecf20Sopenharmony_ci pblk_pipeline_stop(pblk); 458c2ecf20Sopenharmony_ci bio_io_error(bio); 468c2ecf20Sopenharmony_ci goto out; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci pblk_ppa_set_empty(&w_ctx.ppa); 508c2ecf20Sopenharmony_ci w_ctx.flags = flags; 518c2ecf20Sopenharmony_ci if (bio->bi_opf & REQ_PREFLUSH) { 528c2ecf20Sopenharmony_ci w_ctx.flags |= PBLK_FLUSH_ENTRY; 538c2ecf20Sopenharmony_ci pblk_write_kick(pblk); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (unlikely(!bio_has_data(bio))) 578c2ecf20Sopenharmony_ci goto out; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci for (i = 0; i < nr_entries; i++) { 608c2ecf20Sopenharmony_ci void *data = bio_data(bio); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci w_ctx.lba = lba + i; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + i); 658c2ecf20Sopenharmony_ci pblk_rb_write_entry_user(&pblk->rwb, data, w_ctx, pos); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci atomic64_add(nr_entries, &pblk->user_wa); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG 738c2ecf20Sopenharmony_ci atomic_long_add(nr_entries, &pblk->inflight_writes); 748c2ecf20Sopenharmony_ci atomic_long_add(nr_entries, &pblk->req_writes); 758c2ecf20Sopenharmony_ci#endif 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci pblk_rl_inserted(&pblk->rl, nr_entries); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciout: 808c2ecf20Sopenharmony_ci bio_end_io_acct(bio, start_time); 818c2ecf20Sopenharmony_ci pblk_write_should_kick(pblk); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (ret == NVM_IO_DONE) 848c2ecf20Sopenharmony_ci bio_endio(bio); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * On GC the incoming lbas are not necessarily sequential. Also, some of the 898c2ecf20Sopenharmony_ci * lbas might not be valid entries, which are marked as empty by the GC thread 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciint pblk_write_gc_to_cache(struct pblk *pblk, struct pblk_gc_rq *gc_rq) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct pblk_w_ctx w_ctx; 948c2ecf20Sopenharmony_ci unsigned int bpos, pos; 958c2ecf20Sopenharmony_ci void *data = gc_rq->data; 968c2ecf20Sopenharmony_ci int i, valid_entries; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* Update the write buffer head (mem) with the entries that we can 998c2ecf20Sopenharmony_ci * write. The write in itself cannot fail, so there is no need to 1008c2ecf20Sopenharmony_ci * rollback from here on. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ciretry: 1038c2ecf20Sopenharmony_ci if (!pblk_rb_may_write_gc(&pblk->rwb, gc_rq->secs_to_gc, &bpos)) { 1048c2ecf20Sopenharmony_ci io_schedule(); 1058c2ecf20Sopenharmony_ci goto retry; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci w_ctx.flags = PBLK_IOTYPE_GC; 1098c2ecf20Sopenharmony_ci pblk_ppa_set_empty(&w_ctx.ppa); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0, valid_entries = 0; i < gc_rq->nr_secs; i++) { 1128c2ecf20Sopenharmony_ci if (gc_rq->lba_list[i] == ADDR_EMPTY) 1138c2ecf20Sopenharmony_ci continue; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci w_ctx.lba = gc_rq->lba_list[i]; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + valid_entries); 1188c2ecf20Sopenharmony_ci pblk_rb_write_entry_gc(&pblk->rwb, data, w_ctx, gc_rq->line, 1198c2ecf20Sopenharmony_ci gc_rq->paddr_list[i], pos); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci data += PBLK_EXPOSED_PAGE_SIZE; 1228c2ecf20Sopenharmony_ci valid_entries++; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci WARN_ONCE(gc_rq->secs_to_gc != valid_entries, 1268c2ecf20Sopenharmony_ci "pblk: inconsistent GC write\n"); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci atomic64_add(valid_entries, &pblk->gc_wa); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG 1318c2ecf20Sopenharmony_ci atomic_long_add(valid_entries, &pblk->inflight_writes); 1328c2ecf20Sopenharmony_ci atomic_long_add(valid_entries, &pblk->recov_gc_writes); 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci pblk_write_should_kick(pblk); 1368c2ecf20Sopenharmony_ci return NVM_IO_OK; 1378c2ecf20Sopenharmony_ci} 138