hammer2 - Add HAMMER2_IO_DEBUG
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 8 Dec 2018 02:05:16 +0000 (18:05 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 8 Dec 2018 02:05:16 +0000 (18:05 -0800)
* Add HAMMER2_IO_DEBUG (default disabled).  This tracks callers
  that use hammer2_io's.  This eats a huge amount of (up to ~20GB)
  of kernel memory.

sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_io.c

index 97a2e32..fb12a40 100644 (file)
@@ -280,6 +280,18 @@ RB_HEAD(hammer2_io_tree, hammer2_io);
  * fixed-sized filesystem buffers frontend by variable-sized hammer2_chain
  * structures.
  */
+/* #define HAMMER2_IO_DEBUG */
+
+#ifdef HAMMER2_IO_DEBUG
+#define HAMMER2_IO_DEBUG_ARGS  , const char *file, int line
+#define HAMMER2_IO_DEBUG_CALL  , file, line
+#define HAMMER2_IO_DEBUG_COUNT 2048
+#define HAMMER2_IO_DEBUG_MASK  (HAMMER2_IO_DEBUG_COUNT - 1)
+#else
+#define HAMMER2_IO_DEBUG_ARGS
+#define HAMMER2_IO_DEBUG_CALL
+#endif
+
 struct hammer2_io {
        RB_ENTRY(hammer2_io) rbnode;    /* indexed by device offset */
        struct hammer2_dev *hmp;
@@ -291,9 +303,19 @@ struct hammer2_io {
        int             btype;          /* approximate BREF_TYPE_* */
        int             ticks;
        int             error;
+#ifdef HAMMER2_IO_DEBUG
+       int             debug_index;
+#else
        int             unused01;
+#endif
        uint64_t        dedup_valid;    /* valid for dedup operation */
        uint64_t        dedup_alloc;    /* allocated / de-dupable */
+#ifdef HAMMER2_IO_DEBUG
+       const char      *debug_file[HAMMER2_IO_DEBUG_COUNT];
+       void            *debug_td[HAMMER2_IO_DEBUG_COUNT];
+       int             debug_line[HAMMER2_IO_DEBUG_COUNT];
+       uint64_t        debug_refs[HAMMER2_IO_DEBUG_COUNT];
+#endif
 };
 
 typedef struct hammer2_io hammer2_io_t;
@@ -1672,13 +1694,10 @@ int hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data,
 /*
  * hammer2_io.c
  */
-void hammer2_io_putblk(hammer2_io_t **diop);
 void hammer2_io_inval(hammer2_io_t *dio, hammer2_off_t data_off, u_int bytes);
 void hammer2_io_cleanup(hammer2_dev_t *hmp, struct hammer2_io_tree *tree);
 char *hammer2_io_data(hammer2_io_t *dio, off_t lbase);
 void hammer2_io_bkvasync(hammer2_io_t *dio);
-hammer2_io_t *hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase,
-                               int lsize, int op);
 void hammer2_io_dedup_set(hammer2_dev_t *hmp, hammer2_blockref_t *bref);
 void hammer2_io_dedup_delete(hammer2_dev_t *hmp, uint8_t btype,
                                hammer2_off_t data_off, u_int bytes);
@@ -1689,16 +1708,76 @@ int hammer2_io_new(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
                                hammer2_io_t **diop);
 int hammer2_io_newnz(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
                                hammer2_io_t **diop);
-int hammer2_io_bread(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
-                               hammer2_io_t **diop);
-hammer2_io_t *hammer2_io_getquick(hammer2_dev_t *hmp, off_t lbase, int lsize);
-void hammer2_io_bawrite(hammer2_io_t **diop);
-void hammer2_io_bdwrite(hammer2_io_t **diop);
-int hammer2_io_bwrite(hammer2_io_t **diop);
+int _hammer2_io_bread(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
+                               hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
 void hammer2_io_setdirty(hammer2_io_t *dio);
-void hammer2_io_brelse(hammer2_io_t **diop);
-void hammer2_io_bqrelse(hammer2_io_t **diop);
-void hammer2_io_ref(hammer2_io_t *dio);
+
+hammer2_io_t *_hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase,
+                               int lsize, int op HAMMER2_IO_DEBUG_ARGS);
+hammer2_io_t *_hammer2_io_getquick(hammer2_dev_t *hmp, off_t lbase,
+                               int lsize HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_putblk(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+int _hammer2_io_bwrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_bawrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_bdwrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_brelse(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_bqrelse(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS);
+void _hammer2_io_ref(hammer2_io_t *dio HAMMER2_IO_DEBUG_ARGS);
+
+#ifndef HAMMER2_IO_DEBUG
+
+#define hammer2_io_getblk(hmp, btype, lbase, lsize, op)                        \
+       _hammer2_io_getblk((hmp), (btype), (lbase), (lsize), (op))
+#define hammer2_io_getquick(hmp, lbase, lsize)                         \
+       _hammer2_io_getquick((hmp), (lbase), (lsize))
+#define hammer2_io_putblk(diop)                                                \
+       _hammer2_io_putblk(diop)
+#define hammer2_io_bwrite(diop)                                                \
+       _hammer2_io_bwrite((diop))
+#define hammer2_io_bawrite(diop)                                       \
+       _hammer2_io_bawrite((diop))
+#define hammer2_io_bdwrite(diop)                                       \
+       _hammer2_io_bdwrite((diop))
+#define hammer2_io_brelse(diop)                                                \
+       _hammer2_io_brelse((diop))
+#define hammer2_io_bqrelse(diop)                                       \
+       _hammer2_io_bqrelse((diop))
+#define hammer2_io_ref(dio)                                            \
+       _hammer2_io_ref((dio))
+
+#define hammer2_io_bread(hmp, btype, lbase, lsize, diop)               \
+       _hammer2_io_bread((hmp), (btype), (lbase), (lsize), (diop))
+
+#else
+
+#define hammer2_io_getblk(hmp, btype, lbase, lsize, op)                        \
+       _hammer2_io_getblk((hmp), (btype), (lbase), (lsize), (op),      \
+       __FILE__, __LINE__)
+
+#define hammer2_io_getquick(hmp, lbase, lsize)                         \
+       _hammer2_io_getquick((hmp), (lbase), (lsize), __FILE__, __LINE__)
+
+#define hammer2_io_putblk(diop)                                                \
+       _hammer2_io_putblk(diop, __FILE__, __LINE__)
+
+#define hammer2_io_bwrite(diop)                                                \
+       _hammer2_io_bwrite((diop), __FILE__, __LINE__)
+#define hammer2_io_bawrite(diop)                                       \
+       _hammer2_io_bawrite((diop), __FILE__, __LINE__)
+#define hammer2_io_bdwrite(diop)                                       \
+       _hammer2_io_bdwrite((diop), __FILE__, __LINE__)
+#define hammer2_io_brelse(diop)                                                \
+       _hammer2_io_brelse((diop), __FILE__, __LINE__)
+#define hammer2_io_bqrelse(diop)                                       \
+       _hammer2_io_bqrelse((diop), __FILE__, __LINE__)
+#define hammer2_io_ref(dio)                                            \
+       _hammer2_io_ref((dio), __FILE__, __LINE__)
+
+#define hammer2_io_bread(hmp, btype, lbase, lsize, diop)               \
+       _hammer2_io_bread((hmp), (btype), (lbase), (lsize), (diop),     \
+                         __FILE__, __LINE__)
+
+#endif
 
 /*
  * hammer2_thread.c
@@ -1921,9 +2000,12 @@ void hammer2_dedup_clear(hammer2_dev_t *hmp);
 /*
  * More complex inlines
  */
+
+#define hammer2_xop_gdata(xop) _hammer2_xop_gdata((xop), __FILE__, __LINE__)
+
 static __inline
 const hammer2_media_data_t *
-hammer2_xop_gdata(hammer2_xop_head_t *xop)
+_hammer2_xop_gdata(hammer2_xop_head_t *xop, const char *file, int line)
 {
        hammer2_chain_t *focus;
        const void *data;
@@ -1932,7 +2014,7 @@ hammer2_xop_gdata(hammer2_xop_head_t *xop)
        if (focus->dio) {
                lockmgr(&focus->diolk, LK_SHARED);
                if ((xop->focus_dio = focus->dio) != NULL) {
-                       hammer2_io_ref(xop->focus_dio);
+                       _hammer2_io_ref(xop->focus_dio HAMMER2_IO_DEBUG_CALL);
                        hammer2_io_bkvasync(xop->focus_dio);
                }
                data = focus->data;
@@ -1944,12 +2026,14 @@ hammer2_xop_gdata(hammer2_xop_head_t *xop)
        return data;
 }
 
+#define hammer2_xop_pdata(xop) _hammer2_xop_pdata((xop), __FILE__, __LINE__)
+
 static __inline
 void
-hammer2_xop_pdata(hammer2_xop_head_t *xop)
+_hammer2_xop_pdata(hammer2_xop_head_t *xop, const char *file, int line)
 {
        if (xop->focus_dio)
-               hammer2_io_putblk(&xop->focus_dio);
+               _hammer2_io_putblk(&xop->focus_dio HAMMER2_IO_DEBUG_CALL);
 }
 
 #endif /* !_KERNEL */
index d1ea75f..f1a4554 100644 (file)
@@ -95,6 +95,27 @@ hammer2_io_mask(hammer2_io_t *dio, hammer2_off_t off, u_int bytes)
 }
 #endif
 
+#ifdef HAMMER2_IO_DEBUG
+
+static __inline void
+DIO_RECORD(hammer2_io_t *dio HAMMER2_IO_DEBUG_ARGS)
+{
+       int i;
+
+       i = atomic_fetchadd_int(&dio->debug_index, 1) & HAMMER2_IO_DEBUG_MASK;
+
+       dio->debug_file[i] = file;
+       dio->debug_line[i] = line;
+       dio->debug_refs[i] = dio->refs;
+       dio->debug_td[i] = curthread;
+}
+
+#else
+
+#define DIO_RECORD(dio)
+
+#endif
+
 /*
  * Returns the DIO corresponding to the data|radix, creating it if necessary.
  *
@@ -182,7 +203,8 @@ hammer2_io_alloc(hammer2_dev_t *hmp, hammer2_key_t data_off, uint8_t btype,
  * a buffer.  If set the buffer already exists and is good to go.
  */
 hammer2_io_t *
-hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize, int op)
+_hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase,
+                  int lsize, int op HAMMER2_IO_DEBUG_ARGS)
 {
        hammer2_io_t *dio;
        off_t peof;
@@ -231,6 +253,7 @@ hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize, int op)
                                /* nothing to do */
                                break;
                        }
+                       DIO_RECORD(dio HAMMER2_IO_DEBUG_CALL);
                        return (dio);
                }
 
