2424#include <linux/export.h>
2525#include <linux/init.h>
2626#include <linux/fs.h>
27+ #include <linux/math.h>
2728#include <linux/minmax.h>
2829#include <linux/debugfs.h>
2930
@@ -354,7 +355,10 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
354355 for (i = 0 ; i < in -> nr_areas ; i ++ ) {
355356 for (j = 0 ; j < in -> pages_per_area ; j ++ )
356357 memcpy (rc -> areas [i ][j ], in -> areas [i ][j ], PAGE_SIZE );
358+ rc -> active_pages [i ] = in -> active_pages [i ];
359+ rc -> active_entries [i ] = in -> active_entries [i ];
357360 }
361+ rc -> active_area = in -> active_area ;
358362out :
359363 spin_unlock_irqrestore (& in -> lock , flags );
360364 return rc ;
@@ -461,6 +465,84 @@ static inline bool debug_next_entry(file_private_info_t *p_info)
461465 return true;
462466}
463467
468+ /**
469+ * debug_to_act_entry - Go to the currently active entry
470+ * @p_info: Private info that is manipulated
471+ *
472+ * Sets the current position in @p_info to the currently active
473+ * entry of @p_info->debug_info_snap
474+ */
475+ static void debug_to_act_entry (file_private_info_t * p_info )
476+ {
477+ debug_info_t * snap_id ;
478+
479+ snap_id = p_info -> debug_info_snap ;
480+ p_info -> act_area = snap_id -> active_area ;
481+ p_info -> act_page = snap_id -> active_pages [snap_id -> active_area ];
482+ p_info -> act_entry = snap_id -> active_entries [snap_id -> active_area ];
483+ }
484+
485+ /**
486+ * debug_prev_entry - Go to the previous entry
487+ * @p_info: Private info that is manipulated
488+ *
489+ * Sets the current position in @p_info to the previous entry. If no previous entry
490+ * exists the current position is set left as DEBUG_PROLOG_ENTRY and the return value
491+ * indicates that no previous entries exist.
492+ *
493+ * Return: True if there are more previous entries, false otherwise
494+ */
495+
496+ static inline bool debug_prev_entry (file_private_info_t * p_info )
497+ {
498+ debug_info_t * id ;
499+
500+ id = p_info -> debug_info_snap ;
501+ if (p_info -> act_entry == DEBUG_PROLOG_ENTRY )
502+ debug_to_act_entry (p_info );
503+ if (!id -> areas )
504+ return false;
505+ p_info -> act_entry -= id -> entry_size ;
506+ /* switch to prev page, if we reached the beginning of the page */
507+ if (p_info -> act_entry < 0 ) {
508+ /* end of previous page */
509+ p_info -> act_entry = rounddown (PAGE_SIZE , id -> entry_size ) - id -> entry_size ;
510+ p_info -> act_page -- ;
511+ if (p_info -> act_page < 0 ) {
512+ /* previous area */
513+ p_info -> act_area -- ;
514+ p_info -> act_page = id -> pages_per_area - 1 ;
515+ }
516+ if (p_info -> act_area < 0 )
517+ p_info -> act_area = (id -> nr_areas - 1 ) % id -> nr_areas ;
518+ }
519+ /* check full circle */
520+ if (id -> active_area == p_info -> act_area &&
521+ id -> active_pages [id -> active_area ] == p_info -> act_page &&
522+ id -> active_entries [id -> active_area ] == p_info -> act_entry )
523+ return false;
524+ return true;
525+ }
526+
527+ /**
528+ * debug_move_entry - Go to next entry in either the forward or backward direction
529+ * @p_info: Private info that is manipulated
530+ * @reverse: If true go to the next entry in reverse i.e. previous
531+ *
532+ * Sets the current position in @p_info to the next (@reverse == false) or
533+ * previous (@reverse == true) entry.
534+ *
535+ * Return: True if there are further entries in that direction,
536+ * false otherwise.
537+ */
538+ static bool debug_move_entry (file_private_info_t * p_info , bool reverse )
539+ {
540+ if (reverse )
541+ return debug_prev_entry (p_info );
542+ else
543+ return debug_next_entry (p_info );
544+ }
545+
464546/*
465547 * debug_output:
466548 * - called for user read()
@@ -638,6 +720,7 @@ static int debug_close(struct inode *inode, struct file *file)
638720 * @view: View with which to dump the debug information
639721 * @buf: Buffer the textual debug data representation is written to
640722 * @buf_size: Size of the buffer, including the trailing '\0' byte
723+ * @reverse: Go backwards from the last written entry
641724 *
642725 * This function may be used whenever a textual representation of the debug
643726 * information is required without using an s390dbf file.
@@ -650,7 +733,7 @@ static int debug_close(struct inode *inode, struct file *file)
650733 * On failure an error code less than 0 is returned.
651734 */
652735ssize_t debug_dump (debug_info_t * id , struct debug_view * view ,
653- char * buf , size_t buf_size )
736+ char * buf , size_t buf_size , bool reverse )
654737{
655738 file_private_info_t * p_info ;
656739 size_t size , offset = 0 ;
@@ -672,7 +755,7 @@ ssize_t debug_dump(debug_info_t *id, struct debug_view *view,
672755 offset += size ;
673756 if (offset >= buf_size )
674757 break ;
675- } while (debug_next_entry (p_info ));
758+ } while (debug_move_entry (p_info , reverse ));
676759 debug_file_private_free (p_info );
677760 buf [offset ] = '\0' ;
678761
0 commit comments