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

lightnvm: specify target's logical address area

We can create more than one target on a lightnvm
device by specifying its begin lun and end lun.

But only specify the physical address area is not
enough, we need to get the corresponding non-
intersection logical address area division from
the backend device's logcial address space.
Otherwise the targets on the device might use
the same logical addresses cause incorrect
information in the device's l2p table.

Signed-off-by: Wenwei Tao <ww.tao0320@gmail.com>
Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Wenwei Tao and committed by
Jens Axboe
4c9dacb8 3681c85d

+116 -2
+1
drivers/lightnvm/core.c
··· 466 466 dev->total_secs = dev->nr_luns * dev->sec_per_lun; 467 467 INIT_LIST_HEAD(&dev->online_targets); 468 468 mutex_init(&dev->mlock); 469 + spin_lock_init(&dev->lock); 469 470 470 471 return 0; 471 472 }
+67
drivers/lightnvm/gennvm.c
··· 20 20 21 21 #include "gennvm.h" 22 22 23 + static int gennvm_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len) 24 + { 25 + struct gen_nvm *gn = dev->mp; 26 + struct gennvm_area *area, *prev, *next; 27 + sector_t begin = 0; 28 + sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9; 29 + 30 + if (len > max_sectors) 31 + return -EINVAL; 32 + 33 + area = kmalloc(sizeof(struct gennvm_area), GFP_KERNEL); 34 + if (!area) 35 + return -ENOMEM; 36 + 37 + prev = NULL; 38 + 39 + spin_lock(&dev->lock); 40 + list_for_each_entry(next, &gn->area_list, list) { 41 + if (begin + len > next->begin) { 42 + begin = next->end; 43 + prev = next; 44 + continue; 45 + } 46 + break; 47 + } 48 + 49 + if ((begin + len) > max_sectors) { 50 + spin_unlock(&dev->lock); 51 + kfree(area); 52 + return -EINVAL; 53 + } 54 + 55 + area->begin = *lba = begin; 56 + area->end = begin + len; 57 + 58 + if (prev) /* insert into sorted order */ 59 + list_add(&area->list, &prev->list); 60 + else 61 + list_add(&area->list, &gn->area_list); 62 + spin_unlock(&dev->lock); 63 + 64 + return 0; 65 + } 66 + 67 + static void gennvm_put_area(struct nvm_dev *dev, sector_t begin) 68 + { 69 + struct gen_nvm *gn = dev->mp; 70 + struct gennvm_area *area; 71 + 72 + spin_lock(&dev->lock); 73 + list_for_each_entry(area, &gn->area_list, list) { 74 + if (area->begin != begin) 75 + continue; 76 + 77 + list_del(&area->list); 78 + spin_unlock(&dev->lock); 79 + kfree(area); 80 + return; 81 + } 82 + spin_unlock(&dev->lock); 83 + } 84 + 23 85 static void gennvm_blocks_free(struct nvm_dev *dev) 24 86 { 25 87 struct gen_nvm *gn = dev->mp; ··· 291 229 292 230 gn->dev = dev; 293 231 gn->nr_luns = dev->nr_luns; 232 + INIT_LIST_HEAD(&gn->area_list); 294 233 dev->mp = gn; 295 234 296 235 ret = gennvm_luns_init(dev, gn); ··· 528 465 529 466 .get_lun = gennvm_get_lun, 530 467 .lun_info_print = gennvm_lun_info_print, 468 + 469 + .get_area = gennvm_get_area, 470 + .put_area = gennvm_put_area, 471 + 531 472 }; 532 473 533 474 static int __init gennvm_module_init(void)
+6
drivers/lightnvm/gennvm.h
··· 39 39 40 40 int nr_luns; 41 41 struct gen_lun *luns; 42 + struct list_head area_list; 42 43 }; 43 44 45 + struct gennvm_area { 46 + struct list_head list; 47 + sector_t begin; 48 + sector_t end; /* end is excluded */ 49 + }; 44 50 #define gennvm_for_each_lun(bm, lun, i) \ 45 51 for ((i) = 0, lun = &(bm)->luns[0]; \ 46 52 (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)])
+33 -2
drivers/lightnvm/rrpc.c
··· 1053 1053 { 1054 1054 struct nvm_dev *dev = rrpc->dev; 1055 1055 sector_t i; 1056 + u64 slba; 1056 1057 int ret; 1058 + 1059 + slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9); 1057 1060 1058 1061 rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); 1059 1062 if (!rrpc->trans_map) ··· 1079 1076 return 0; 1080 1077 1081 1078 /* Bring up the mapping table from device */ 1082 - ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update, 1079 + ret = dev->ops->get_l2p_tbl(dev, slba, rrpc->nr_sects, rrpc_l2p_update, 1083 1080 rrpc); 1084 1081 if (ret) { 1085 1082 pr_err("nvm: rrpc: could not read L2P table.\n"); ··· 1088 1085 1089 1086 return 0; 1090 1087 } 1091 - 1092 1088 1093 1089 /* Minimum pages needed within a lun */ 1094 1090 #define PAGE_POOL_SIZE 16 ··· 1202 1200 return -ENOMEM; 1203 1201 } 1204 1202 1203 + /* returns 0 on success and stores the beginning address in *begin */ 1204 + static int rrpc_area_init(struct rrpc *rrpc, sector_t *begin) 1205 + { 1206 + struct nvm_dev *dev = rrpc->dev; 1207 + struct nvmm_type *mt = dev->mt; 1208 + sector_t size = rrpc->nr_sects * dev->sec_size; 1209 + 1210 + size >>= 9; 1211 + 1212 + return mt->get_area(dev, begin, size); 1213 + } 1214 + 1215 + static void rrpc_area_free(struct rrpc *rrpc) 1216 + { 1217 + struct nvm_dev *dev = rrpc->dev; 1218 + struct nvmm_type *mt = dev->mt; 1219 + 1220 + mt->put_area(dev, rrpc->soffset); 1221 + } 1222 + 1205 1223 static void rrpc_free(struct rrpc *rrpc) 1206 1224 { 1207 1225 rrpc_gc_free(rrpc); 1208 1226 rrpc_map_free(rrpc); 1209 1227 rrpc_core_free(rrpc); 1210 1228 rrpc_luns_free(rrpc); 1229 + rrpc_area_free(rrpc); 1211 1230 1212 1231 kfree(rrpc); 1213 1232 } ··· 1350 1327 struct request_queue *bqueue = dev->q; 1351 1328 struct request_queue *tqueue = tdisk->queue; 1352 1329 struct rrpc *rrpc; 1330 + sector_t soffset; 1353 1331 int ret; 1354 1332 1355 1333 if (!(dev->identity.dom & NVM_RSP_L2P)) { ··· 1375 1351 1376 1352 /* simple round-robin strategy */ 1377 1353 atomic_set(&rrpc->next_lun, -1); 1354 + 1355 + ret = rrpc_area_init(rrpc, &soffset); 1356 + if (ret < 0) { 1357 + pr_err("nvm: rrpc: could not initialize area\n"); 1358 + return ERR_PTR(ret); 1359 + } 1360 + rrpc->soffset = soffset; 1378 1361 1379 1362 ret = rrpc_luns_init(rrpc, lun_begin, lun_end); 1380 1363 if (ret) {
+1
drivers/lightnvm/rrpc.h
··· 97 97 struct nvm_dev *dev; 98 98 struct gendisk *disk; 99 99 100 + sector_t soffset; /* logical sector offset */ 100 101 u64 poffset; /* physical page offset */ 101 102 int lun_offset; 102 103
+8
include/linux/lightnvm.h
··· 355 355 char name[DISK_NAME_LEN]; 356 356 357 357 struct mutex mlock; 358 + spinlock_t lock; 358 359 }; 359 360 360 361 static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, ··· 468 467 typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); 469 468 typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); 470 469 470 + typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); 471 + typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t); 472 + 471 473 struct nvmm_type { 472 474 const char *name; 473 475 unsigned int version[3]; ··· 495 491 496 492 /* Statistics */ 497 493 nvmm_lun_info_print_fn *lun_info_print; 494 + 495 + nvmm_get_area_fn *get_area; 496 + nvmm_put_area_fn *put_area; 497 + 498 498 struct list_head list; 499 499 }; 500 500