@@ -353,6 +376,7 @@ hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize, int op)
                bkvasync(dio->bp);
                BUF_KERNPROC(dio->bp);
                dio->bp->b_flags &= ~B_AGE;
+               dio->bp->b_debug_info2 = dio;
        }
        dio->error = error;
 
@@ -374,6 +398,7 @@ hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize, int op)
        }
 
        /* XXX error handling */
+       DIO_RECORD(dio HAMMER2_IO_DEBUG_CALL);
 
        return dio;
 }
@@ -385,7 +410,7 @@ hammer2_io_getblk(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize, int op)
  * of dio->bp.  Then we clean up DIO_INPROG and DIO_WAITING.
  */
 void
-hammer2_io_putblk(hammer2_io_t **diop)
+_hammer2_io_putblk(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
        hammer2_dev_t *hmp;
        hammer2_io_t *dio;
@@ -399,6 +424,7 @@ hammer2_io_putblk(hammer2_io_t **diop)
        dio = *diop;
        *diop = NULL;
        hmp = dio->hmp;
+       DIO_RECORD(dio HAMMER2_IO_DEBUG_CALL);
 
        KKASSERT((dio->refs & HAMMER2_DIO_MASK) != 0);
 
@@ -653,41 +679,54 @@ hammer2_io_newnz(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
 }
 
 int
-hammer2_io_bread(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
-               hammer2_io_t **diop)
+_hammer2_io_bread(hammer2_dev_t *hmp, int btype, off_t lbase, int lsize,
+               hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
-       *diop = hammer2_io_getblk(hmp, btype, lbase, lsize, HAMMER2_DOP_READ);
+#ifdef HAMMER2_IO_DEBUG
+       hammer2_io_t *dio;
+#endif
+
+       *diop = _hammer2_io_getblk(hmp, btype, lbase, lsize,
+                                  HAMMER2_DOP_READ HAMMER2_IO_DEBUG_CALL);
+#ifdef HAMMER2_IO_DEBUG
+       if ((dio = *diop) != NULL) {
+               int i = (dio->debug_index - 1) & HAMMER2_IO_DEBUG_MASK;
+               dio->debug_data[i] = debug_data;
+       }
+#endif
        return ((*diop)->error);
 }
 
 hammer2_io_t *
-hammer2_io_getquick(hammer2_dev_t *hmp, off_t lbase, int lsize)
+_hammer2_io_getquick(hammer2_dev_t *hmp, off_t lbase,
+                    int lsize HAMMER2_IO_DEBUG_ARGS)
 {
        hammer2_io_t *dio;
 
-       dio = hammer2_io_getblk(hmp, 0, lbase, lsize, HAMMER2_DOP_READQ);
+       dio = _hammer2_io_getblk(hmp, 0, lbase, lsize,
+                                HAMMER2_DOP_READQ HAMMER2_IO_DEBUG_CALL);
        return dio;
 }
 
 void
-hammer2_io_bawrite(hammer2_io_t **diop)
+_hammer2_io_bawrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
        atomic_set_64(&(*diop)->refs, HAMMER2_DIO_DIRTY);
-       hammer2_io_putblk(diop);
+       _hammer2_io_putblk(diop HAMMER2_IO_DEBUG_CALL);
 }
 
 void
