Author: cem
Date: Thu Sep  8 21:20:01 2016
New Revision: 305627
URL: https://svnweb.freebsd.org/changeset/base/305627

Log:
  queue(3): Enhance queue debugging macros
  
  Split the QUEUE_MACRO_DEBUG into QUEUE_MACRO_DEBUG_TRACE and
  QUEUE_MACRO_DEBUG_TRASH.
  
  Add the debug macrso QMD_IS_TRASHED() and QMD_SLIST_CHECK_PREVPTR().
  
  Document these in queue.3.
  
  Reviewed by:  emaste
  Sponsored by: Dell EMC Isilon
  Differential Revision:        https://reviews.freebsd.org/D3984

Modified:
  head/UPDATING
  head/share/man/man3/Makefile
  head/share/man/man3/queue.3
  head/sys/sys/queue.h

Modified: head/UPDATING
==============================================================================
--- head/UPDATING       Thu Sep  8 20:01:26 2016        (r305626)
+++ head/UPDATING       Thu Sep  8 21:20:01 2016        (r305627)
@@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12
        disable the most expensive debugging functionality run
        "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20160908:
+       The queue(3) debugging macro, QUEUE_MACRO_DEBUG, has been split into
+       two separate components, QUEUE_MACRO_DEBUG_TRACE and
+       QUEUE_MACRO_DEBUG_TRASH.  Define both for the original
+       QUEUE_MACRO_DEBUG behavior.
+
 20160824:
        r304787 changed some ioctl interfaces between the iSCSI userspace
        programs and the kernel.  ctladm, ctld, iscsictl, and iscsid must be

Modified: head/share/man/man3/Makefile
==============================================================================
--- head/share/man/man3/Makefile        Thu Sep  8 20:01:26 2016        
(r305626)
+++ head/share/man/man3/Makefile        Thu Sep  8 21:20:01 2016        
(r305627)
@@ -106,6 +106,7 @@ MLINKS+=    queue.3 LIST_CLASS_ENTRY.3 \
                queue.3 SLIST_REMOVE.3 \
                queue.3 SLIST_REMOVE_AFTER.3 \
                queue.3 SLIST_REMOVE_HEAD.3 \
+               queue.3 SLIST_REMOVE_PREVPTR.3 \
                queue.3 SLIST_SWAP.3 \
                queue.3 STAILQ_CLASS_ENTRY.3 \
                queue.3 STAILQ_CLASS_HEAD.3 \

Modified: head/share/man/man3/queue.3
==============================================================================
--- head/share/man/man3/queue.3 Thu Sep  8 20:01:26 2016        (r305626)
+++ head/share/man/man3/queue.3 Thu Sep  8 21:20:01 2016        (r305627)
@@ -28,7 +28,7 @@
 .\"    @(#)queue.3     8.2 (Berkeley) 1/24/94
 .\" $FreeBSD$
 .\"
-.Dd August 15, 2016
+.Dd September 8, 2016
 .Dt QUEUE 3
 .Os
 .Sh NAME
@@ -1284,6 +1284,50 @@ while (n1 != NULL) {
 }
 TAILQ_INIT(&head);
 .Ed
+.Sh DIAGNOSTICS
+When debugging
+.Nm queue(3) ,
+it can be useful to trace queue changes.
+To enable tracing, define the macro
+.Va QUEUE_MACRO_DEBUG_TRACE
+at compile time.
+.Pp
+It can also be useful to trash pointers that have been unlinked from a queue,
+to detect use after removal.
+To enable pointer trashing, define the macro
+.Va QUEUE_MACRO_DEBUG_TRASH
+at compile time.
+The macro
+.Fn QMD_IS_TRASHED "void *ptr"
+returns true if
+.Fa ptr
+has been trashed by the
+.Va QUEUE_MACRO_DEBUG_TRASH
+option.
+.Pp
+In the kernel (with
+.Va INVARIANTS
+enabled), the
+.Fn SLIST_REMOVE_PREVPTR
+macro is available to aid debugging:
+.Bl -hang -offset indent
+.It Fn SLIST_REMOVE_PREVPTR "TYPE **prev" "TYPE *elm" "SLIST_ENTRY NAME"
+.Pp
+Removes
+.Fa elm ,
+which must directly follow the element whose
+.Va &SLIST_NEXT()
+is
+.Fa prev ,
+from the SLIST.
+This macro validates that
+.Fa elm
+follows
+.Fa prev
+in
+.Va INVARIANTS
+mode.
+.El
 .Sh SEE ALSO
 .Xr tree 3
 .Sh HISTORY

