Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Introduce POOL_REDZONE.



details:   https://anonhg.NetBSD.org/src/rev/f1bdb7c7d5ed
branches:  trunk
changeset: 339555:f1bdb7c7d5ed
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue Jul 28 12:32:44 2015 +0000

description:
Introduce POOL_REDZONE.

diffstat:

 sys/kern/subr_pool.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++---
 sys/sys/pool.h       |    8 ++-
 2 files changed, 152 insertions(+), 13 deletions(-)

diffs (286 lines):

diff -r 6bbb40151988 -r f1bdb7c7d5ed sys/kern/subr_pool.c
--- a/sys/kern/subr_pool.c      Tue Jul 28 12:27:55 2015 +0000
+++ b/sys/kern/subr_pool.c      Tue Jul 28 12:32:44 2015 +0000
@@ -1,13 +1,14 @@
-/*     $NetBSD: subr_pool.c,v 1.203 2014/06/13 19:09:07 joerg Exp $    */
+/*     $NetBSD: subr_pool.c,v 1.204 2015/07/28 12:32:44 maxv Exp $     */
 
 /*-
- * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014
+ * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015
  *     The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Paul Kranenburg; by Jason R. Thorpe of the Numerical Aerospace
- * Simulation Facility, NASA Ames Research Center, and by Andrew Doran.
+ * Simulation Facility, NASA Ames Research Center; by Andrew Doran, and by
+ * Maxime Villard.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.203 2014/06/13 19:09:07 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.204 2015/07/28 12:32:44 maxv Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -82,6 +83,17 @@
 static struct pool psppool;
 #endif
 
+#ifdef POOL_REDZONE
+# define POOL_REDZONE_SIZE 2
+static void pool_redzone_init(struct pool *, size_t);
+static void pool_redzone_fill(struct pool *, void *);
+static void pool_redzone_check(struct pool *, void *);
+#else
+# define pool_redzone_init(pp, sz)     /* NOTHING */
+# define pool_redzone_fill(pp, ptr)    /* NOTHING */
+# define pool_redzone_check(pp, ptr)   /* NOTHING */
+#endif
+
 static void *pool_page_alloc_meta(struct pool *, int);
 static void pool_page_free_meta(struct pool *, void *);
 
@@ -459,7 +471,7 @@
     const char *wchan, struct pool_allocator *palloc, int ipl)
 {
        struct pool *pp1;
-       size_t trysize, phsize;
+       size_t trysize, phsize, prsize;
        int off, slack;
 
 #ifdef DEBUG
@@ -506,13 +518,14 @@
        if (align == 0)
                align = ALIGN(1);
 
-       if ((flags & PR_NOTOUCH) == 0 && size < sizeof(struct pool_item))
-               size = sizeof(struct pool_item);
-
-       size = roundup(size, align);
+       prsize = size;
+       if ((flags & PR_NOTOUCH) == 0 && prsize < sizeof(struct pool_item))
+               prsize = sizeof(struct pool_item);
+
+       prsize = roundup(prsize, align);
 #ifdef DIAGNOSTIC
-       if (size > palloc->pa_pagesz)
-               panic("pool_init: pool item size (%zu) too large", size);
+       if (prsize > palloc->pa_pagesz)
+               panic("pool_init: pool item size (%zu) too large", prsize);
 #endif
 
        /*
@@ -529,7 +542,7 @@
        pp->pr_maxpages = UINT_MAX;
        pp->pr_roflags = flags;
        pp->pr_flags = 0;
-       pp->pr_size = size;
+       pp->pr_size = prsize;
        pp->pr_align = align;
        pp->pr_wchan = wchan;
        pp->pr_alloc = palloc;
@@ -544,6 +557,7 @@
        pp->pr_drain_hook = NULL;
        pp->pr_drain_hook_arg = NULL;
        pp->pr_freecheck = NULL;
+       pool_redzone_init(pp, size);
 
        /*
         * Decide whether to put the page header off page to avoid
@@ -935,6 +949,7 @@
        mutex_exit(&pp->pr_lock);
        KASSERT((((vaddr_t)v + pp->pr_itemoffset) & (pp->pr_align - 1)) == 0);
        FREECHECK_OUT(&pp->pr_freecheck, v);
+       pool_redzone_fill(pp, v);
        return (v);
 }
 
@@ -948,6 +963,7 @@
        struct pool_item_header *ph;
 
        KASSERT(mutex_owned(&pp->pr_lock));
+       pool_redzone_check(pp, v);
        FREECHECK_IN(&pp->pr_freecheck, v);
        LOCKDEBUG_MEM_CHECK(v, pp->pr_size);
 
@@ -2188,6 +2204,7 @@
        }
 
        FREECHECK_OUT(&pc->pc_freecheck, object);
+       pool_redzone_fill(&pc->pc_pool, object);
        return false;
 }
 
@@ -2233,6 +2250,7 @@
                        cc->cc_hits++;
                        splx(s);
                        FREECHECK_OUT(&pc->pc_freecheck, object);
+                       pool_redzone_fill(&pc->pc_pool, object);
                        return object;
                }
 
@@ -2376,6 +2394,7 @@
        int s;
 
        KASSERT(object != NULL);
+       pool_redzone_check(&pc->pc_pool, object);
        FREECHECK_IN(&pc->pc_freecheck, object);
 
        /* Lock out interrupts and disable preemption. */
@@ -2597,6 +2616,120 @@
        vmem_free(kmem_meta_arena, (vmem_addr_t)v, pp->pr_alloc->pa_pagesz);
 }
 
