Skip to content

Commit 7bccd12

Browse files
Ben Sheltonrichardweinberger
authored andcommitted
ubi: Add debugfs file for tracking PEB state
Add a file under debugfs to allow easy access to the erase count for each physical erase block on an UBI device. This is useful when debugging data integrity issues with UBIFS on NAND flash devices. Signed-off-by: Ben Shelton <[email protected]> Signed-off-by: Zach Brown <[email protected]> v2: * If ubi_io_is_bad eraseblk_count_seq_show just returns the err. * if ubi->lookuptbl returns null, its no longer treated as an error instead info for that block is not printeded * Removed check for UBI_MAX_ERASECOUNTER since it is impossible to hit * Removed block state from print, if a block is printed then it is good and if it is not printed, then it is bad. v3: * Remove errant ! symbol from if statement checking if erase count is valid. Signed-off-by: Richard Weinberger <[email protected]>
1 parent 798868c commit 7bccd12

File tree

1 file changed

+125
-1
lines changed

1 file changed

+125
-1
lines changed

drivers/mtd/ubi/debug.c

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/debugfs.h>
2323
#include <linux/uaccess.h>
2424
#include <linux/module.h>
25+
#include <linux/seq_file.h>
2526

2627

2728
/**
@@ -386,7 +387,9 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
386387
return count;
387388
}
388389

389-
/* File operations for all UBI debugfs files */
390+
/* File operations for all UBI debugfs files except
391+
* detailed_erase_block_info
392+
*/
390393
static const struct file_operations dfs_fops = {
391394
.read = dfs_file_read,
392395
.write = dfs_file_write,
@@ -395,6 +398,121 @@ static const struct file_operations dfs_fops = {
395398
.owner = THIS_MODULE,
396399
};
397400

401+
/* As long as the position is less then that total number of erase blocks,
402+
* we still have more to print.
403+
*/
404+
static void *eraseblk_count_seq_start(struct seq_file *s, loff_t *pos)
405+
{
406+
struct ubi_device *ubi = s->private;
407+
408+
if (*pos == 0)
409+
return SEQ_START_TOKEN;
410+
411+
if (*pos < ubi->peb_count)
412+
return pos;
413+
414+
return NULL;
415+
}
416+
417+
/* Since we are using the position as the iterator, we just need to check if we
418+
* are done and increment the position.
419+
*/
420+
static void *eraseblk_count_seq_next(struct seq_file *s, void *v, loff_t *pos)
421+
{
422+
struct ubi_device *ubi = s->private;
423+
424+
if (v == SEQ_START_TOKEN)
425+
return pos;
426+
(*pos)++;
427+
428+
if (*pos < ubi->peb_count)
429+
return pos;
430+
431+
return NULL;
432+
}
433+
434+
static void eraseblk_count_seq_stop(struct seq_file *s, void *v)
435+
{
436+
}
437+
438+
static int eraseblk_count_seq_show(struct seq_file *s, void *iter)
439+
{
440+
struct ubi_device *ubi = s->private;
441+
struct ubi_wl_entry *wl;
442+
int *block_number = iter;
443+
int erase_count = -1;
444+
int err;
445+
446+
/* If this is the start, print a header */
447+
if (iter == SEQ_START_TOKEN) {
448+
seq_puts(s,
449+
"physical_block_number\terase_count\tblock_status\tread_status\n");
450+
return 0;
451+
}
452+
453+
err = ubi_io_is_bad(ubi, *block_number);
454+
if (err)
455+
return err;
456+
457+
spin_lock(&ubi->wl_lock);
458+
459+
wl = ubi->lookuptbl[*block_number];
460+
if (wl)
461+
erase_count = wl->ec;
462+
463+
spin_unlock(&ubi->wl_lock);
464+
465+
if (erase_count < 0)
466+
return 0;
467+
468+
seq_printf(s, "%-22d\t%-11d\n", *block_number, erase_count);
469+
470+
return 0;
471+
}
472+
473+
static const struct seq_operations eraseblk_count_seq_ops = {
474+
.start = eraseblk_count_seq_start,
475+
.next = eraseblk_count_seq_next,
476+
.stop = eraseblk_count_seq_stop,
477+
.show = eraseblk_count_seq_show
478+
};
479+
480+
static int eraseblk_count_open(struct inode *inode, struct file *f)
481+
{
482+
struct seq_file *s;
483+
int err;
484+
485+
err = seq_open(f, &eraseblk_count_seq_ops);
486+
if (err)
487+
return err;
488+
489+
s = f->private_data;
490+
s->private = ubi_get_device((unsigned long)inode->i_private);
491+
492+
if (!s->private)
493+
return -ENODEV;
494+
else
495+
return 0;
496+
}
497+
498+
static int eraseblk_count_release(struct inode *inode, struct file *f)
499+
{
500+
struct seq_file *s = f->private_data;
501+
struct ubi_device *ubi = s->private;
502+
503+
ubi_put_device(ubi);
504+
505+
return seq_release(inode, f);
506+
}
507+
508+
static const struct file_operations eraseblk_count_fops = {
509+
.owner = THIS_MODULE,
510+
.open = eraseblk_count_open,
511+
.read = seq_read,
512+
.llseek = seq_lseek,
513+
.release = eraseblk_count_release,
514+
};
515+
398516
/**
399517
* ubi_debugfs_init_dev - initialize debugfs for an UBI device.
400518
* @ubi: UBI device description object
@@ -491,6 +609,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
491609
goto out_remove;
492610
d->dfs_power_cut_max = dent;
493611

612+
fname = "detailed_erase_block_info";
613+
dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
614+
&eraseblk_count_fops);
615+
if (IS_ERR_OR_NULL(dent))
616+
goto out_remove;
617+
494618
return 0;
495619

496620
out_remove:

0 commit comments

Comments
 (0)