Print this page
9525 kmem_dump_size is a corrupting influence

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/mdb/common/modules/genunix/kmem.c
          +++ new/usr/src/cmd/mdb/common/modules/genunix/kmem.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /*
  27      - * Copyright 2011 Joyent, Inc.  All rights reserved.
       27 + * Copyright 2018 Joyent, Inc.  All rights reserved.
  28   28   * Copyright (c) 2012 by Delphix. All rights reserved.
  29   29   */
  30   30  
  31   31  #include <mdb/mdb_param.h>
  32   32  #include <mdb/mdb_modapi.h>
  33   33  #include <mdb/mdb_ctf.h>
  34   34  #include <mdb/mdb_whatis.h>
  35   35  #include <sys/cpuvar.h>
  36   36  #include <sys/kmem_impl.h>
  37   37  #include <sys/vmem_impl.h>
↓ open down ↓ 2967 lines elided ↑ open up ↑
3005 3005                          mdb_printf("\n");
3006 3006          }
3007 3007  
3008 3008          return (DCMD_OK);
3009 3009  }
3010 3010  
3011 3011  typedef struct kmem_verify {
3012 3012          uint64_t *kmv_buf;              /* buffer to read cache contents into */
3013 3013          size_t kmv_size;                /* number of bytes in kmv_buf */
3014 3014          int kmv_corruption;             /* > 0 if corruption found. */
3015      -        int kmv_besilent;               /* report actual corruption sites */
     3015 +        uint_t kmv_flags;               /* dcmd flags */
3016 3016          struct kmem_cache kmv_cache;    /* the cache we're operating on */
3017 3017  } kmem_verify_t;
3018 3018  
3019 3019  /*
3020 3020   * verify_pattern()
3021 3021   *      verify that buf is filled with the pattern pat.
3022 3022   */
3023 3023  static int64_t
3024 3024  verify_pattern(uint64_t *buf_arg, size_t size, uint64_t pat)
3025 3025  {
↓ open down ↓ 24 lines elided ↑ open up ↑
3050 3050   */
3051 3051  /*ARGSUSED1*/
3052 3052  static int
3053 3053  verify_free(uintptr_t addr, const void *data, void *private)
3054 3054  {
3055 3055          kmem_verify_t *kmv = (kmem_verify_t *)private;
3056 3056          uint64_t *buf = kmv->kmv_buf;   /* buf to validate */
3057 3057          int64_t corrupt;                /* corruption offset */
3058 3058          kmem_buftag_t *buftagp;         /* ptr to buftag */
3059 3059          kmem_cache_t *cp = &kmv->kmv_cache;
3060      -        int besilent = kmv->kmv_besilent;
     3060 +        boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
3061 3061  
3062 3062          /*LINTED*/
3063 3063          buftagp = KMEM_BUFTAG(cp, buf);
3064 3064  
3065 3065          /*
3066 3066           * Read the buffer to check.
3067 3067           */
3068 3068          if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3069 3069                  if (!besilent)
3070 3070                          mdb_warn("couldn't read %p", addr);
↓ open down ↓ 25 lines elided ↑ open up ↑
3096 3096           */
3097 3097          if (verify_buftag(buftagp, KMEM_BUFTAG_FREE) == -1) {
3098 3098                  if (!besilent)
3099 3099                          mdb_printf("buffer %p (free) has a corrupt "
3100 3100                              "buftag\n", addr);
3101 3101                  goto corrupt;
3102 3102          }
3103 3103  
3104 3104          return (WALK_NEXT);
3105 3105  corrupt:
     3106 +        if (kmv->kmv_flags & DCMD_PIPE_OUT)
     3107 +                mdb_printf("%p\n", addr);
3106 3108          kmv->kmv_corruption++;
3107 3109          return (WALK_NEXT);
3108 3110  }
3109 3111  
3110 3112  /*
3111 3113   * verify_alloc()
3112 3114   *      Verify that the buftag of an allocated buffer makes sense with respect
3113 3115   *      to the buffer.
3114 3116   */
3115 3117  /*ARGSUSED1*/
↓ open down ↓ 1 lines elided ↑ open up ↑
3117 3119  verify_alloc(uintptr_t addr, const void *data, void *private)
3118 3120  {
3119 3121          kmem_verify_t *kmv = (kmem_verify_t *)private;
3120 3122          kmem_cache_t *cp = &kmv->kmv_cache;
3121 3123          uint64_t *buf = kmv->kmv_buf;   /* buf to validate */
3122 3124          /*LINTED*/
3123 3125          kmem_buftag_t *buftagp = KMEM_BUFTAG(cp, buf);
3124 3126          uint32_t *ip = (uint32_t *)buftagp;
3125 3127          uint8_t *bp = (uint8_t *)buf;
3126 3128          int looks_ok = 0, size_ok = 1;  /* flags for finding corruption */
3127      -        int besilent = kmv->kmv_besilent;
     3129 +        boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
3128 3130  
3129 3131          /*
3130 3132           * Read the buffer to check.
3131 3133           */
3132 3134          if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3133 3135                  if (!besilent)
3134 3136                          mdb_warn("couldn't read %p", addr);
3135 3137                  return (WALK_NEXT);
3136 3138          }
3137 3139  
↓ open down ↓ 37 lines elided ↑ open up ↑
3175 3177  
3176 3178          if (verify_buftag(buftagp, KMEM_BUFTAG_ALLOC) == -1) {
3177 3179                  if (!besilent)
3178 3180                          mdb_printf("buffer %p (allocated) has a "
3179 3181                              "corrupt buftag\n", addr);
3180 3182                  goto corrupt;
3181 3183          }
3182 3184  
3183 3185          return (WALK_NEXT);
3184 3186  corrupt:
     3187 +        if (kmv->kmv_flags & DCMD_PIPE_OUT)
     3188 +                mdb_printf("%p\n", addr);
     3189 +
3185 3190          kmv->kmv_corruption++;
3186 3191          return (WALK_NEXT);
3187 3192  }
3188 3193  
3189 3194  /*ARGSUSED2*/
3190 3195  int
3191 3196  kmem_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3192 3197  {
3193 3198          if (flags & DCMD_ADDRSPEC) {
3194 3199                  int check_alloc = 0, check_free = 0;
3195 3200                  kmem_verify_t kmv;
3196 3201  
3197 3202                  if (mdb_vread(&kmv.kmv_cache, sizeof (kmv.kmv_cache),
3198 3203                      addr) == -1) {
3199 3204                          mdb_warn("couldn't read kmem_cache %p", addr);
3200 3205                          return (DCMD_ERR);
3201 3206                  }
3202 3207  
     3208 +                if ((kmv.kmv_cache.cache_dump.kd_unsafe ||
     3209 +                    kmv.kmv_cache.cache_dump.kd_alloc_fails) &&
     3210 +                    !(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {
     3211 +                        mdb_warn("WARNING: cache was used during dump: "
     3212 +                            "corruption may be incorrectly reported\n");
     3213 +                }
     3214 +
3203 3215                  kmv.kmv_size = kmv.kmv_cache.cache_buftag +
3204 3216                      sizeof (kmem_buftag_t);
3205 3217                  kmv.kmv_buf = mdb_alloc(kmv.kmv_size, UM_SLEEP | UM_GC);
3206 3218                  kmv.kmv_corruption = 0;
     3219 +                kmv.kmv_flags = flags;
3207 3220  
3208 3221                  if ((kmv.kmv_cache.cache_flags & KMF_REDZONE)) {
3209 3222                          check_alloc = 1;
3210 3223                          if (kmv.kmv_cache.cache_flags & KMF_DEADBEEF)
3211 3224                                  check_free = 1;
3212 3225                  } else {
3213 3226                          if (!(flags & DCMD_LOOP)) {
3214 3227                                  mdb_warn("cache %p (%s) does not have "
3215 3228                                      "redzone checking enabled\n", addr,
3216 3229                                      kmv.kmv_cache.cache_name);
3217 3230                          }
3218 3231                          return (DCMD_ERR);
3219 3232                  }
3220 3233  
3221      -                if (flags & DCMD_LOOP) {
3222      -                        /*
3223      -                         * table mode, don't print out every corrupt buffer
3224      -                         */
3225      -                        kmv.kmv_besilent = 1;
3226      -                } else {
     3234 +                if (!(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {
3227 3235                          mdb_printf("Summary for cache '%s'\n",
3228 3236                              kmv.kmv_cache.cache_name);
3229 3237                          mdb_inc_indent(2);
3230      -                        kmv.kmv_besilent = 0;
3231 3238                  }
3232 3239  
3233 3240                  if (check_alloc)
3234 3241                          (void) mdb_pwalk("kmem", verify_alloc, &kmv, addr);
3235 3242                  if (check_free)
3236 3243                          (void) mdb_pwalk("freemem", verify_free, &kmv, addr);
3237 3244  
3238      -                if (flags & DCMD_LOOP) {
3239      -                        if (kmv.kmv_corruption == 0) {
3240      -                                mdb_printf("%-*s %?p clean\n",
3241      -                                    KMEM_CACHE_NAMELEN,
3242      -                                    kmv.kmv_cache.cache_name, addr);
     3245 +                if (!(flags & DCMD_PIPE_OUT)) {
     3246 +                        if (flags & DCMD_LOOP) {
     3247 +                                if (kmv.kmv_corruption == 0) {
     3248 +                                        mdb_printf("%-*s %?p clean\n",
     3249 +                                            KMEM_CACHE_NAMELEN,
     3250 +                                            kmv.kmv_cache.cache_name, addr);
     3251 +                                } else {
     3252 +                                        mdb_printf("%-*s %?p %d corrupt "
     3253 +                                            "buffer%s\n", KMEM_CACHE_NAMELEN,
     3254 +                                            kmv.kmv_cache.cache_name, addr,
     3255 +                                            kmv.kmv_corruption,
     3256 +                                            kmv.kmv_corruption > 1 ? "s" : "");
     3257 +                                }
3243 3258                          } else {
3244      -                                char *s = "";   /* optional s in "buffer[s]" */
3245      -                                if (kmv.kmv_corruption > 1)
3246      -                                        s = "s";
     3259 +                                /*
     3260 +                                 * This is the more verbose mode, when the user
     3261 +                                 * typed addr::kmem_verify.  If the cache was
     3262 +                                 * clean, nothing will have yet been printed. So
     3263 +                                 * say something.
     3264 +                                 */
     3265 +                                if (kmv.kmv_corruption == 0)
     3266 +                                        mdb_printf("clean\n");
3247 3267  
3248      -                                mdb_printf("%-*s %?p %d corrupt buffer%s\n",
3249      -                                    KMEM_CACHE_NAMELEN,
3250      -                                    kmv.kmv_cache.cache_name, addr,
3251      -                                    kmv.kmv_corruption, s);
     3268 +                                mdb_dec_indent(2);
3252 3269                          }
3253      -                } else {
3254      -                        /*
3255      -                         * This is the more verbose mode, when the user has
3256      -                         * type addr::kmem_verify.  If the cache was clean,
3257      -                         * nothing will have yet been printed. So say something.
3258      -                         */
3259      -                        if (kmv.kmv_corruption == 0)
3260      -                                mdb_printf("clean\n");
3261      -
3262      -                        mdb_dec_indent(2);
3263 3270                  }
3264 3271          } else {
3265 3272                  /*
3266 3273                   * If the user didn't specify a cache to verify, we'll walk all
3267 3274                   * kmem_cache's, specifying ourself as a callback for each...
3268 3275                   * this is the equivalent of '::walk kmem_cache .::kmem_verify'
3269 3276                   */
3270      -                mdb_printf("%<u>%-*s %-?s %-20s%</b>\n", KMEM_CACHE_NAMELEN,
3271      -                    "Cache Name", "Addr", "Cache Integrity");
     3277 +
     3278 +                if (!(flags & DCMD_PIPE_OUT)) {
     3279 +                        uintptr_t dump_curr;
     3280 +                        uintptr_t dump_end;
     3281 +
     3282 +                        if (mdb_readvar(&dump_curr, "kmem_dump_curr") != -1 &&
     3283 +                            mdb_readvar(&dump_end, "kmem_dump_end") != -1 &&
     3284 +                            dump_curr == dump_end) {
     3285 +                                mdb_warn("WARNING: exceeded kmem_dump_size; "
     3286 +                                    "corruption may be incorrectly reported\n");
     3287 +                        }
     3288 +
     3289 +                        mdb_printf("%<u>%-*s %-?s %-20s%</b>\n",
     3290 +                            KMEM_CACHE_NAMELEN, "Cache Name", "Addr",
     3291 +                            "Cache Integrity");
     3292 +                }
     3293 +
3272 3294                  (void) (mdb_walk_dcmd("kmem_cache", "kmem_verify", 0, NULL));
3273 3295          }
3274 3296  
3275 3297          return (DCMD_OK);
3276 3298  }
3277 3299  
3278 3300  typedef struct vmem_node {
3279 3301          struct vmem_node *vn_next;
3280 3302          struct vmem_node *vn_parent;
3281 3303          struct vmem_node *vn_sibling;
↓ open down ↓ 1100 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX