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

MTD: nandsim: add option to use a file to cache pages

Add a new module parameter 'cache_file' which causes nandsim
to use that file instead of memory to cache nand data.
Using a file allows the simulation of NAND that is bigger
than the available memory.

Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Adrian Hunter and committed by
David Woodhouse
a9fc8991 9359ea46

+261 -24
+261 -24
drivers/mtd/nand/nandsim.c
··· 38 38 #include <linux/delay.h> 39 39 #include <linux/list.h> 40 40 #include <linux/random.h> 41 + #include <linux/fs.h> 42 + #include <linux/pagemap.h> 41 43 42 44 /* Default simulator parameters values */ 43 45 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ ··· 102 100 static char *gravepages = NULL; 103 101 static unsigned int rptwear = 0; 104 102 static unsigned int overridesize = 0; 103 + static char *cache_file = NULL; 105 104 106 105 module_param(first_id_byte, uint, 0400); 107 106 module_param(second_id_byte, uint, 0400); ··· 125 122 module_param(gravepages, charp, 0400); 126 123 module_param(rptwear, uint, 0400); 127 124 module_param(overridesize, uint, 0400); 125 + module_param(cache_file, charp, 0400); 128 126 129 127 MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); 130 128 MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); 131 129 MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); 132 130 MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); 133 - MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); 131 + MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); 134 132 MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); 135 133 MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); 136 134 MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); ··· 157 153 MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " 158 154 "The size is specified in erase blocks and as the exponent of a power of two" 159 155 " e.g. 5 means a size of 32 erase blocks"); 156 + MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); 160 157 161 158 /* The largest possible page size */ 162 159 #define NS_LARGEST_PAGE_SIZE 2048 ··· 271 266 */ 272 267 #define NS_MAX_PREVSTATES 1 273 268 269 + /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ 270 + #define NS_MAX_HELD_PAGES 16 271 + 274 272 /* 275 273 * A union to represent flash memory contents and flash buffer. 276 274 */ ··· 343 335 int ale; /* address Latch Enable */ 344 336 int wp; /* write Protect */ 345 337 } lines; 338 + 339 + /* Fields needed when using a cache file */ 340 + struct file *cfile; /* Open file */ 341 + unsigned char *pages_written; /* Which pages have been written */ 342 + void *file_buf; 343 + struct page *held_pages[NS_MAX_HELD_PAGES]; 344 + int held_cnt; 346 345 }; 347 346 348 347 /* ··· 442 427 */ 443 428 static int alloc_device(struct nandsim *ns) 444 429 { 445 - int i; 430 + struct file *cfile; 431 + int i, err; 432 + 433 + if (cache_file) { 434 + cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); 435 + if (IS_ERR(cfile)) 436 + return PTR_ERR(cfile); 437 + if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { 438 + NS_ERR("alloc_device: cache file not readable\n"); 439 + err = -EINVAL; 440 + goto err_close; 441 + } 442 + if (!cfile->f_op->write && !cfile->f_op->aio_write) { 443 + NS_ERR("alloc_device: cache file not writeable\n"); 444 + err = -EINVAL; 445 + goto err_close; 446 + } 447 + ns->pages_written = vmalloc(ns->geom.pgnum); 448 + if (!ns->pages_written) { 449 + NS_ERR("alloc_device: unable to allocate pages written array\n"); 450 + err = -ENOMEM; 451 + goto err_close; 452 + } 453 + ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); 454 + if (!ns->file_buf) { 455 + NS_ERR("alloc_device: unable to allocate file buf\n"); 456 + err = -ENOMEM; 457 + goto err_free; 458 + } 459 + ns->cfile = cfile; 460 + memset(ns->pages_written, 0, ns->geom.pgnum); 461 + return 0; 462 + } 446 463 447 464 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); 448 465 if (!ns->pages) { 449 - NS_ERR("alloc_map: unable to allocate page array\n"); 466 + NS_ERR("alloc_device: unable to allocate page array\n"); 450 467 return -ENOMEM; 451 468 } 452 469 for (i = 0; i < ns->geom.pgnum; i++) { ··· 486 439 } 487 440 488 441 return 0; 442 + 443 + err_free: 444 + vfree(ns->pages_written); 445 + err_close: 446 + filp_close(cfile, NULL); 447 + return err; 489 448 } 490 449 491 450 /* ··· 500 447 static void free_device(struct nandsim *ns) 501 448 { 502 449 int i; 450 + 451 + if (ns->cfile) { 452 + kfree(ns->file_buf); 453 + vfree(ns->pages_written); 454 + filp_close(ns->cfile, NULL); 455 + return; 456 + } 503 457 504 458 if (ns->pages) { 505 459 for (i = 0; i < ns->geom.pgnum; i++) { ··· 1271 1211 return -1; 1272 1212 } 1273 1213 1214 + static void put_pages(struct nandsim *ns) 1215 + { 1216 + int i; 1217 + 1218 + for (i = 0; i < ns->held_cnt; i++) 1219 + page_cache_release(ns->held_pages[i]); 1220 + } 1221 + 1222 + /* Get page cache pages in advance to provide NOFS memory allocation */ 1223 + static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) 1224 + { 1225 + pgoff_t index, start_index, end_index; 1226 + struct page *page; 1227 + struct address_space *mapping = file->f_mapping; 1228 + 1229 + start_index = pos >> PAGE_CACHE_SHIFT; 1230 + end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT; 1231 + if (end_index - start_index + 1 > NS_MAX_HELD_PAGES) 1232 + return -EINVAL; 1233 + ns->held_cnt = 0; 1234 + for (index = start_index; index <= end_index; index++) { 1235 + page = find_get_page(mapping, index); 1236 + if (page == NULL) { 1237 + page = find_or_create_page(mapping, index, GFP_NOFS); 1238 + if (page == NULL) { 1239 + write_inode_now(mapping->host, 1); 1240 + page = find_or_create_page(mapping, index, GFP_NOFS); 1241 + } 1242 + if (page == NULL) { 1243 + put_pages(ns); 1244 + return -ENOMEM; 1245 + } 1246 + unlock_page(page); 1247 + } 1248 + ns->held_pages[ns->held_cnt++] = page; 1249 + } 1250 + return 0; 1251 + } 1252 + 1253 + static int set_memalloc(void) 1254 + { 1255 + if (current->flags & PF_MEMALLOC) 1256 + return 0; 1257 + current->flags |= PF_MEMALLOC; 1258 + return 1; 1259 + } 1260 + 1261 + static void clear_memalloc(int memalloc) 1262 + { 1263 + if (memalloc) 1264 + current->flags &= ~PF_MEMALLOC; 1265 + } 1266 + 1267 + static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) 1268 + { 1269 + mm_segment_t old_fs; 1270 + ssize_t tx; 1271 + int err, memalloc; 1272 + 1273 + err = get_pages(ns, file, count, *pos); 1274 + if (err) 1275 + return err; 1276 + old_fs = get_fs(); 1277 + set_fs(get_ds()); 1278 + memalloc = set_memalloc(); 1279 + tx = vfs_read(file, (char __user *)buf, count, pos); 1280 + clear_memalloc(memalloc); 1281 + set_fs(old_fs); 1282 + put_pages(ns); 1283 + return tx; 1284 + } 1285 + 1286 + static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) 1287 + { 1288 + mm_segment_t old_fs; 1289 + ssize_t tx; 1290 + int err, memalloc; 1291 + 1292 + err = get_pages(ns, file, count, *pos); 1293 + if (err) 1294 + return err; 1295 + old_fs = get_fs(); 1296 + set_fs(get_ds()); 1297 + memalloc = set_memalloc(); 1298 + tx = vfs_write(file, (char __user *)buf, count, pos); 1299 + clear_memalloc(memalloc); 1300 + set_fs(old_fs); 1301 + put_pages(ns); 1302 + return tx; 1303 + } 1304 + 1274 1305 /* 1275 1306 * Returns a pointer to the current page. 1276 1307 */ ··· 1378 1227 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; 1379 1228 } 1380 1229 1230 + int do_read_error(struct nandsim *ns, int num) 1231 + { 1232 + unsigned int page_no = ns->regs.row; 1233 + 1234 + if (read_error(page_no)) { 1235 + int i; 1236 + memset(ns->buf.byte, 0xFF, num); 1237 + for (i = 0; i < num; ++i) 1238 + ns->buf.byte[i] = random32(); 1239 + NS_WARN("simulating read error in page %u\n", page_no); 1240 + return 1; 1241 + } 1242 + return 0; 1243 + } 1244 + 1245 + void do_bit_flips(struct nandsim *ns, int num) 1246 + { 1247 + if (bitflips && random32() < (1 << 22)) { 1248 + int flips = 1; 1249 + if (bitflips > 1) 1250 + flips = (random32() % (int) bitflips) + 1; 1251 + while (flips--) { 1252 + int pos = random32() % (num * 8); 1253 + ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); 1254 + NS_WARN("read_page: flipping bit %d in page %d " 1255 + "reading from %d ecc: corrected=%u failed=%u\n", 1256 + pos, ns->regs.row, ns->regs.column + ns->regs.off, 1257 + nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); 1258 + } 1259 + } 1260 + } 1261 + 1381 1262 /* 1382 1263 * Fill the NAND buffer with data read from the specified page. 1383 1264 */ ··· 1417 1234 { 1418 1235 union ns_mem *mypage; 1419 1236 1237 + if (ns->cfile) { 1238 + if (!ns->pages_written[ns->regs.row]) { 1239 + NS_DBG("read_page: page %d not written\n", ns->regs.row); 1240 + memset(ns->buf.byte, 0xFF, num); 1241 + } else { 1242 + loff_t pos; 1243 + ssize_t tx; 1244 + 1245 + NS_DBG("read_page: page %d written, reading from %d\n", 1246 + ns->regs.row, ns->regs.column + ns->regs.off); 1247 + if (do_read_error(ns, num)) 1248 + return; 1249 + pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; 1250 + tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos); 1251 + if (tx != num) { 1252 + NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); 1253 + return; 1254 + } 1255 + do_bit_flips(ns, num); 1256 + } 1257 + return; 1258 + } 1259 + 1420 1260 mypage = NS_GET_PAGE(ns); 1421 1261 if (mypage->byte == NULL) { 1422 1262 NS_DBG("read_page: page %d not allocated\n", ns->regs.row); 1423 1263 memset(ns->buf.byte, 0xFF, num); 1424 1264 } else { 1425 - unsigned int page_no = ns->regs.row; 1426 1265 NS_DBG("read_page: page %d allocated, reading from %d\n", 1427 1266 ns->regs.row, ns->regs.column + ns->regs.off); 1428 - if (read_error(page_no)) { 1429 - int i; 1430 - memset(ns->buf.byte, 0xFF, num); 1431 - for (i = 0; i < num; ++i) 1432 - ns->buf.byte[i] = random32(); 1433 - NS_WARN("simulating read error in page %u\n", page_no); 1267 + if (do_read_error(ns, num)) 1434 1268 return; 1435 - } 1436 1269 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); 1437 - if (bitflips && random32() < (1 << 22)) { 1438 - int flips = 1; 1439 - if (bitflips > 1) 1440 - flips = (random32() % (int) bitflips) + 1; 1441 - while (flips--) { 1442 - int pos = random32() % (num * 8); 1443 - ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); 1444 - NS_WARN("read_page: flipping bit %d in page %d " 1445 - "reading from %d ecc: corrected=%u failed=%u\n", 1446 - pos, ns->regs.row, ns->regs.column + ns->regs.off, 1447 - nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); 1448 - } 1449 - } 1270 + do_bit_flips(ns, num); 1450 1271 } 1451 1272 } 1452 1273 ··· 1461 1274 { 1462 1275 union ns_mem *mypage; 1463 1276 int i; 1277 + 1278 + if (ns->cfile) { 1279 + for (i = 0; i < ns->geom.pgsec; i++) 1280 + if (ns->pages_written[ns->regs.row + i]) { 1281 + NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); 1282 + ns->pages_written[ns->regs.row + i] = 0; 1283 + } 1284 + return; 1285 + } 1464 1286 1465 1287 mypage = NS_GET_PAGE(ns); 1466 1288 for (i = 0; i < ns->geom.pgsec; i++) { ··· 1490 1294 int i; 1491 1295 union ns_mem *mypage; 1492 1296 u_char *pg_off; 1297 + 1298 + if (ns->cfile) { 1299 + loff_t off, pos; 1300 + ssize_t tx; 1301 + int all; 1302 + 1303 + NS_DBG("prog_page: writing page %d\n", ns->regs.row); 1304 + pg_off = ns->file_buf + ns->regs.column + ns->regs.off; 1305 + off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; 1306 + if (!ns->pages_written[ns->regs.row]) { 1307 + all = 1; 1308 + memset(ns->file_buf, 0xff, ns->geom.pgszoob); 1309 + } else { 1310 + all = 0; 1311 + pos = off; 1312 + tx = read_file(ns, ns->cfile, pg_off, num, &pos); 1313 + if (tx != num) { 1314 + NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); 1315 + return -1; 1316 + } 1317 + } 1318 + for (i = 0; i < num; i++) 1319 + pg_off[i] &= ns->buf.byte[i]; 1320 + if (all) { 1321 + pos = (loff_t)ns->regs.row * ns->geom.pgszoob; 1322 + tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); 1323 + if (tx != ns->geom.pgszoob) { 1324 + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); 1325 + return -1; 1326 + } 1327 + ns->pages_written[ns->regs.row] = 1; 1328 + } else { 1329 + pos = off; 1330 + tx = write_file(ns, ns->cfile, pg_off, num, &pos); 1331 + if (tx != num) { 1332 + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); 1333 + return -1; 1334 + } 1335 + } 1336 + return 0; 1337 + } 1493 1338 1494 1339 mypage = NS_GET_PAGE(ns); 1495 1340 if (mypage->byte == NULL) {