Lines Matching +full:erase +full:- +full:size
1 // SPDX-License-Identifier: GPL-2.0
3 #define dev_fmt(fmt) "mtdoops-pstore: " fmt
30 struct mtd_info *mtd = cxt->mtd; in mtdpstore_block_isbad()
33 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_block_isbad()
34 blknum = div_u64(off, mtd->erasesize); in mtdpstore_block_isbad()
36 if (test_bit(blknum, cxt->badmap)) in mtdpstore_block_isbad()
40 dev_err(&mtd->dev, "mtd_block_isbad failed, aborting\n"); in mtdpstore_block_isbad()
43 set_bit(blknum, cxt->badmap); in mtdpstore_block_isbad()
52 struct mtd_info *mtd = cxt->mtd; in mtdpstore_panic_block_isbad()
55 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_panic_block_isbad()
56 blknum = div_u64(off, mtd->erasesize); in mtdpstore_panic_block_isbad()
57 return test_bit(blknum, cxt->badmap); in mtdpstore_panic_block_isbad()
63 struct mtd_info *mtd = cxt->mtd; in mtdpstore_mark_used()
64 u64 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_mark_used()
66 dev_dbg(&mtd->dev, "mark zone %llu used\n", zonenum); in mtdpstore_mark_used()
67 set_bit(zonenum, cxt->usedmap); in mtdpstore_mark_used()
73 struct mtd_info *mtd = cxt->mtd; in mtdpstore_mark_unused()
74 u64 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_mark_unused()
76 dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum); in mtdpstore_mark_unused()
77 clear_bit(zonenum, cxt->usedmap); in mtdpstore_mark_unused()
83 struct mtd_info *mtd = cxt->mtd; in mtdpstore_block_mark_unused()
84 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size; in mtdpstore_block_mark_unused()
87 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_block_mark_unused()
88 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_block_mark_unused()
90 dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum); in mtdpstore_block_mark_unused()
91 clear_bit(zonenum, cxt->usedmap); in mtdpstore_block_mark_unused()
93 zonecnt--; in mtdpstore_block_mark_unused()
99 u64 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_is_used()
100 u64 blknum = div_u64(off, cxt->mtd->erasesize); in mtdpstore_is_used()
102 if (test_bit(blknum, cxt->badmap)) in mtdpstore_is_used()
104 return test_bit(zonenum, cxt->usedmap); in mtdpstore_is_used()
110 struct mtd_info *mtd = cxt->mtd; in mtdpstore_block_is_used()
111 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size; in mtdpstore_block_is_used()
114 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_block_is_used()
115 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_block_is_used()
117 if (test_bit(zonenum, cxt->usedmap)) in mtdpstore_block_is_used()
120 zonecnt--; in mtdpstore_block_is_used()
126 size_t size) in mtdpstore_is_empty() argument
128 struct mtd_info *mtd = cxt->mtd; in mtdpstore_is_empty()
132 sz = min_t(uint32_t, size, mtd->writesize / 4); in mtdpstore_is_empty()
142 struct mtd_info *mtd = cxt->mtd; in mtdpstore_mark_removed()
143 u64 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_mark_removed()
145 dev_dbg(&mtd->dev, "mark zone %llu removed\n", zonenum); in mtdpstore_mark_removed()
146 set_bit(zonenum, cxt->rmmap); in mtdpstore_mark_removed()
152 struct mtd_info *mtd = cxt->mtd; in mtdpstore_block_clear_removed()
153 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size; in mtdpstore_block_clear_removed()
156 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_block_clear_removed()
157 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_block_clear_removed()
159 clear_bit(zonenum, cxt->rmmap); in mtdpstore_block_clear_removed()
161 zonecnt--; in mtdpstore_block_clear_removed()
168 struct mtd_info *mtd = cxt->mtd; in mtdpstore_block_is_removed()
169 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size; in mtdpstore_block_is_removed()
172 off = ALIGN_DOWN(off, mtd->erasesize); in mtdpstore_block_is_removed()
173 zonenum = div_u64(off, cxt->info.kmsg_size); in mtdpstore_block_is_removed()
175 if (test_bit(zonenum, cxt->rmmap)) in mtdpstore_block_is_removed()
178 zonecnt--; in mtdpstore_block_is_removed()
185 struct mtd_info *mtd = cxt->mtd; in mtdpstore_erase_do()
186 struct erase_info erase; in mtdpstore_erase_do() local
189 off = ALIGN_DOWN(off, cxt->mtd->erasesize); in mtdpstore_erase_do()
190 dev_dbg(&mtd->dev, "try to erase off 0x%llx\n", off); in mtdpstore_erase_do()
191 erase.len = cxt->mtd->erasesize; in mtdpstore_erase_do()
192 erase.addr = off; in mtdpstore_erase_do()
193 ret = mtd_erase(cxt->mtd, &erase); in mtdpstore_erase_do()
197 dev_err(&mtd->dev, "erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", in mtdpstore_erase_do()
198 (unsigned long long)erase.addr, in mtdpstore_erase_do()
199 (unsigned long long)erase.len, cxt->info.device); in mtdpstore_erase_do()
206 * Avoiding over erasing, do erase block only when the whole block is unused.
207 * If the block contains valid log, do erase lazily on flush_removed() when
210 static ssize_t mtdpstore_erase(size_t size, loff_t off) in mtdpstore_erase() argument
215 return -EIO; in mtdpstore_erase()
219 /* If the block still has valid data, mtdpstore do erase lazily */ in mtdpstore_erase()
225 /* all zones are unused, erase it */ in mtdpstore_erase()
231 * As there is no erase for panic case, we should ensure at least one zone
233 * If zone is used, write operation will return -ENOMSG, which means that
240 struct mtd_info *mtd = cxt->mtd; in mtdpstore_security()
241 u32 zonenum = (u32)div_u64(off, cxt->info.kmsg_size); in mtdpstore_security()
242 u32 zonecnt = (u32)div_u64(cxt->mtd->size, cxt->info.kmsg_size); in mtdpstore_security()
243 u32 blkcnt = (u32)div_u64(cxt->mtd->size, cxt->mtd->erasesize); in mtdpstore_security()
244 u32 erasesize = cxt->mtd->erasesize; in mtdpstore_security()
250 if (!test_bit(num, cxt->usedmap)) in mtdpstore_security()
254 /* If there is no any empty zone, we have no way but to do erase */ in mtdpstore_security()
255 while (blkcnt--) { in mtdpstore_security()
256 div64_u64_rem(off + erasesize, cxt->mtd->size, (u64 *)&off); in mtdpstore_security()
269 dev_err(&mtd->dev, "all blocks bad!\n"); in mtdpstore_security()
270 dev_dbg(&mtd->dev, "end security\n"); in mtdpstore_security()
274 static ssize_t mtdpstore_write(const char *buf, size_t size, loff_t off) in mtdpstore_write() argument
277 struct mtd_info *mtd = cxt->mtd; in mtdpstore_write()
282 return -ENOMSG; in mtdpstore_write()
286 return -ENOMSG; in mtdpstore_write()
288 dev_dbg(&mtd->dev, "try to write off 0x%llx size %zu\n", off, size); in mtdpstore_write()
289 ret = mtd_write(cxt->mtd, off, size, &retlen, (u_char *)buf); in mtdpstore_write()
290 if (ret < 0 || retlen != size) { in mtdpstore_write()
291 dev_err(&mtd->dev, "write failure at %lld (%zu of %zu written), err %d\n", in mtdpstore_write()
292 off, retlen, size, ret); in mtdpstore_write()
293 return -EIO; in mtdpstore_write()
310 static ssize_t mtdpstore_read(char *buf, size_t size, loff_t off) in mtdpstore_read() argument
313 struct mtd_info *mtd = cxt->mtd; in mtdpstore_read()
318 return -ENOMSG; in mtdpstore_read()
320 dev_dbg(&mtd->dev, "try to read off 0x%llx size %zu\n", off, size); in mtdpstore_read()
321 for (done = 0, retlen = 0; done < size; done += retlen) { in mtdpstore_read()
324 ret = mtd_read(cxt->mtd, off + done, size - done, &retlen, in mtdpstore_read()
327 dev_err(&mtd->dev, "read failure at %lld (%zu of %zu read), err %d\n", in mtdpstore_read()
328 off + done, retlen, size - done, ret); in mtdpstore_read()
330 return -ENOMSG; in mtdpstore_read()
340 dev_err(&mtd->dev, "ecc error at %lld (%zu of %zu read), err %d\n", in mtdpstore_read()
341 off + done, retlen, size - done, ret); in mtdpstore_read()
343 retlen = retlen == 0 ? size - done : retlen; in mtdpstore_read()
347 if (mtdpstore_is_empty(cxt, buf, size)) in mtdpstore_read()
356 static ssize_t mtdpstore_panic_write(const char *buf, size_t size, loff_t off) in mtdpstore_panic_write() argument
359 struct mtd_info *mtd = cxt->mtd; in mtdpstore_panic_write()
364 return -ENOMSG; in mtdpstore_panic_write()
368 return -ENOMSG; in mtdpstore_panic_write()
370 ret = mtd_panic_write(cxt->mtd, off, size, &retlen, (u_char *)buf); in mtdpstore_panic_write()
371 if (ret < 0 || size != retlen) { in mtdpstore_panic_write()
372 dev_err(&mtd->dev, "panic write failure at %lld (%zu of %zu read), err %d\n", in mtdpstore_panic_write()
373 off, retlen, size, ret); in mtdpstore_panic_write()
374 return -EIO; in mtdpstore_panic_write()
385 struct pstore_blk_config *info = &cxt->info; in mtdpstore_notify_add()
388 if (!strcmp(mtd->name, info->device)) in mtdpstore_notify_add()
389 cxt->index = mtd->index; in mtdpstore_notify_add()
391 if (mtd->index != cxt->index || cxt->index < 0) in mtdpstore_notify_add()
394 dev_dbg(&mtd->dev, "found matching MTD device %s\n", mtd->name); in mtdpstore_notify_add()
396 if (mtd->size < info->kmsg_size * 2) { in mtdpstore_notify_add()
397 dev_err(&mtd->dev, "MTD partition %d not big enough\n", in mtdpstore_notify_add()
398 mtd->index); in mtdpstore_notify_add()
407 if (mtd->erasesize < info->kmsg_size) { in mtdpstore_notify_add()
408 dev_err(&mtd->dev, "eraseblock size of MTD partition %d too small\n", in mtdpstore_notify_add()
409 mtd->index); in mtdpstore_notify_add()
412 if (unlikely(info->kmsg_size % mtd->writesize)) { in mtdpstore_notify_add()
413 dev_err(&mtd->dev, "record size %lu KB must align to write size %d KB\n", in mtdpstore_notify_add()
414 info->kmsg_size / 1024, in mtdpstore_notify_add()
415 mtd->writesize / 1024); in mtdpstore_notify_add()
419 longcnt = BITS_TO_LONGS(div_u64(mtd->size, info->kmsg_size)); in mtdpstore_notify_add()
420 cxt->rmmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); in mtdpstore_notify_add()
421 cxt->usedmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); in mtdpstore_notify_add()
423 longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize)); in mtdpstore_notify_add()
424 cxt->badmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); in mtdpstore_notify_add()
426 if (!cxt->rmmap || !cxt->usedmap || !cxt->badmap) in mtdpstore_notify_add()
430 cxt->dev.flags = PSTORE_FLAGS_DMESG; in mtdpstore_notify_add()
431 cxt->dev.zone.read = mtdpstore_read; in mtdpstore_notify_add()
432 cxt->dev.zone.write = mtdpstore_write; in mtdpstore_notify_add()
433 cxt->dev.zone.erase = mtdpstore_erase; in mtdpstore_notify_add()
434 cxt->dev.zone.panic_write = mtdpstore_panic_write; in mtdpstore_notify_add()
435 cxt->dev.zone.total_size = mtd->size; in mtdpstore_notify_add()
437 ret = register_pstore_device(&cxt->dev); in mtdpstore_notify_add()
439 dev_err(&mtd->dev, "mtd%d register to psblk failed\n", in mtdpstore_notify_add()
440 mtd->index); in mtdpstore_notify_add()
443 cxt->mtd = mtd; in mtdpstore_notify_add()
444 dev_info(&mtd->dev, "Attached to MTD device %d\n", mtd->index); in mtdpstore_notify_add()
448 loff_t off, size_t size) in mtdpstore_flush_removed_do() argument
450 struct mtd_info *mtd = cxt->mtd; in mtdpstore_flush_removed_do()
454 struct erase_info erase; in mtdpstore_flush_removed_do() local
456 buf = kmalloc(mtd->erasesize, GFP_KERNEL); in mtdpstore_flush_removed_do()
458 return -ENOMEM; in mtdpstore_flush_removed_do()
461 ret = mtd_read(mtd, off, mtd->erasesize, &retlen, buf); in mtdpstore_flush_removed_do()
465 /* 2nd. erase block */ in mtdpstore_flush_removed_do()
466 erase.len = mtd->erasesize; in mtdpstore_flush_removed_do()
467 erase.addr = off; in mtdpstore_flush_removed_do()
468 ret = mtd_erase(mtd, &erase); in mtdpstore_flush_removed_do()
473 while (size) { in mtdpstore_flush_removed_do()
474 unsigned int zonesize = cxt->info.kmsg_size; in mtdpstore_flush_removed_do()
480 dev_err(&mtd->dev, "write failure at %lld (%zu of %u written), err %d\n", in mtdpstore_flush_removed_do()
485 size -= min_t(unsigned int, zonesize, size); in mtdpstore_flush_removed_do()
497 * it's nice to erase the block. However if the block still contains valid log,
498 * what mtdpstore can do is to erase and write the valid log back.
502 struct mtd_info *mtd = cxt->mtd; in mtdpstore_flush_removed()
505 u32 blkcnt = (u32)div_u64(mtd->size, mtd->erasesize); in mtdpstore_flush_removed()
507 for (off = 0; blkcnt > 0; blkcnt--, off += mtd->erasesize) { in mtdpstore_flush_removed()
516 ret = mtdpstore_flush_removed_do(cxt, off, mtd->erasesize); in mtdpstore_flush_removed()
527 if (mtd->index != cxt->index || cxt->index < 0) in mtdpstore_notify_remove()
532 unregister_pstore_device(&cxt->dev); in mtdpstore_notify_remove()
533 cxt->mtd = NULL; in mtdpstore_notify_remove()
534 cxt->index = -1; in mtdpstore_notify_remove()
546 struct pstore_blk_config *info = &cxt->info; in mtdpstore_init()
552 if (strlen(info->device) == 0) { in mtdpstore_init()
554 return -EINVAL; in mtdpstore_init()
556 if (!info->kmsg_size) { in mtdpstore_init()
558 return -EINVAL; in mtdpstore_init()
562 ret = kstrtoint((char *)info->device, 0, &cxt->index); in mtdpstore_init()
564 cxt->index = -1; in mtdpstore_init()