+#ifdef POOL_REDZONE
+#if defined(_LP64)
+# define PRIME 0x9e37fffffffc0000UL
+#else /* defined(_LP64) */
+# define PRIME 0x9e3779b1
+#endif /* defined(_LP64) */
+#define STATIC_BYTE    0xFE
+CTASSERT(POOL_REDZONE_SIZE > 1);
+
+static inline uint8_t
+pool_pattern_generate(const void *p)
+{
+       return (uint8_t)(((uintptr_t)p) * PRIME
+          >> ((sizeof(uintptr_t) - sizeof(uint8_t))) * CHAR_BIT);
+}
+
+static void
+pool_redzone_init(struct pool *pp, size_t requested_size)
+{
+       size_t nsz;
+
+       if (pp->pr_roflags & PR_NOTOUCH) {
+               pp->pr_reqsize = 0;
+               pp->pr_redzone = false;
+               return;
+       }
+
+       /*
+        * We may have extended the requested size earlier; check if
+        * there's naturally space in the padding for a red zone.
+        */
+       if (pp->pr_size - requested_size >= POOL_REDZONE_SIZE) {
+               pp->pr_reqsize = requested_size;
+               pp->pr_redzone = true;
+               return;
+       }
+
+       /*
+        * No space in the natural padding; check if we can extend a
+        * bit the size of the pool.
+        */
+       nsz = roundup(pp->pr_size + POOL_REDZONE_SIZE, pp->pr_align);
+       if (nsz <= pp->pr_alloc->pa_pagesz) {
+               /* Ok, we can */
+               pp->pr_size = nsz;
+               pp->pr_reqsize = requested_size;
+               pp->pr_redzone = true;
+       } else {
+               /* No space for a red zone... snif :'( */
+               pp->pr_reqsize = 0;
+               pp->pr_redzone = false;
+               printf("pool redzone disabled for '%s'\n", pp->pr_wchan);
+       }
+}
+
+static void
+pool_redzone_fill(struct pool *pp, void *p)
+{
+       uint8_t *cp, pat;
+       const uint8_t *ep;
+
+       if (!pp->pr_redzone)
+               return;
+
+       cp = (uint8_t *)p + pp->pr_reqsize;
+       ep = cp + POOL_REDZONE_SIZE;
+
+       /*
+        * We really don't want the first byte of the red zone to be '\0';
+        * an off-by-one in a string may not be properly detected.
+        */
+       pat = pool_pattern_generate(cp);
+       *cp = (pat == '\0') ? STATIC_BYTE: pat;
+       cp++;
+
+       while (cp < ep) {
+               *cp = pool_pattern_generate(cp);
+               cp++;
+       }
+}
+
+static void
+pool_redzone_check(struct pool *pp, void *p)
+{
+       uint8_t *cp, pat, expected;
+       const uint8_t *ep;
+
+       if (!pp->pr_redzone)
+               return;
+
+       cp = (uint8_t *)p + pp->pr_reqsize;
+       ep = cp + POOL_REDZONE_SIZE;
+
+       pat = pool_pattern_generate(cp);
+       expected = (pat == '\0') ? STATIC_BYTE: pat;
+       if (expected != *cp) {
+               panic("%s: %p: 0x%02x != 0x%02x\n",
+                  __func__, cp, *cp, expected);
+       }
+       cp++;
+
+       while (cp < ep) {
+               expected = pool_pattern_generate(cp);
+               if (*cp != expected) {
+                       panic("%s: %p: 0x%02x != 0x%02x\n",
+                          __func__, cp, *cp, expected);
+               }
+               cp++;
+       }
+}
+
+#endif /* POOL_REDZONE */
+
+
 #ifdef POOL_SUBPAGE
 /* Sub-page allocator, for machines with large hardware pages. */
 void *
diff -r 6bbb40151988 -r f1bdb7c7d5ed sys/sys/pool.h
--- a/sys/sys/pool.h    Tue Jul 28 12:27:55 2015 +0000
+++ b/sys/sys/pool.h    Tue Jul 28 12:32:44 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pool.h,v 1.77 2014/09/05 05:42:50 matt Exp $   */
+/*     $NetBSD: pool.h,v 1.78 2015/07/28 12:32:44 maxv Exp $   */
 
 /*-
  * Copyright (c) 1997, 1998, 1999, 2000, 2007 The NetBSD Foundation, Inc.
@@ -189,6 +189,8 @@
         */
        void            *pr_freecheck;
        void            *pr_qcache;
+       bool            pr_redzone;
+       size_t          pr_reqsize;
 };
 
 /*
@@ -253,7 +255,11 @@
        unsigned int    pc_nfull;       /* full groups in cache */
        unsigned int    pc_npart;       /* partial groups in cache */
        unsigned int    pc_refcnt;      /* ref count for pagedaemon, etc */
+
+       /* Diagnostic aides. */
        void            *pc_freecheck;
+       bool            pc_redzone;
+       size_t          pc_reqsize;
 
        /* CPU layer. */
        pool_cache_cpu_t pc_cpu0 __aligned(CACHE_LINE_SIZE);



Home | Main Index | Thread Index | Old Index