|
@@ -22,6 +22,7 @@
|
|
|
#include <linux/debugfs.h>
|
|
|
#include <linux/uaccess.h>
|
|
|
#include <linux/module.h>
|
|
|
+#include <linux/seq_file.h>
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -386,7 +387,9 @@ out:
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-/* File operations for all UBI debugfs files */
|
|
|
+/* File operations for all UBI debugfs files except
|
|
|
+ * detailed_erase_block_info
|
|
|
+ */
|
|
|
static const struct file_operations dfs_fops = {
|
|
|
.read = dfs_file_read,
|
|
|
.write = dfs_file_write,
|
|
@@ -395,6 +398,121 @@ static const struct file_operations dfs_fops = {
|
|
|
.owner = THIS_MODULE,
|
|
|
};
|
|
|
|
|
|
+/* As long as the position is less then that total number of erase blocks,
|
|
|
+ * we still have more to print.
|
|
|
+ */
|
|
|
+static void *eraseblk_count_seq_start(struct seq_file *s, loff_t *pos)
|
|
|
+{
|
|
|
+ struct ubi_device *ubi = s->private;
|
|
|
+
|
|
|
+ if (*pos == 0)
|
|
|
+ return SEQ_START_TOKEN;
|
|
|
+
|
|
|
+ if (*pos < ubi->peb_count)
|
|
|
+ return pos;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Since we are using the position as the iterator, we just need to check if we
|
|
|
+ * are done and increment the position.
|
|
|
+ */
|
|
|
+static void *eraseblk_count_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
|
|
+{
|
|
|
+ struct ubi_device *ubi = s->private;
|
|
|
+
|
|
|
+ if (v == SEQ_START_TOKEN)
|
|
|
+ return pos;
|
|
|
+ (*pos)++;
|
|
|
+
|
|
|
+ if (*pos < ubi->peb_count)
|
|
|
+ return pos;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void eraseblk_count_seq_stop(struct seq_file *s, void *v)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static int eraseblk_count_seq_show(struct seq_file *s, void *iter)
|
|
|
+{
|
|
|
+ struct ubi_device *ubi = s->private;
|
|
|
+ struct ubi_wl_entry *wl;
|
|
|
+ int *block_number = iter;
|
|
|
+ int erase_count = -1;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* If this is the start, print a header */
|
|
|
+ if (iter == SEQ_START_TOKEN) {
|
|
|
+ seq_puts(s,
|
|
|
+ "physical_block_number\terase_count\tblock_status\tread_status\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = ubi_io_is_bad(ubi, *block_number);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ spin_lock(&ubi->wl_lock);
|
|
|
+
|
|
|
+ wl = ubi->lookuptbl[*block_number];
|
|
|
+ if (wl)
|
|
|
+ erase_count = wl->ec;
|
|
|
+
|
|
|
+ spin_unlock(&ubi->wl_lock);
|
|
|
+
|
|
|
+ if (erase_count < 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ seq_printf(s, "%-22d\t%-11d\n", *block_number, erase_count);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct seq_operations eraseblk_count_seq_ops = {
|
|
|
+ .start = eraseblk_count_seq_start,
|
|
|
+ .next = eraseblk_count_seq_next,
|
|
|
+ .stop = eraseblk_count_seq_stop,
|
|
|
+ .show = eraseblk_count_seq_show
|
|
|
+};
|
|
|
+
|
|
|
+static int eraseblk_count_open(struct inode *inode, struct file *f)
|
|
|
+{
|
|
|
+ struct seq_file *s;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = seq_open(f, &eraseblk_count_seq_ops);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ s = f->private_data;
|
|
|
+ s->private = ubi_get_device((unsigned long)inode->i_private);
|
|
|
+
|
|
|
+ if (!s->private)
|
|
|
+ return -ENODEV;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int eraseblk_count_release(struct inode *inode, struct file *f)
|
|
|
+{
|
|
|
+ struct seq_file *s = f->private_data;
|
|
|
+ struct ubi_device *ubi = s->private;
|
|
|
+
|
|
|
+ ubi_put_device(ubi);
|
|
|
+
|
|
|
+ return seq_release(inode, f);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations eraseblk_count_fops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = eraseblk_count_open,
|
|
|
+ .read = seq_read,
|
|
|
+ .llseek = seq_lseek,
|
|
|
+ .release = eraseblk_count_release,
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* ubi_debugfs_init_dev - initialize debugfs for an UBI device.
|
|
|
* @ubi: UBI device description object
|
|
@@ -491,6 +609,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
|
|
goto out_remove;
|
|
|
d->dfs_power_cut_max = dent;
|
|
|
|
|
|
+ fname = "detailed_erase_block_info";
|
|
|
+ dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
|
|
|
+ &eraseblk_count_fops);
|
|
|
+ if (IS_ERR_OR_NULL(dent))
|
|
|
+ goto out_remove;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
out_remove:
|