1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  14  */
  15 
  16 /*
  17  * mdb module for libmlsvc, which contains interesting data structures
  18  * including: the share cache
  19  */
  20 
  21 #include <mdb/mdb_modapi.h>
  22 #include <mdb/mdb_ks.h>
  23 #include <mdb/mdb_ctf.h>
  24 
  25 #include <synch.h>
  26 #include <smbsrv/hash_table.h>
  27 #include <smbsrv/libsmb.h>
  28 #include <smbsrv/smb_share.h>
  29 
  30 #define MLSVC_OBJNAME   "libmlsvc.so.1"
  31 #define MLSVC_SCOPE     MLSVC_OBJNAME "`"
  32 
  33 #define AFLAG           1
  34 #define VFLAG           2
  35 
  36 typedef struct dump_shr_args {
  37         uint_t dsa_opts;
  38         uintptr_t dsa_hdl;
  39         smb_share_t dsa_shr;
  40 } dump_shr_args_t;
  41 
  42 /*ARGSUSED*/
  43 static int
  44 dump_shr_cb(uintptr_t addr, const void *data, void *varg)
  45 {
  46         dump_shr_args_t *args = varg;
  47         const HT_ITEM *hi = data;
  48         smb_share_t *shr = &args->dsa_shr;
  49 
  50         if (hi->hi_data == NULL)
  51                 return (WALK_NEXT);
  52 
  53         if ((hi->hi_flags & HT_DELETE) != 0 &&
  54             (args->dsa_opts & AFLAG) == 0)
  55                 return (WALK_NEXT);
  56 
  57         if (args->dsa_opts & VFLAG) {
  58                 mdb_arg_t argv;
  59                 int flags = DCMD_ADDRSPEC;
  60 
  61                 argv.a_type = MDB_TYPE_STRING;
  62                 argv.a_un.a_str = MLSVC_SCOPE "smb_share_t";
  63                 /* Don't fail the walk if this fails. */
  64                 mdb_printf("%-?p ", hi->hi_data);
  65                 mdb_call_dcmd("print", (uintptr_t)hi->hi_data,
  66                     flags, 1, &argv);
  67         } else {
  68                 if (mdb_vread(shr, sizeof (*shr),
  69                     (uintptr_t)hi->hi_data) == -1) {
  70                         mdb_warn("failed to read %s at %p",
  71                             "smb_share_t", hi->hi_data);
  72                         return (WALK_NEXT);
  73                 }
  74 
  75                 mdb_printf("%-?p ", hi->hi_data);
  76                 mdb_printf("name=%s path=%s desc=\"%s\"\n",
  77                     shr->shr_name, shr->shr_path, shr->shr_cmnt);
  78         }
  79 
  80         return (WALK_NEXT);
  81 }
  82 
  83 
  84 /*
  85  * *************************** Top level dcmds ****************************
  86  */
  87 
  88 typedef struct mdb_smb_shr_cache {
  89         HT_HANDLE       *sc_cache;
  90         rwlock_t        sc_cache_lck;
  91         mutex_t         sc_mtx;
  92         cond_t          sc_cv;
  93         uint32_t        sc_state;
  94         uint32_t        sc_nops;
  95 } mdb_smb_shr_cache_t;
  96 
  97 
  98 static void
  99 smb_shr_cache_help(void)
 100 {
 101         mdb_printf(
 102             "Displays the list of shares in the smbd smb_shr_cache.\n"
 103             "With -a, also show deleted entries.\n"
 104             "With -v, print full smb_share_t objects.\n\n");
 105 }
 106 
 107 /*
 108  * ::smb_shr_cache
 109  */
 110 /*ARGSUSED*/
 111 static int
 112 smb_shr_cache_dcmd(uintptr_t addr, uint_t flags, int argc,
 113     const mdb_arg_t *argv)
 114 {
 115         dump_shr_args_t *args;
 116         mdb_smb_shr_cache_t *ssc;
 117 
 118         args = mdb_zalloc(sizeof (*args), UM_SLEEP | UM_GC);
 119 
 120         if (mdb_getopts(argc, argv,
 121             'a', MDB_OPT_SETBITS, AFLAG, &args->dsa_opts,
 122             'v', MDB_OPT_SETBITS, VFLAG, &args->dsa_opts,
 123             NULL) != argc)
 124                 return (DCMD_USAGE);
 125 
 126         if (!(flags & DCMD_ADDRSPEC)) {
 127                 GElf_Sym        sym;
 128 
 129                 /* Locate the shr hash head. */
 130                 if (mdb_lookup_by_obj(MLSVC_OBJNAME, "smb_shr_cache", &sym)) {
 131                         mdb_warn("failed to lookup `smb_shr_cache'\n");
 132                         return (DCMD_ERR);
 133                 }
 134                 addr = sym.st_value;
 135         }
 136 
 137         ssc = mdb_zalloc(sizeof (*ssc), UM_SLEEP | UM_GC);
 138         if (mdb_ctf_vread(ssc, MLSVC_SCOPE "smb_shr_cache_t",
 139             "mdb_smb_shr_cache_t", addr, 0) < 0) {
 140                 mdb_warn("failed to read smb_shr_cache at %p", addr);
 141                 return (DCMD_ERR);
 142         }
 143 
 144         /* Now walk HT_HANDLE *sc_cache */
 145         args->dsa_hdl = (uintptr_t)ssc->sc_cache;
 146 
 147         if (mdb_pwalk(MLSVC_SCOPE "smb_ht_walker",
 148             dump_shr_cb, args, args->dsa_hdl) == -1) {
 149                 mdb_warn("cannot walk smb_shr_cache list");
 150                 return (DCMD_ERR);
 151         }
 152         return (DCMD_OK);
 153 }
 154 
 155 
 156 
 157 /*
 158  * MDB module linkage information:
 159  *
 160  * We declare a list of structures describing our dcmds, a list of structures
 161  * describing our walkers and a function named _mdb_init to return a pointer
 162  * to our module information.
 163  */
 164 static const mdb_dcmd_t dcmds[] = {
 165 
 166         /* Avoiding name conflict with smbsrv`smb_shr_cache */
 167         {   "smbd_shr_cache",
 168             "[-av]",
 169             "print SMB share cache",
 170             smb_shr_cache_dcmd,
 171             smb_shr_cache_help },
 172 
 173         { NULL }
 174 };
 175 
 176 int smb_ht_walk_init(mdb_walk_state_t *wsp);
 177 int smb_ht_walk_step(mdb_walk_state_t *wsp);
 178 
 179 static const mdb_walker_t walkers[] = {
 180         {   "smb_ht_walker",
 181             "walk an smb_hash_t structure",
 182             smb_ht_walk_init,
 183             smb_ht_walk_step,
 184             NULL,
 185             NULL },
 186         { NULL }
 187 };
 188 
 189 static const mdb_modinfo_t modinfo = {
 190         MDB_API_VERSION, dcmds, walkers
 191 };
 192 
 193 const mdb_modinfo_t *
 194 _mdb_init(void)
 195 {
 196         return (&modinfo);
 197 }