Modified: head/sys/sys/queue.h
==============================================================================
--- head/sys/sys/queue.h        Thu Sep  8 20:01:26 2016        (r305626)
+++ head/sys/sys/queue.h        Thu Sep  8 21:20:01 2016        (r305627)
@@ -113,6 +113,12 @@
  *
  */
 #ifdef QUEUE_MACRO_DEBUG
+#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
+#define        QUEUE_MACRO_DEBUG_TRACE
+#define        QUEUE_MACRO_DEBUG_TRASH
+#endif
+
+#ifdef QUEUE_MACRO_DEBUG_TRACE
 /* Store the last 2 places the queue element or head was altered */
 struct qm_trace {
        unsigned long    lastline;
@@ -123,8 +129,6 @@ struct qm_trace {
 
 #define        TRACEBUF        struct qm_trace trace;
 #define        TRACEBUF_INITIALIZER    { __LINE__, 0, __FILE__, NULL } ,
-#define        TRASHIT(x)      do {(x) = (void *)-1;} while (0)
-#define        QMD_SAVELINK(name, link)        void **name = (void *)&(link)
 
 #define        QMD_TRACE_HEAD(head) do {                                       
\
        (head)->trace.prevline = (head)->trace.lastline;                \
@@ -140,14 +144,26 @@ struct qm_trace {
        (elem)->trace.lastfile = __FILE__;                              \
 } while (0)
 
-#else
+#else  /* !QUEUE_MACRO_DEBUG_TRACE */
 #define        QMD_TRACE_ELEM(elem)
 #define        QMD_TRACE_HEAD(head)
-#define        QMD_SAVELINK(name, link)
 #define        TRACEBUF
 #define        TRACEBUF_INITIALIZER
+#endif /* QUEUE_MACRO_DEBUG_TRACE */
+
+#ifdef QUEUE_MACRO_DEBUG_TRASH
+#define        TRASHIT(x)              do {(x) = (void *)-1;} while (0)
+#define        QMD_IS_TRASHED(x)       ((x) == (void *)(intptr_t)-1)
+#else  /* !QUEUE_MACRO_DEBUG_TRASH */
 #define        TRASHIT(x)
-#endif /* QUEUE_MACRO_DEBUG */
+#define        QMD_IS_TRASHED(x)       0
+#endif /* QUEUE_MACRO_DEBUG_TRASH */
+
+#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH)
+#define        QMD_SAVELINK(name, link)        void **name = (void *)&(link)
+#else  /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */
+#define        QMD_SAVELINK(name, link)
+#endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */
 
 #ifdef __cplusplus
 /*
@@ -187,6 +203,16 @@ struct {                                                   
        \
 /*
  * Singly-linked List functions.
  */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define        QMD_SLIST_CHECK_PREVPTR(prevp, elm) do {                        
\
+       if (*(prevp) != (elm))                                          \
+               panic("Bad prevptr *(%p) == %p != %p",                  \
+                   (prevp), *(prevp), (elm));                          \
+} while (0)
+#else
+#define        QMD_SLIST_CHECK_PREVPTR(prevp, elm)
+#endif
+
 #define SLIST_CONCAT(head1, head2, type, field) do {                   \
        QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1);                \
        if (curelm == NULL) {                                           \
@@ -268,6 +294,12 @@ struct {                                                   
        \
        SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);   \
 } while (0)
 
+#define        SLIST_REMOVE_PREVPTR(prevp, elm, field) do {                    
\
+       QMD_SLIST_CHECK_PREVPTR(prevp, elm);                            \
+       *(prevp) = SLIST_NEXT(elm, field);                              \
+       TRASHIT((elm)->field.sle_next);                                 \
+} while (0)
+
 #define SLIST_SWAP(head1, head2, type) do {                            \
        QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1);            \
        SLIST_FIRST(head1) = SLIST_FIRST(head2);                        \
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to