Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.9-rc8 682 lines 15 kB view raw
1/* 2 * Copyright (C) 2015 Matias Bjorling <m@bjorling.me> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License version 6 * 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program; see the file COPYING. If not, write to 15 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 16 * USA. 17 * 18 * Implementation of a general nvm manager for Open-Channel SSDs. 19 */ 20 21#include "gennvm.h" 22 23static struct nvm_target *gen_find_target(struct gen_dev *gn, const char *name) 24{ 25 struct nvm_target *tgt; 26 27 list_for_each_entry(tgt, &gn->targets, list) 28 if (!strcmp(name, tgt->disk->disk_name)) 29 return tgt; 30 31 return NULL; 32} 33 34static const struct block_device_operations gen_fops = { 35 .owner = THIS_MODULE, 36}; 37 38static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) 39{ 40 struct gen_dev *gn = dev->mp; 41 struct nvm_ioctl_create_simple *s = &create->conf.s; 42 struct request_queue *tqueue; 43 struct gendisk *tdisk; 44 struct nvm_tgt_type *tt; 45 struct nvm_target *t; 46 void *targetdata; 47 48 tt = nvm_find_target_type(create->tgttype, 1); 49 if (!tt) { 50 pr_err("nvm: target type %s not found\n", create->tgttype); 51 return -EINVAL; 52 } 53 54 mutex_lock(&gn->lock); 55 t = gen_find_target(gn, create->tgtname); 56 if (t) { 57 pr_err("nvm: target name already exists.\n"); 58 mutex_unlock(&gn->lock); 59 return -EINVAL; 60 } 61 mutex_unlock(&gn->lock); 62 63 t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL); 64 if (!t) 65 return -ENOMEM; 66 67 tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node); 68 if (!tqueue) 69 goto err_t; 70 blk_queue_make_request(tqueue, tt->make_rq); 71 72 tdisk = alloc_disk(0); 73 if (!tdisk) 74 goto err_queue; 75 76 sprintf(tdisk->disk_name, "%s", create->tgtname); 77 tdisk->flags = GENHD_FL_EXT_DEVT; 78 tdisk->major = 0; 79 tdisk->first_minor = 0; 80 tdisk->fops = &gen_fops; 81 tdisk->queue = tqueue; 82 83 targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end); 84 if (IS_ERR(targetdata)) 85 goto err_init; 86 87 tdisk->private_data = targetdata; 88 tqueue->queuedata = targetdata; 89 90 blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect); 91 92 set_capacity(tdisk, tt->capacity(targetdata)); 93 add_disk(tdisk); 94 95 t->type = tt; 96 t->disk = tdisk; 97 t->dev = dev; 98 99 mutex_lock(&gn->lock); 100 list_add_tail(&t->list, &gn->targets); 101 mutex_unlock(&gn->lock); 102 103 return 0; 104err_init: 105 put_disk(tdisk); 106err_queue: 107 blk_cleanup_queue(tqueue); 108err_t: 109 kfree(t); 110 return -ENOMEM; 111} 112 113static void __gen_remove_target(struct nvm_target *t) 114{ 115 struct nvm_tgt_type *tt = t->type; 116 struct gendisk *tdisk = t->disk; 117 struct request_queue *q = tdisk->queue; 118 119 del_gendisk(tdisk); 120 blk_cleanup_queue(q); 121 122 if (tt->exit) 123 tt->exit(tdisk->private_data); 124 125 put_disk(tdisk); 126 127 list_del(&t->list); 128 kfree(t); 129} 130 131/** 132 * gen_remove_tgt - Removes a target from the media manager 133 * @dev: device 134 * @remove: ioctl structure with target name to remove. 135 * 136 * Returns: 137 * 0: on success 138 * 1: on not found 139 * <0: on error 140 */ 141static int gen_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) 142{ 143 struct gen_dev *gn = dev->mp; 144 struct nvm_target *t; 145 146 if (!gn) 147 return 1; 148 149 mutex_lock(&gn->lock); 150 t = gen_find_target(gn, remove->tgtname); 151 if (!t) { 152 mutex_unlock(&gn->lock); 153 return 1; 154 } 155 __gen_remove_target(t); 156 mutex_unlock(&gn->lock); 157 158 return 0; 159} 160 161static int gen_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len) 162{ 163 struct gen_dev *gn = dev->mp; 164 struct gen_area *area, *prev, *next; 165 sector_t begin = 0; 166 sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9; 167 168 if (len > max_sectors) 169 return -EINVAL; 170 171 area = kmalloc(sizeof(struct gen_area), GFP_KERNEL); 172 if (!area) 173 return -ENOMEM; 174 175 prev = NULL; 176 177 spin_lock(&dev->lock); 178 list_for_each_entry(next, &gn->area_list, list) { 179 if (begin + len > next->begin) { 180 begin = next->end; 181 prev = next; 182 continue; 183 } 184 break; 185 } 186 187 if ((begin + len) > max_sectors) { 188 spin_unlock(&dev->lock); 189 kfree(area); 190 return -EINVAL; 191 } 192 193 area->begin = *lba = begin; 194 area->end = begin + len; 195 196 if (prev) /* insert into sorted order */ 197 list_add(&area->list, &prev->list); 198 else 199 list_add(&area->list, &gn->area_list); 200 spin_unlock(&dev->lock); 201 202 return 0; 203} 204 205static void gen_put_area(struct nvm_dev *dev, sector_t begin) 206{ 207 struct gen_dev *gn = dev->mp; 208 struct gen_area *area; 209 210 spin_lock(&dev->lock); 211 list_for_each_entry(area, &gn->area_list, list) { 212 if (area->begin != begin) 213 continue; 214 215 list_del(&area->list); 216 spin_unlock(&dev->lock); 217 kfree(area); 218 return; 219 } 220 spin_unlock(&dev->lock); 221} 222 223static void gen_blocks_free(struct nvm_dev *dev) 224{ 225 struct gen_dev *gn = dev->mp; 226 struct gen_lun *lun; 227 int i; 228 229 gen_for_each_lun(gn, lun, i) { 230 if (!lun->vlun.blocks) 231 break; 232 vfree(lun->vlun.blocks); 233 } 234} 235 236static void gen_luns_free(struct nvm_dev *dev) 237{ 238 struct gen_dev *gn = dev->mp; 239 240 kfree(gn->luns); 241} 242 243static int gen_luns_init(struct nvm_dev *dev, struct gen_dev *gn) 244{ 245 struct gen_lun *lun; 246 int i; 247 248 gn->luns = kcalloc(dev->nr_luns, sizeof(struct gen_lun), GFP_KERNEL); 249 if (!gn->luns) 250 return -ENOMEM; 251 252 gen_for_each_lun(gn, lun, i) { 253 spin_lock_init(&lun->vlun.lock); 254 INIT_LIST_HEAD(&lun->free_list); 255 INIT_LIST_HEAD(&lun->used_list); 256 INIT_LIST_HEAD(&lun->bb_list); 257 258 lun->reserved_blocks = 2; /* for GC only */ 259 lun->vlun.id = i; 260 lun->vlun.lun_id = i % dev->luns_per_chnl; 261 lun->vlun.chnl_id = i / dev->luns_per_chnl; 262 lun->vlun.nr_free_blocks = dev->blks_per_lun; 263 } 264 return 0; 265} 266 267static int gen_block_bb(struct gen_dev *gn, struct ppa_addr ppa, 268 u8 *blks, int nr_blks) 269{ 270 struct nvm_dev *dev = gn->dev; 271 struct gen_lun *lun; 272 struct nvm_block *blk; 273 int i; 274 275 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); 276 if (nr_blks < 0) 277 return nr_blks; 278 279 lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun]; 280 281 for (i = 0; i < nr_blks; i++) { 282 if (blks[i] == 0) 283 continue; 284 285 blk = &lun->vlun.blocks[i]; 286 list_move_tail(&blk->list, &lun->bb_list); 287 lun->vlun.nr_free_blocks--; 288 } 289 290 return 0; 291} 292 293static int gen_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) 294{ 295 struct nvm_dev *dev = private; 296 struct gen_dev *gn = dev->mp; 297 u64 elba = slba + nlb; 298 struct gen_lun *lun; 299 struct nvm_block *blk; 300 u64 i; 301 int lun_id; 302 303 if (unlikely(elba > dev->total_secs)) { 304 pr_err("gen: L2P data from device is out of bounds!\n"); 305 return -EINVAL; 306 } 307 308 for (i = 0; i < nlb; i++) { 309 u64 pba = le64_to_cpu(entries[i]); 310 311 if (unlikely(pba >= dev->total_secs && pba != U64_MAX)) { 312 pr_err("gen: L2P data entry is out of bounds!\n"); 313 return -EINVAL; 314 } 315 316 /* Address zero is a special one. The first page on a disk is 317 * protected. It often holds internal device boot 318 * information. 319 */ 320 if (!pba) 321 continue; 322 323 /* resolve block from physical address */ 324 lun_id = div_u64(pba, dev->sec_per_lun); 325 lun = &gn->luns[lun_id]; 326 327 /* Calculate block offset into lun */ 328 pba = pba - (dev->sec_per_lun * lun_id); 329 blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)]; 330 331 if (!blk->state) { 332 /* at this point, we don't know anything about the 333 * block. It's up to the FTL on top to re-etablish the 334 * block state. The block is assumed to be open. 335 */ 336 list_move_tail(&blk->list, &lun->used_list); 337 blk->state = NVM_BLK_ST_TGT; 338 lun->vlun.nr_free_blocks--; 339 } 340 } 341 342 return 0; 343} 344 345static int gen_blocks_init(struct nvm_dev *dev, struct gen_dev *gn) 346{ 347 struct gen_lun *lun; 348 struct nvm_block *block; 349 sector_t lun_iter, blk_iter, cur_block_id = 0; 350 int ret, nr_blks; 351 u8 *blks; 352 353 nr_blks = dev->blks_per_lun * dev->plane_mode; 354 blks = kmalloc(nr_blks, GFP_KERNEL); 355 if (!blks) 356 return -ENOMEM; 357 358 gen_for_each_lun(gn, lun, lun_iter) { 359 lun->vlun.blocks = vzalloc(sizeof(struct nvm_block) * 360 dev->blks_per_lun); 361 if (!lun->vlun.blocks) { 362 kfree(blks); 363 return -ENOMEM; 364 } 365 366 for (blk_iter = 0; blk_iter < dev->blks_per_lun; blk_iter++) { 367 block = &lun->vlun.blocks[blk_iter]; 368 369 INIT_LIST_HEAD(&block->list); 370 371 block->lun = &lun->vlun; 372 block->id = cur_block_id++; 373 374 /* First block is reserved for device */ 375 if (unlikely(lun_iter == 0 && blk_iter == 0)) { 376 lun->vlun.nr_free_blocks--; 377 continue; 378 } 379 380 list_add_tail(&block->list, &lun->free_list); 381 } 382 383 if (dev->ops->get_bb_tbl) { 384 struct ppa_addr ppa; 385 386 ppa.ppa = 0; 387 ppa.g.ch = lun->vlun.chnl_id; 388 ppa.g.lun = lun->vlun.lun_id; 389 390 ret = nvm_get_bb_tbl(dev, ppa, blks); 391 if (ret) 392 pr_err("gen: could not get BB table\n"); 393 394 ret = gen_block_bb(gn, ppa, blks, nr_blks); 395 if (ret) 396 pr_err("gen: BB table map failed\n"); 397 } 398 } 399 400 if ((dev->identity.dom & NVM_RSP_L2P) && dev->ops->get_l2p_tbl) { 401 ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, 402 gen_block_map, dev); 403 if (ret) { 404 pr_err("gen: could not read L2P table.\n"); 405 pr_warn("gen: default block initialization"); 406 } 407 } 408 409 kfree(blks); 410 return 0; 411} 412 413static void gen_free(struct nvm_dev *dev) 414{ 415 gen_blocks_free(dev); 416 gen_luns_free(dev); 417 kfree(dev->mp); 418 dev->mp = NULL; 419} 420 421static int gen_register(struct nvm_dev *dev) 422{ 423 struct gen_dev *gn; 424 int ret; 425 426 if (!try_module_get(THIS_MODULE)) 427 return -ENODEV; 428 429 gn = kzalloc(sizeof(struct gen_dev), GFP_KERNEL); 430 if (!gn) 431 return -ENOMEM; 432 433 gn->dev = dev; 434 gn->nr_luns = dev->nr_luns; 435 INIT_LIST_HEAD(&gn->area_list); 436 mutex_init(&gn->lock); 437 INIT_LIST_HEAD(&gn->targets); 438 dev->mp = gn; 439 440 ret = gen_luns_init(dev, gn); 441 if (ret) { 442 pr_err("gen: could not initialize luns\n"); 443 goto err; 444 } 445 446 ret = gen_blocks_init(dev, gn); 447 if (ret) { 448 pr_err("gen: could not initialize blocks\n"); 449 goto err; 450 } 451 452 return 1; 453err: 454 gen_free(dev); 455 module_put(THIS_MODULE); 456 return ret; 457} 458 459static void gen_unregister(struct nvm_dev *dev) 460{ 461 struct gen_dev *gn = dev->mp; 462 struct nvm_target *t, *tmp; 463 464 mutex_lock(&gn->lock); 465 list_for_each_entry_safe(t, tmp, &gn->targets, list) { 466 if (t->dev != dev) 467 continue; 468 __gen_remove_target(t); 469 } 470 mutex_unlock(&gn->lock); 471 472 gen_free(dev); 473 module_put(THIS_MODULE); 474} 475 476static struct nvm_block *gen_get_blk(struct nvm_dev *dev, 477 struct nvm_lun *vlun, unsigned long flags) 478{ 479 struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun); 480 struct nvm_block *blk = NULL; 481 int is_gc = flags & NVM_IOTYPE_GC; 482 483 spin_lock(&vlun->lock); 484 if (list_empty(&lun->free_list)) { 485 pr_err_ratelimited("gen: lun %u have no free pages available", 486 lun->vlun.id); 487 goto out; 488 } 489 490 if (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) 491 goto out; 492 493 blk = list_first_entry(&lun->free_list, struct nvm_block, list); 494 495 list_move_tail(&blk->list, &lun->used_list); 496 blk->state = NVM_BLK_ST_TGT; 497 lun->vlun.nr_free_blocks--; 498out: 499 spin_unlock(&vlun->lock); 500 return blk; 501} 502 503static void gen_put_blk(struct nvm_dev *dev, struct nvm_block *blk) 504{ 505 struct nvm_lun *vlun = blk->lun; 506 struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun); 507 508 spin_lock(&vlun->lock); 509 if (blk->state & NVM_BLK_ST_TGT) { 510 list_move_tail(&blk->list, &lun->free_list); 511 lun->vlun.nr_free_blocks++; 512 blk->state = NVM_BLK_ST_FREE; 513 } else if (blk->state & NVM_BLK_ST_BAD) { 514 list_move_tail(&blk->list, &lun->bb_list); 515 blk->state = NVM_BLK_ST_BAD; 516 } else { 517 WARN_ON_ONCE(1); 518 pr_err("gen: erroneous block type (%lu -> %u)\n", 519 blk->id, blk->state); 520 list_move_tail(&blk->list, &lun->bb_list); 521 } 522 spin_unlock(&vlun->lock); 523} 524 525static void gen_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type) 526{ 527 struct gen_dev *gn = dev->mp; 528 struct gen_lun *lun; 529 struct nvm_block *blk; 530 531 pr_debug("gen: ppa (ch: %u lun: %u blk: %u pg: %u) -> %u\n", 532 ppa.g.ch, ppa.g.lun, ppa.g.blk, ppa.g.pg, type); 533 534 if (unlikely(ppa.g.ch > dev->nr_chnls || 535 ppa.g.lun > dev->luns_per_chnl || 536 ppa.g.blk > dev->blks_per_lun)) { 537 WARN_ON_ONCE(1); 538 pr_err("gen: ppa broken (ch: %u > %u lun: %u > %u blk: %u > %u", 539 ppa.g.ch, dev->nr_chnls, 540 ppa.g.lun, dev->luns_per_chnl, 541 ppa.g.blk, dev->blks_per_lun); 542 return; 543 } 544 545 lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun]; 546 blk = &lun->vlun.blocks[ppa.g.blk]; 547 548 /* will be moved to bb list on put_blk from target */ 549 blk->state = type; 550} 551 552/* 553 * mark block bad in gen. It is expected that the target recovers separately 554 */ 555static void gen_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd) 556{ 557 int bit = -1; 558 int max_secs = dev->ops->max_phys_sect; 559 void *comp_bits = &rqd->ppa_status; 560 561 nvm_addr_to_generic_mode(dev, rqd); 562 563 /* look up blocks and mark them as bad */ 564 if (rqd->nr_ppas == 1) { 565 gen_mark_blk(dev, rqd->ppa_addr, NVM_BLK_ST_BAD); 566 return; 567 } 568 569 while ((bit = find_next_bit(comp_bits, max_secs, bit + 1)) < max_secs) 570 gen_mark_blk(dev, rqd->ppa_list[bit], NVM_BLK_ST_BAD); 571} 572 573static void gen_end_io(struct nvm_rq *rqd) 574{ 575 struct nvm_tgt_instance *ins = rqd->ins; 576 577 if (rqd->error == NVM_RSP_ERR_FAILWRITE) 578 gen_mark_blk_bad(rqd->dev, rqd); 579 580 ins->tt->end_io(rqd); 581} 582 583static int gen_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) 584{ 585 if (!dev->ops->submit_io) 586 return -ENODEV; 587 588 /* Convert address space */ 589 nvm_generic_to_addr_mode(dev, rqd); 590 591 rqd->dev = dev; 592 rqd->end_io = gen_end_io; 593 return dev->ops->submit_io(dev, rqd); 594} 595 596static int gen_erase_blk(struct nvm_dev *dev, struct nvm_block *blk, 597 unsigned long flags) 598{ 599 struct ppa_addr addr = block_to_ppa(dev, blk); 600 601 return nvm_erase_ppa(dev, &addr, 1); 602} 603 604static int gen_reserve_lun(struct nvm_dev *dev, int lunid) 605{ 606 return test_and_set_bit(lunid, dev->lun_map); 607} 608 609static void gen_release_lun(struct nvm_dev *dev, int lunid) 610{ 611 WARN_ON(!test_and_clear_bit(lunid, dev->lun_map)); 612} 613 614static struct nvm_lun *gen_get_lun(struct nvm_dev *dev, int lunid) 615{ 616 struct gen_dev *gn = dev->mp; 617 618 if (unlikely(lunid >= dev->nr_luns)) 619 return NULL; 620 621 return &gn->luns[lunid].vlun; 622} 623 624static void gen_lun_info_print(struct nvm_dev *dev) 625{ 626 struct gen_dev *gn = dev->mp; 627 struct gen_lun *lun; 628 unsigned int i; 629 630 631 gen_for_each_lun(gn, lun, i) { 632 spin_lock(&lun->vlun.lock); 633 634 pr_info("%s: lun%8u\t%u\n", dev->name, i, 635 lun->vlun.nr_free_blocks); 636 637 spin_unlock(&lun->vlun.lock); 638 } 639} 640 641static struct nvmm_type gen = { 642 .name = "gennvm", 643 .version = {0, 1, 0}, 644 645 .register_mgr = gen_register, 646 .unregister_mgr = gen_unregister, 647 648 .create_tgt = gen_create_tgt, 649 .remove_tgt = gen_remove_tgt, 650 651 .get_blk = gen_get_blk, 652 .put_blk = gen_put_blk, 653 654 .submit_io = gen_submit_io, 655 .erase_blk = gen_erase_blk, 656 657 .mark_blk = gen_mark_blk, 658 659 .get_lun = gen_get_lun, 660 .reserve_lun = gen_reserve_lun, 661 .release_lun = gen_release_lun, 662 .lun_info_print = gen_lun_info_print, 663 664 .get_area = gen_get_area, 665 .put_area = gen_put_area, 666 667}; 668 669static int __init gen_module_init(void) 670{ 671 return nvm_register_mgr(&gen); 672} 673 674static void gen_module_exit(void) 675{ 676 nvm_unregister_mgr(&gen); 677} 678 679module_init(gen_module_init); 680module_exit(gen_module_exit); 681MODULE_LICENSE("GPL v2"); 682MODULE_DESCRIPTION("General media manager for Open-Channel SSDs");