Date: Thu, 8 Sep 2016 21:20:01 +0000 (UTC) From: "Conrad E. Meyer" <cem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r305627 - in head: . share/man/man3 sys/sys Message-ID: <201609082120.u88LK13f028849@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); \
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201609082120.u88LK13f028849>