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+ */
390393static 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
496620out_remove :
0 commit comments