Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#define dev_fmt(fmt) "mtdoops-pstore: " fmt
  4
  5#include <linux/kernel.h>
  6#include <linux/module.h>
  7#include <linux/pstore_blk.h>
  8#include <linux/mtd/mtd.h>
  9#include <linux/bitops.h>
 10#include <linux/slab.h>
 11
 12static struct mtdpstore_context {
 13	int index;
 14	struct pstore_blk_config info;
 15	struct pstore_device_info dev;
 16	struct mtd_info *mtd;
 17	unsigned long *rmmap;		/* removed bit map */
 18	unsigned long *usedmap;		/* used bit map */
 19	/*
 20	 * used for panic write
 21	 * As there are no block_isbad for panic case, we should keep this
 22	 * status before panic to ensure panic_write not failed.
 23	 */
 24	unsigned long *badmap;		/* bad block bit map */
 25} oops_cxt;
 26
 27static int mtdpstore_block_isbad(struct mtdpstore_context *cxt, loff_t off)
 28{
 29	int ret;
 30	struct mtd_info *mtd = cxt->mtd;
 31	u64 blknum;
 32
 33	off = ALIGN_DOWN(off, mtd->erasesize);
 34	blknum = div_u64(off, mtd->erasesize);
 35
 36	if (test_bit(blknum, cxt->badmap))
 37		return true;
 38	ret = mtd_block_isbad(mtd, off);
 39	if (ret < 0) {
 40		dev_err(&mtd->dev, "mtd_block_isbad failed, aborting\n");
 41		return ret;
 42	} else if (ret > 0) {
 43		set_bit(blknum, cxt->badmap);
 44		return true;
 45	}
 46	return false;
 47}
 48
 49static inline int mtdpstore_panic_block_isbad(struct mtdpstore_context *cxt,
 50		loff_t off)
 51{
 52	struct mtd_info *mtd = cxt->mtd;
 53	u64 blknum;
 54
 55	off = ALIGN_DOWN(off, mtd->erasesize);
 56	blknum = div_u64(off, mtd->erasesize);
 57	return test_bit(blknum, cxt->badmap);
 58}
 59
 60static inline void mtdpstore_mark_used(struct mtdpstore_context *cxt,
 61		loff_t off)
 62{
 63	struct mtd_info *mtd = cxt->mtd;
 64	u64 zonenum = div_u64(off, cxt->info.kmsg_size);
 65
 66	dev_dbg(&mtd->dev, "mark zone %llu used\n", zonenum);
 67	set_bit(zonenum, cxt->usedmap);
 68}
 69
 70static inline void mtdpstore_mark_unused(struct mtdpstore_context *cxt,
 71		loff_t off)
 72{
 73	struct mtd_info *mtd = cxt->mtd;
 74	u64 zonenum = div_u64(off, cxt->info.kmsg_size);
 75
 76	dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum);
 77	clear_bit(zonenum, cxt->usedmap);
 78}
 79
 80static inline void mtdpstore_block_mark_unused(struct mtdpstore_context *cxt,
 81		loff_t off)
 82{
 83	struct mtd_info *mtd = cxt->mtd;
 84	u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;
 85	u64 zonenum;
 86
 87	off = ALIGN_DOWN(off, mtd->erasesize);
 88	zonenum = div_u64(off, cxt->info.kmsg_size);
 89	while (zonecnt > 0) {
 90		dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum);
 91		clear_bit(zonenum, cxt->usedmap);
 92		zonenum++;
 93		zonecnt--;
 94	}
 95}
 96
 97static inline int mtdpstore_is_used(struct mtdpstore_context *cxt, loff_t off)
 98{
 99	u64 zonenum = div_u64(off, cxt->info.kmsg_size);
100	u64 blknum = div_u64(off, cxt->mtd->erasesize);
101
102	if (test_bit(blknum, cxt->badmap))
103		return true;
104	return test_bit(zonenum, cxt->usedmap);
105}
106
107static int mtdpstore_block_is_used(struct mtdpstore_context *cxt,
108		loff_t off)
109{
110	struct mtd_info *mtd = cxt->mtd;
111	u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;
112	u64 zonenum;
113
114	off = ALIGN_DOWN(off, mtd->erasesize);
115	zonenum = div_u64(off, cxt->info.kmsg_size);
116	while (zonecnt > 0) {
117		if (test_bit(zonenum, cxt->usedmap))
118			return true;
119		zonenum++;
120		zonecnt--;
121	}
122	return false;
123}
124
125static int mtdpstore_is_empty(struct mtdpstore_context *cxt, char *buf,
126		size_t size)
127{
128	struct mtd_info *mtd = cxt->mtd;
129	size_t sz;
130	int i;
131
132	sz = min_t(uint32_t, size, mtd->writesize / 4);
133	for (i = 0; i < sz; i++) {
134		if (buf[i] != (char)0xFF)
135			return false;
136	}
137	return true;
138}
139
140static void mtdpstore_mark_removed(struct mtdpstore_context *cxt, loff_t off)
141{
142	struct mtd_info *mtd = cxt->mtd;
143	u64 zonenum = div_u64(off, cxt->info.kmsg_size);
144
145	dev_dbg(&mtd->dev, "mark zone %llu removed\n", zonenum);
146	set_bit(zonenum, cxt->rmmap);
147}
148
149static void mtdpstore_block_clear_removed(struct mtdpstore_context *cxt,
150		loff_t off)
151{
152	struct mtd_info *mtd = cxt->mtd;
153	u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;
154	u64 zonenum;
155
156	off = ALIGN_DOWN(off, mtd->erasesize);
157	zonenum = div_u64(off, cxt->info.kmsg_size);
158	while (zonecnt > 0) {
159		clear_bit(zonenum, cxt->rmmap);
160		zonenum++;
161		zonecnt--;
162	}
163}
164
165static int mtdpstore_block_is_removed(struct mtdpstore_context *cxt,
166		loff_t off)
167{
168	struct mtd_info *mtd = cxt->mtd;
169	u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;
170	u64 zonenum;
171
172	off = ALIGN_DOWN(off, mtd->erasesize);
173	zonenum = div_u64(off, cxt->info.kmsg_size);
174	while (zonecnt > 0) {
175		if (test_bit(zonenum, cxt->rmmap))
176			return true;
177		zonenum++;
178		zonecnt--;
179	}
180	return false;
181}
182
183static int mtdpstore_erase_do(struct mtdpstore_context *cxt, loff_t off)
184{
185	struct mtd_info *mtd = cxt->mtd;
186	struct erase_info erase;
187	int ret;
188
189	off = ALIGN_DOWN(off, cxt->mtd->erasesize);
190	dev_dbg(&mtd->dev, "try to erase off 0x%llx\n", off);
191	erase.len = cxt->mtd->erasesize;
192	erase.addr = off;
193	ret = mtd_erase(cxt->mtd, &erase);
194	if (!ret)
195		mtdpstore_block_clear_removed(cxt, off);
196	else
197		dev_err(&mtd->dev, "erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
198		       (unsigned long long)erase.addr,
199		       (unsigned long long)erase.len, cxt->info.device);
200	return ret;
201}
202
203/*
204 * called while removing file
205 *
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
208 * unregister.
209 */
210static ssize_t mtdpstore_erase(size_t size, loff_t off)
211{
212	struct mtdpstore_context *cxt = &oops_cxt;
213
214	if (mtdpstore_block_isbad(cxt, off))
215		return -EIO;
216
217	mtdpstore_mark_unused(cxt, off);
218
219	/* If the block still has valid data, mtdpstore do erase lazily */
220	if (likely(mtdpstore_block_is_used(cxt, off))) {
221		mtdpstore_mark_removed(cxt, off);
222		return 0;
223	}
224
225	/* all zones are unused, erase it */
226	return mtdpstore_erase_do(cxt, off);
227}
228
229/*
230 * What is security for mtdpstore?
231 * As there is no erase for panic case, we should ensure at least one zone
232 * is writable. Otherwise, panic write will fail.
233 * If zone is used, write operation will return -ENOMSG, which means that
234 * pstore/blk will try one by one until gets an empty zone. So, it is not
235 * needed to ensure the next zone is empty, but at least one.
236 */
237static int mtdpstore_security(struct mtdpstore_context *cxt, loff_t off)
238{
239	int ret = 0, i;
240	struct mtd_info *mtd = cxt->mtd;
241	u32 zonenum = (u32)div_u64(off, cxt->info.kmsg_size);
242	u32 zonecnt = (u32)div_u64(cxt->mtd->size, cxt->info.kmsg_size);
243	u32 blkcnt = (u32)div_u64(cxt->mtd->size, cxt->mtd->erasesize);
244	u32 erasesize = cxt->mtd->erasesize;
245
246	for (i = 0; i < zonecnt; i++) {
247		u32 num = (zonenum + i) % zonecnt;
248
249		/* found empty zone */
250		if (!test_bit(num, cxt->usedmap))
251			return 0;
252	}
253
254	/* If there is no any empty zone, we have no way but to do erase */
255	while (blkcnt--) {
256		div64_u64_rem(off + erasesize, cxt->mtd->size, (u64 *)&off);
257
258		if (mtdpstore_block_isbad(cxt, off))
259			continue;
260
261		ret = mtdpstore_erase_do(cxt, off);
262		if (!ret) {
263			mtdpstore_block_mark_unused(cxt, off);
264			break;
265		}
266	}
267
268	if (ret)
269		dev_err(&mtd->dev, "all blocks bad!\n");
270	dev_dbg(&mtd->dev, "end security\n");
271	return ret;
272}
273
274static ssize_t mtdpstore_write(const char *buf, size_t size, loff_t off)
275{
276	struct mtdpstore_context *cxt = &oops_cxt;
277	struct mtd_info *mtd = cxt->mtd;
278	size_t retlen;
279	int ret;
280
281	if (mtdpstore_block_isbad(cxt, off))
282		return -ENOMSG;
283
284	/* zone is used, please try next one */
285	if (mtdpstore_is_used(cxt, off))
286		return -ENOMSG;
287
288	dev_dbg(&mtd->dev, "try to write off 0x%llx size %zu\n", off, size);
289	ret = mtd_write(cxt->mtd, off, size, &retlen, (u_char *)buf);
290	if (ret < 0 || retlen != size) {
291		dev_err(&mtd->dev, "write failure at %lld (%zu of %zu written), err %d\n",
292				off, retlen, size, ret);
293		return -EIO;
294	}
295	mtdpstore_mark_used(cxt, off);
296
297	mtdpstore_security(cxt, off);
298	return retlen;
299}
300
301static inline bool mtdpstore_is_io_error(int ret)
302{
303	return ret < 0 && !mtd_is_bitflip(ret) && !mtd_is_eccerr(ret);
304}
305
306/*
307 * All zones will be read as pstore/blk will read zone one by one when do
308 * recover.
309 */
310static ssize_t mtdpstore_read(char *buf, size_t size, loff_t off)
311{
312	struct mtdpstore_context *cxt = &oops_cxt;
313	struct mtd_info *mtd = cxt->mtd;
314	size_t retlen, done;
315	int ret;
316
317	if (mtdpstore_block_isbad(cxt, off))
318		return -ENOMSG;
319
320	dev_dbg(&mtd->dev, "try to read off 0x%llx size %zu\n", off, size);
321	for (done = 0, retlen = 0; done < size; done += retlen) {
322		retlen = 0;
323
324		ret = mtd_read(cxt->mtd, off + done, size - done, &retlen,
325				(u_char *)buf + done);
326		if (mtdpstore_is_io_error(ret)) {
327			dev_err(&mtd->dev, "read failure at %lld (%zu of %zu read), err %d\n",
328					off + done, retlen, size - done, ret);
329			/* the zone may be broken, try next one */
330			return -ENOMSG;
331		}
332
333		/*
334		 * ECC error. The impact on log data is so small. Maybe we can
335		 * still read it and try to understand. So mtdpstore just hands
336		 * over what it gets and user can judge whether the data is
337		 * valid or not.
338		 */
339		if (mtd_is_eccerr(ret)) {
340			dev_err(&mtd->dev, "ecc error at %lld (%zu of %zu read), err %d\n",
341					off + done, retlen, size - done, ret);
342			/* driver may not set retlen when ecc error */
343			retlen = retlen == 0 ? size - done : retlen;
344		}
345	}
346
347	if (mtdpstore_is_empty(cxt, buf, size))
348		mtdpstore_mark_unused(cxt, off);
349	else
350		mtdpstore_mark_used(cxt, off);
351
352	mtdpstore_security(cxt, off);
353	return retlen;
354}
355
356static ssize_t mtdpstore_panic_write(const char *buf, size_t size, loff_t off)
357{
358	struct mtdpstore_context *cxt = &oops_cxt;
359	struct mtd_info *mtd = cxt->mtd;
360	size_t retlen;
361	int ret;
362
363	if (mtdpstore_panic_block_isbad(cxt, off))
364		return -ENOMSG;
365
366	/* zone is used, please try next one */
367	if (mtdpstore_is_used(cxt, off))
368		return -ENOMSG;
369
370	ret = mtd_panic_write(cxt->mtd, off, size, &retlen, (u_char *)buf);
371	if (ret < 0 || size != retlen) {
372		dev_err(&mtd->dev, "panic write failure at %lld (%zu of %zu read), err %d\n",
373				off, retlen, size, ret);
374		return -EIO;
375	}
376	mtdpstore_mark_used(cxt, off);
377
378	return retlen;
379}
380
381static void mtdpstore_notify_add(struct mtd_info *mtd)
382{
383	int ret;
384	struct mtdpstore_context *cxt = &oops_cxt;
385	struct pstore_blk_config *info = &cxt->info;
386	unsigned long longcnt;
387
388	if (!strcmp(mtd->name, info->device))
389		cxt->index = mtd->index;
390
391	if (mtd->index != cxt->index || cxt->index < 0)
392		return;
393
394	dev_dbg(&mtd->dev, "found matching MTD device %s\n", mtd->name);
395
396	if (mtd->size < info->kmsg_size * 2) {
397		dev_err(&mtd->dev, "MTD partition %d not big enough\n",
398				mtd->index);
399		return;
400	}
401	/*
402	 * kmsg_size must be aligned to 4096 Bytes, which is limited by
403	 * psblk. The default value of kmsg_size is 64KB. If kmsg_size
404	 * is larger than erasesize, some errors will occur since mtdpstore
405	 * is designed on it.
406	 */
407	if (mtd->erasesize < info->kmsg_size) {
408		dev_err(&mtd->dev, "eraseblock size of MTD partition %d too small\n",
409				mtd->index);
410		return;
411	}
412	if (unlikely(info->kmsg_size % mtd->writesize)) {
413		dev_err(&mtd->dev, "record size %lu KB must align to write size %d KB\n",
414				info->kmsg_size / 1024,
415				mtd->writesize / 1024);
416		return;
417	}
418
419	longcnt = BITS_TO_LONGS(div_u64(mtd->size, info->kmsg_size));
420	cxt->rmmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);
421	cxt->usedmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);
422
423	longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize));
424	cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);
425
426	/* just support dmesg right now */
427	cxt->dev.flags = PSTORE_FLAGS_DMESG;
428	cxt->dev.zone.read = mtdpstore_read;
429	cxt->dev.zone.write = mtdpstore_write;
430	cxt->dev.zone.erase = mtdpstore_erase;
431	cxt->dev.zone.panic_write = mtdpstore_panic_write;
432	cxt->dev.zone.total_size = mtd->size;
433
434	ret = register_pstore_device(&cxt->dev);
435	if (ret) {
436		dev_err(&mtd->dev, "mtd%d register to psblk failed\n",
437				mtd->index);
438		return;
439	}
440	cxt->mtd = mtd;
441	dev_info(&mtd->dev, "Attached to MTD device %d\n", mtd->index);
442}
443
444static int mtdpstore_flush_removed_do(struct mtdpstore_context *cxt,
445		loff_t off, size_t size)
446{
447	struct mtd_info *mtd = cxt->mtd;
448	u_char *buf;
449	int ret;
450	size_t retlen;
451	struct erase_info erase;
452
453	buf = kmalloc(mtd->erasesize, GFP_KERNEL);
454	if (!buf)
455		return -ENOMEM;
456
457	/* 1st. read to cache */
458	ret = mtd_read(mtd, off, mtd->erasesize, &retlen, buf);
459	if (mtdpstore_is_io_error(ret))
460		goto free;
461
462	/* 2nd. erase block */
463	erase.len = mtd->erasesize;
464	erase.addr = off;
465	ret = mtd_erase(mtd, &erase);
466	if (ret)
467		goto free;
468
469	/* 3rd. write back */
470	while (size) {
471		unsigned int zonesize = cxt->info.kmsg_size;
472
473		/* there is valid data on block, write back */
474		if (mtdpstore_is_used(cxt, off)) {
475			ret = mtd_write(mtd, off, zonesize, &retlen, buf);
476			if (ret)
477				dev_err(&mtd->dev, "write failure at %lld (%zu of %u written), err %d\n",
478						off, retlen, zonesize, ret);
479		}
480
481		off += zonesize;
482		size -= min_t(unsigned int, zonesize, size);
483	}
484
485free:
486	kfree(buf);
487	return ret;
488}
489
490/*
491 * What does mtdpstore_flush_removed() do?
492 * When user remove any log file on pstore filesystem, mtdpstore should do
493 * something to ensure log file removed. If the whole block is no longer used,
494 * it's nice to erase the block. However if the block still contains valid log,
495 * what mtdpstore can do is to erase and write the valid log back.
496 */
497static int mtdpstore_flush_removed(struct mtdpstore_context *cxt)
498{
499	struct mtd_info *mtd = cxt->mtd;
500	int ret;
501	loff_t off;
502	u32 blkcnt = (u32)div_u64(mtd->size, mtd->erasesize);
503
504	for (off = 0; blkcnt > 0; blkcnt--, off += mtd->erasesize) {
505		ret = mtdpstore_block_isbad(cxt, off);
506		if (ret)
507			continue;
508
509		ret = mtdpstore_block_is_removed(cxt, off);
510		if (!ret)
511			continue;
512
513		ret = mtdpstore_flush_removed_do(cxt, off, mtd->erasesize);
514		if (ret)
515			return ret;
516	}
517	return 0;
518}
519
520static void mtdpstore_notify_remove(struct mtd_info *mtd)
521{
522	struct mtdpstore_context *cxt = &oops_cxt;
523
524	if (mtd->index != cxt->index || cxt->index < 0)
525		return;
526
527	mtdpstore_flush_removed(cxt);
528
529	unregister_pstore_device(&cxt->dev);
530	kfree(cxt->badmap);
531	kfree(cxt->usedmap);
532	kfree(cxt->rmmap);
533	cxt->mtd = NULL;
534	cxt->index = -1;
535}
536
537static struct mtd_notifier mtdpstore_notifier = {
538	.add	= mtdpstore_notify_add,
539	.remove	= mtdpstore_notify_remove,
540};
541
542static int __init mtdpstore_init(void)
543{
544	int ret;
545	struct mtdpstore_context *cxt = &oops_cxt;
546	struct pstore_blk_config *info = &cxt->info;
547
548	ret = pstore_blk_get_config(info);
549	if (unlikely(ret))
550		return ret;
551
552	if (strlen(info->device) == 0) {
553		pr_err("mtd device must be supplied (device name is empty)\n");
554		return -EINVAL;
555	}
556	if (!info->kmsg_size) {
557		pr_err("no backend enabled (kmsg_size is 0)\n");
558		return -EINVAL;
559	}
560
561	/* Setup the MTD device to use */
562	ret = kstrtoint((char *)info->device, 0, &cxt->index);
563	if (ret)
564		cxt->index = -1;
565
566	register_mtd_user(&mtdpstore_notifier);
567	return 0;
568}
569module_init(mtdpstore_init);
570
571static void __exit mtdpstore_exit(void)
572{
573	unregister_mtd_user(&mtdpstore_notifier);
574}
575module_exit(mtdpstore_exit);
576
577MODULE_LICENSE("GPL");
578MODULE_AUTHOR("WeiXiong Liao <liaoweixiong@allwinnertech.com>");
579MODULE_DESCRIPTION("MTD backend for pstore/blk");