-hammer2_io_bdwrite(hammer2_io_t **diop)
+_hammer2_io_bdwrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
        atomic_set_64(&(*diop)->refs, HAMMER2_DIO_DIRTY);
-       hammer2_io_putblk(diop);
+       _hammer2_io_putblk(diop HAMMER2_IO_DEBUG_CALL);
 }
 
 int
-hammer2_io_bwrite(hammer2_io_t **diop)
+_hammer2_io_bwrite(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
        atomic_set_64(&(*diop)->refs, HAMMER2_DIO_DIRTY);
-       hammer2_io_putblk(diop);
+       _hammer2_io_putblk(diop HAMMER2_IO_DEBUG_CALL);
        return (0);     /* XXX */
 }
 
@@ -720,15 +759,15 @@ hammer2_io_inval(hammer2_io_t *dio, hammer2_off_t data_off, u_int bytes)
 }
 
 void
-hammer2_io_brelse(hammer2_io_t **diop)
+_hammer2_io_brelse(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
-       hammer2_io_putblk(diop);
+       _hammer2_io_putblk(diop HAMMER2_IO_DEBUG_CALL);
 }
 
 void
-hammer2_io_bqrelse(hammer2_io_t **diop)
+_hammer2_io_bqrelse(hammer2_io_t **diop HAMMER2_IO_DEBUG_ARGS)
 {
-       hammer2_io_putblk(diop);
+       _hammer2_io_putblk(diop HAMMER2_IO_DEBUG_CALL);
 }
 
 /*
@@ -854,7 +893,8 @@ hammer2_io_bkvasync(hammer2_io_t *dio)
  * Ref a dio that is already owned
  */
 void
-hammer2_io_ref(hammer2_io_t *dio)
+_hammer2_io_ref(hammer2_io_t *dio HAMMER2_IO_DEBUG_ARGS)
 {
+       DIO_RECORD(dio HAMMER2_IO_DEBUG_CALL);
        atomic_add_64(&dio->refs, 1);
 }