Print this page
    
9059 Simplify SMAP relocations with krtld
Portions contributed by: John Levon <john.levon@joyent.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/os/modctl.c
          +++ new/usr/src/uts/common/os/modctl.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright (c) 2017 Joyent, Inc.
  24   25   */
  25   26  
  26   27  /*
  27   28   * modctl system call for loadable module support.
  28   29   */
  29   30  
  30   31  #include <sys/param.h>
  31   32  #include <sys/user.h>
  32   33  #include <sys/systm.h>
  33   34  #include <sys/exec.h>
  34   35  #include <sys/file.h>
  35   36  #include <sys/stat.h>
  36   37  #include <sys/conf.h>
  37   38  #include <sys/time.h>
  38   39  #include <sys/reboot.h>
  39   40  #include <sys/fs/ufs_fsdir.h>
  40   41  #include <sys/kmem.h>
  41   42  #include <sys/sysconf.h>
  42   43  #include <sys/cmn_err.h>
  43   44  #include <sys/ddi.h>
  44   45  #include <sys/sunddi.h>
  45   46  #include <sys/sunndi.h>
  46   47  #include <sys/ndi_impldefs.h>
  47   48  #include <sys/ddi_impldefs.h>
  48   49  #include <sys/ddi_implfuncs.h>
  49   50  #include <sys/bootconf.h>
  50   51  #include <sys/dc_ki.h>
  51   52  #include <sys/cladm.h>
  52   53  #include <sys/dtrace.h>
  53   54  #include <sys/kdi.h>
  54   55  
  55   56  #include <sys/devpolicy.h>
  56   57  #include <sys/modctl.h>
  57   58  #include <sys/kobj.h>
  58   59  #include <sys/devops.h>
  59   60  #include <sys/autoconf.h>
  60   61  #include <sys/hwconf.h>
  61   62  #include <sys/callb.h>
  62   63  #include <sys/debug.h>
  63   64  #include <sys/cpuvar.h>
  64   65  #include <sys/sysmacros.h>
  65   66  #include <sys/sysevent.h>
  66   67  #include <sys/sysevent_impl.h>
  67   68  #include <sys/instance.h>
  68   69  #include <sys/modhash.h>
  69   70  #include <sys/modhash_impl.h>
  70   71  #include <sys/dacf_impl.h>
  71   72  #include <sys/vfs.h>
  72   73  #include <sys/pathname.h>
  73   74  #include <sys/console.h>
  74   75  #include <sys/policy.h>
  75   76  #include <ipp/ipp_impl.h>
  76   77  #include <sys/fs/dv_node.h>
  77   78  #include <sys/strsubr.h>
  78   79  #include <sys/fs/sdev_impl.h>
  79   80  
  80   81  static int              mod_circdep(struct modctl *);
  81   82  static int              modinfo(modid_t, struct modinfo *);
  82   83  
  83   84  static void             mod_uninstall_all(void);
  84   85  static int              mod_getinfo(struct modctl *, struct modinfo *);
  85   86  static struct modctl    *allocate_modp(const char *, const char *);
  86   87  
  87   88  static int              mod_load(struct modctl *, int);
  88   89  static void             mod_unload(struct modctl *);
  89   90  static int              modinstall(struct modctl *);
  90   91  static int              moduninstall(struct modctl *);
  91   92  
  92   93  static struct modctl    *mod_hold_by_name_common(struct modctl *, const char *);
  93   94  static struct modctl    *mod_hold_next_by_id(modid_t);
  94   95  static struct modctl    *mod_hold_loaded_mod(struct modctl *, char *, int *);
  95   96  static struct modctl    *mod_hold_installed_mod(char *, int, int, int *);
  96   97  
  97   98  static void             mod_release(struct modctl *);
  98   99  static void             mod_make_requisite(struct modctl *, struct modctl *);
  99  100  static int              mod_install_requisites(struct modctl *);
 100  101  static void             check_esc_sequences(char *, char *);
 101  102  static struct modctl    *mod_hold_by_name_requisite(struct modctl *, char *);
 102  103  
 103  104  /*
 104  105   * module loading thread control structure. Calls to kobj_load_module()() are
 105  106   * handled off to a separate thead using this structure.
 106  107   */
 107  108  struct loadmt {
 108  109          ksema_t         sema;
 109  110          struct modctl   *mp;
 110  111          int             usepath;
 111  112          kthread_t       *owner;
 112  113          int             retval;
 113  114  };
 114  115  
 115  116  static void     modload_thread(struct loadmt *);
 116  117  
 117  118  kcondvar_t      mod_cv;
 118  119  kcondvar_t      mod_uninstall_cv;       /* Communication between swapper */
 119  120                                          /* and the uninstall daemon. */
 120  121  kmutex_t        mod_lock;               /* protects &modules insert linkage, */
 121  122                                          /* mod_busy, mod_want, and mod_ref. */
 122  123                                          /* blocking operations while holding */
 123  124                                          /* mod_lock should be avoided */
 124  125  kmutex_t        mod_uninstall_lock;     /* protects mod_uninstall_cv */
 125  126  kthread_id_t    mod_aul_thread;
 126  127  
 127  128  int             modunload_wait;
 128  129  kmutex_t        modunload_wait_mutex;
 129  130  kcondvar_t      modunload_wait_cv;
 130  131  int             modunload_active_count;
 131  132  int             modunload_disable_count;
 132  133  
 133  134  int     isminiroot;             /* set if running as miniroot */
 134  135  int     modrootloaded;          /* set after root driver and fs are loaded */
 135  136  int     moddebug = 0x0;         /* debug flags for module writers */
 136  137  int     swaploaded;             /* set after swap driver and fs are loaded */
 137  138  int     bop_io_quiesced = 0;    /* set when BOP I/O can no longer be used */
 138  139  int     last_module_id;
 139  140  clock_t mod_uninstall_interval = 0;
 140  141  int     mod_uninstall_pass_max = 6;
 141  142  int     mod_uninstall_ref_zero; /* # modules that went mod_ref == 0 */
 142  143  int     mod_uninstall_pass_exc; /* mod_uninstall_all left new stuff */
 143  144  
 144  145  int     ddi_modclose_unload = 1;        /* 0 -> just decrement reference */
 145  146  
 146  147  int     devcnt_incr     = 256;          /* allow for additional drivers */
 147  148  int     devcnt_min      = 512;          /* and always at least this number */
 148  149  
 149  150  struct devnames *devnamesp;
 150  151  struct devnames orphanlist;
 151  152  
 152  153  krwlock_t       devinfo_tree_lock;      /* obsolete, to be removed */
 153  154  
 154  155  #define MAJBINDFILE "/etc/name_to_major"
 155  156  #define SYSBINDFILE "/etc/name_to_sysnum"
 156  157  
 157  158  static char     majbind[] = MAJBINDFILE;
 158  159  static char     sysbind[] = SYSBINDFILE;
 159  160  static uint_t   mod_autounload_key;     /* for module autounload detection */
 160  161  
 161  162  extern int obpdebug;
 162  163  
 163  164  #define DEBUGGER_PRESENT        ((boothowto & RB_DEBUG) || (obpdebug != 0))
 164  165  
 165  166  static int minorperm_loaded = 0;
 166  167  
 167  168  void
 168  169  mod_setup(void)
 169  170  {
 170  171          struct sysent *callp;
 171  172          int callnum, exectype;
 172  173          int     num_devs;
 173  174          int     i;
 174  175  
 175  176          /*
 176  177           * Initialize the list of loaded driver dev_ops.
 177  178           * XXX - This must be done before reading the system file so that
 178  179           * forceloads of drivers will work.
 179  180           */
 180  181          num_devs = read_binding_file(majbind, mb_hashtab, make_mbind);
 181  182          /*
 182  183           * Since read_binding_file is common code, it doesn't enforce that all
 183  184           * of the binding file entries have major numbers <= MAXMAJ32.  Thus,
 184  185           * ensure that we don't allocate some massive amount of space due to a
 185  186           * bad entry.  We can't have major numbers bigger than MAXMAJ32
 186  187           * until file system support for larger major numbers exists.
 187  188           */
 188  189  
 189  190          /*
 190  191           * Leave space for expansion, but not more than L_MAXMAJ32
 191  192           */
 192  193          devcnt = MIN(num_devs + devcnt_incr, L_MAXMAJ32);
 193  194          devcnt = MAX(devcnt, devcnt_min);
 194  195          devopsp = kmem_alloc(devcnt * sizeof (struct dev_ops *), KM_SLEEP);
 195  196          for (i = 0; i < devcnt; i++)
 196  197                  devopsp[i] = &mod_nodev_ops;
 197  198  
 198  199          init_devnamesp(devcnt);
 199  200  
 200  201          /*
 201  202           * Sync up with the work that the stand-alone linker has already done.
 202  203           */
 203  204          (void) kobj_sync();
 204  205  
 205  206          if (boothowto & RB_DEBUG)
 206  207                  kdi_dvec_modavail();
 207  208  
 208  209          make_aliases(mb_hashtab);
 209  210  
 210  211          /*
 211  212           * Initialize streams device implementation structures.
 212  213           */
 213  214          devimpl = kmem_zalloc(devcnt * sizeof (cdevsw_impl_t), KM_SLEEP);
 214  215  
 215  216          /*
 216  217           * If the cl_bootstrap module is present,
 217  218           * we should be configured as a cluster. Loading this module
 218  219           * will set "cluster_bootflags" to non-zero.
 219  220           */
 220  221          (void) modload("misc", "cl_bootstrap");
 221  222  
 222  223          (void) read_binding_file(sysbind, sb_hashtab, make_mbind);
 223  224          init_syscallnames(NSYSCALL);
 224  225  
 225  226          /*
 226  227           * Start up dynamic autoconfiguration framework (dacf).
 227  228           */
 228  229          mod_hash_init();
 229  230          dacf_init();
 230  231  
 231  232          /*
 232  233           * Start up IP policy framework (ipp).
 233  234           */
 234  235          ipp_init();
 235  236  
 236  237          /*
 237  238           * Allocate loadable native system call locks.
 238  239           */
 239  240          for (callnum = 0, callp = sysent; callnum < NSYSCALL;
 240  241              callnum++, callp++) {
 241  242                  if (LOADABLE_SYSCALL(callp)) {
 242  243                          if (mod_getsysname(callnum) != NULL) {
 243  244                                  callp->sy_lock =
 244  245                                      kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
 245  246                                  rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL);
 246  247                          } else {
 247  248                                  callp->sy_flags &= ~SE_LOADABLE;
 248  249                                  callp->sy_callc = nosys;
 249  250                          }
 250  251  #ifdef DEBUG
 251  252                  } else {
 252  253                          /*
 253  254                           * Do some sanity checks on the sysent table
 254  255                           */
 255  256                          switch (callp->sy_flags & SE_RVAL_MASK) {
 256  257                          case SE_32RVAL1:
 257  258                                  /* only r_val1 returned */
 258  259                          case SE_32RVAL1 | SE_32RVAL2:
 259  260                                  /* r_val1 and r_val2 returned */
 260  261                          case SE_64RVAL:
 261  262                                  /* 64-bit rval returned */
 262  263                                  break;
 263  264                          default:
 264  265                                  cmn_err(CE_WARN, "sysent[%d]: bad flags %x",
 265  266                                      callnum, callp->sy_flags);
 266  267                          }
 267  268  #endif
 268  269                  }
 269  270          }
 270  271  
 271  272  #ifdef _SYSCALL32_IMPL
 272  273          /*
 273  274           * Allocate loadable system call locks for 32-bit compat syscalls
 274  275           */
 275  276          for (callnum = 0, callp = sysent32; callnum < NSYSCALL;
 276  277              callnum++, callp++) {
 277  278                  if (LOADABLE_SYSCALL(callp)) {
 278  279                          if (mod_getsysname(callnum) != NULL) {
 279  280                                  callp->sy_lock =
 280  281                                      kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
 281  282                                  rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL);
 282  283                          } else {
 283  284                                  callp->sy_flags &= ~SE_LOADABLE;
 284  285                                  callp->sy_callc = nosys;
 285  286                          }
 286  287  #ifdef DEBUG
 287  288                  } else {
 288  289                          /*
 289  290                           * Do some sanity checks on the sysent table
 290  291                           */
 291  292                          switch (callp->sy_flags & SE_RVAL_MASK) {
 292  293                          case SE_32RVAL1:
 293  294                                  /* only r_val1 returned */
 294  295                          case SE_32RVAL1 | SE_32RVAL2:
 295  296                                  /* r_val1 and r_val2 returned */
 296  297                          case SE_64RVAL:
 297  298                                  /* 64-bit rval returned */
 298  299                                  break;
 299  300                          default:
 300  301                                  cmn_err(CE_WARN, "sysent32[%d]: bad flags %x",
 301  302                                      callnum, callp->sy_flags);
 302  303                                  goto skip;
 303  304                          }
 304  305  
 305  306                          /*
 306  307                           * Cross-check the native and compatibility tables.
 307  308                           */
 308  309                          if (callp->sy_callc == nosys ||
 309  310                              sysent[callnum].sy_callc == nosys)
 310  311                                  continue;
 311  312                          /*
 312  313                           * If only one or the other slot is loadable, then
 313  314                           * there's an error -- they should match!
 314  315                           */
 315  316                          if ((callp->sy_callc == loadable_syscall) ^
 316  317                              (sysent[callnum].sy_callc == loadable_syscall)) {
 317  318                                  cmn_err(CE_WARN, "sysent[%d] loadable?",
 318  319                                      callnum);
 319  320                          }
 320  321                          /*
 321  322                           * This is more of a heuristic test -- if the
 322  323                           * system call returns two values in the 32-bit
 323  324                           * world, it should probably return two 32-bit
 324  325                           * values in the 64-bit world too.
 325  326                           */
 326  327                          if (((callp->sy_flags & SE_32RVAL2) == 0) ^
 327  328                              ((sysent[callnum].sy_flags & SE_32RVAL2) == 0)) {
 328  329                                  cmn_err(CE_WARN, "sysent[%d] rval2 mismatch!",
 329  330                                      callnum);
 330  331                          }
 331  332  skip:;
 332  333  #endif  /* DEBUG */
 333  334                  }
 334  335          }
 335  336  #endif  /* _SYSCALL32_IMPL */
 336  337  
 337  338          /*
 338  339           * Allocate loadable exec locks.  (Assumes all execs are loadable)
 339  340           */
 340  341          for (exectype = 0; exectype < nexectype; exectype++) {
 341  342                  execsw[exectype].exec_lock =
 342  343                      kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
 343  344                  rw_init(execsw[exectype].exec_lock, NULL, RW_DEFAULT, NULL);
 344  345          }
 345  346  
 346  347          read_class_file();
 347  348  
 348  349          /* init thread specific structure for mod_uninstall_all */
 349  350          tsd_create(&mod_autounload_key, NULL);
 350  351  }
 351  352  
 352  353  static int
 353  354  modctl_modload(int use_path, char *filename, int *rvp)
 354  355  {
 355  356          struct modctl *modp;
 356  357          int retval = 0;
 357  358          char *filenamep;
 358  359          int modid;
 359  360  
 360  361          filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
 361  362  
 362  363          if (copyinstr(filename, filenamep, MOD_MAXPATH, 0)) {
 363  364                  retval = EFAULT;
 364  365                  goto out;
 365  366          }
 366  367  
 367  368          filenamep[MOD_MAXPATH - 1] = 0;
 368  369          modp = mod_hold_installed_mod(filenamep, use_path, 0, &retval);
 369  370  
 370  371          if (modp == NULL)
 371  372                  goto out;
 372  373  
 373  374          modp->mod_loadflags |= MOD_NOAUTOUNLOAD;
 374  375          modid = modp->mod_id;
 375  376          mod_release_mod(modp);
 376  377          CPU_STATS_ADDQ(CPU, sys, modload, 1);
 377  378          if (rvp != NULL && copyout(&modid, rvp, sizeof (modid)) != 0)
 378  379                  retval = EFAULT;
 379  380  out:
 380  381          kmem_free(filenamep, MOD_MAXPATH);
 381  382  
 382  383          return (retval);
 383  384  }
 384  385  
 385  386  static int
 386  387  modctl_modunload(modid_t id)
 387  388  {
 388  389          int rval = 0;
 389  390  
 390  391          if (id == 0) {
 391  392  #ifdef DEBUG
 392  393                  /*
 393  394                   * Turn on mod_uninstall_daemon
 394  395                   */
 395  396                  if (mod_uninstall_interval == 0) {
 396  397                          mod_uninstall_interval = 60;
 397  398                          modreap();
 398  399                          return (rval);
 399  400                  }
 400  401  #endif
 401  402                  mod_uninstall_all();
 402  403          } else {
 403  404                  rval = modunload(id);
 404  405          }
 405  406          return (rval);
 406  407  }
 407  408  
 408  409  static int
 409  410  modctl_modinfo(modid_t id, struct modinfo *umodi)
 410  411  {
 411  412          int retval;
 412  413          struct modinfo modi;
 413  414  #if defined(_SYSCALL32_IMPL)
 414  415          int nobase;
 415  416          struct modinfo32 modi32;
 416  417  #endif
 417  418  
 418  419          nobase = 0;
 419  420          if (get_udatamodel() == DATAMODEL_NATIVE) {
 420  421                  if (copyin(umodi, &modi, sizeof (struct modinfo)) != 0)
 421  422                          return (EFAULT);
 422  423          }
 423  424  #ifdef _SYSCALL32_IMPL
 424  425          else {
 425  426                  bzero(&modi, sizeof (modi));
 426  427                  if (copyin(umodi, &modi32, sizeof (struct modinfo32)) != 0)
 427  428                          return (EFAULT);
 428  429                  modi.mi_info = modi32.mi_info;
 429  430                  modi.mi_id = modi32.mi_id;
 430  431                  modi.mi_nextid = modi32.mi_nextid;
 431  432                  nobase = modi.mi_info & MI_INFO_NOBASE;
 432  433          }
 433  434  #endif
 434  435          /*
 435  436           * This flag is -only- for the kernels use.
 436  437           */
 437  438          modi.mi_info &= ~MI_INFO_LINKAGE;
 438  439  
 439  440          retval = modinfo(id, &modi);
 440  441          if (retval)
 441  442                  return (retval);
 442  443  
 443  444          if (get_udatamodel() == DATAMODEL_NATIVE) {
 444  445                  if (copyout(&modi, umodi, sizeof (struct modinfo)) != 0)
 445  446                          retval = EFAULT;
 446  447  #ifdef _SYSCALL32_IMPL
 447  448          } else {
 448  449                  int i;
 449  450  
 450  451                  if (!nobase && (uintptr_t)modi.mi_base > UINT32_MAX)
 451  452                          return (EOVERFLOW);
 452  453  
 453  454                  modi32.mi_info = modi.mi_info;
 454  455                  modi32.mi_state = modi.mi_state;
 455  456                  modi32.mi_id = modi.mi_id;
 456  457                  modi32.mi_nextid = modi.mi_nextid;
 457  458                  modi32.mi_base = (caddr32_t)(uintptr_t)modi.mi_base;
 458  459                  modi32.mi_size = modi.mi_size;
 459  460                  modi32.mi_rev = modi.mi_rev;
 460  461                  modi32.mi_loadcnt = modi.mi_loadcnt;
 461  462                  bcopy(modi.mi_name, modi32.mi_name, sizeof (modi32.mi_name));
 462  463                  for (i = 0; i < MODMAXLINK32; i++) {
 463  464                          modi32.mi_msinfo[i].msi_p0 = modi.mi_msinfo[i].msi_p0;
 464  465                          bcopy(modi.mi_msinfo[i].msi_linkinfo,
 465  466                              modi32.mi_msinfo[i].msi_linkinfo,
 466  467                              sizeof (modi32.mi_msinfo[0].msi_linkinfo));
 467  468                  }
 468  469                  if (copyout(&modi32, umodi, sizeof (struct modinfo32)) != 0)
 469  470                          retval = EFAULT;
 470  471  #endif
 471  472          }
 472  473  
 473  474          return (retval);
 474  475  }
 475  476  
 476  477  /*
 477  478   * Return the last major number in the range of permissible major numbers.
 478  479   */
 479  480  /*ARGSUSED*/
 480  481  static int
 481  482  modctl_modreserve(modid_t id, int *data)
 482  483  {
 483  484          if (copyout(&devcnt, data, sizeof (devcnt)) != 0)
 484  485                  return (EFAULT);
 485  486          return (0);
 486  487  }
 487  488  
 488  489  /* Add/Remove driver and binding aliases */
 489  490  static int
 490  491  modctl_update_driver_aliases(int add, int *data)
 491  492  {
 492  493          struct modconfig        mc;
 493  494          int                     i, n, rv = 0;
 494  495          struct aliases          alias;
 495  496          struct aliases          *ap;
 496  497          char                    name[MAXMODCONFNAME];
 497  498          char                    cname[MAXMODCONFNAME];
 498  499          char                    *drvname;
 499  500          int                     resid;
 500  501          struct alias_info {
 501  502                  char    *alias_name;
 502  503                  int     alias_resid;
 503  504          } *aliases, *aip;
 504  505  
 505  506          aliases = NULL;
 506  507          bzero(&mc, sizeof (struct modconfig));
 507  508          if (get_udatamodel() == DATAMODEL_NATIVE) {
 508  509                  if (copyin(data, &mc, sizeof (struct modconfig)) != 0)
 509  510                          return (EFAULT);
 510  511          }
 511  512  #ifdef _SYSCALL32_IMPL
 512  513          else {
 513  514                  struct modconfig32 modc32;
 514  515                  if (copyin(data, &modc32, sizeof (struct modconfig32)) != 0)
 515  516                          return (EFAULT);
 516  517                  else {
 517  518                          bcopy(modc32.drvname, mc.drvname,
 518  519                              sizeof (modc32.drvname));
 519  520                          bcopy(modc32.drvclass, mc.drvclass,
 520  521                              sizeof (modc32.drvclass));
 521  522                          mc.major = modc32.major;
 522  523                          mc.flags = modc32.flags;
 523  524                          mc.num_aliases = modc32.num_aliases;
 524  525                          mc.ap = (struct aliases *)(uintptr_t)modc32.ap;
 525  526                  }
 526  527          }
 527  528  #endif
 528  529  
 529  530          /*
 530  531           * If the driver is already in the mb_hashtab, and the name given
 531  532           * doesn't match that driver's name, fail.  Otherwise, pass, since
 532  533           * we may be adding aliases.
 533  534           */
 534  535          drvname = mod_major_to_name(mc.major);
 535  536          if ((drvname != NULL) && strcmp(drvname, mc.drvname) != 0)
 536  537                  return (EINVAL);
 537  538  
 538  539          /*
 539  540           * Precede alias removal by unbinding as many devices as possible.
 540  541           */
 541  542          if (add == 0) {
 542  543                  (void) i_ddi_unload_drvconf(mc.major);
 543  544                  i_ddi_unbind_devs(mc.major);
 544  545          }
 545  546  
 546  547          /*
 547  548           * Add/remove each supplied driver alias to/from mb_hashtab
 548  549           */
 549  550          ap = mc.ap;
 550  551          if (mc.num_aliases > 0)
 551  552                  aliases = kmem_zalloc(
 552  553                      mc.num_aliases * sizeof (struct alias_info), KM_SLEEP);
 553  554          aip = aliases;
 554  555          for (i = 0; i < mc.num_aliases; i++) {
 555  556                  bzero(&alias, sizeof (struct aliases));
 556  557                  if (get_udatamodel() == DATAMODEL_NATIVE) {
 557  558                          if (copyin(ap, &alias, sizeof (struct aliases)) != 0) {
 558  559                                  rv = EFAULT;
 559  560                                  goto error;
 560  561                          }
 561  562                          if (alias.a_len > MAXMODCONFNAME) {
 562  563                                  rv = EINVAL;
 563  564                                  goto error;
 564  565                          }
 565  566                          if (copyin(alias.a_name, name, alias.a_len) != 0) {
 566  567                                  rv = EFAULT;
 567  568                                  goto error;
 568  569                          }
 569  570                          if (name[alias.a_len - 1] != '\0') {
 570  571                                  rv = EINVAL;
 571  572                                  goto error;
 572  573                          }
 573  574                  }
 574  575  #ifdef _SYSCALL32_IMPL
 575  576                  else {
 576  577                          struct aliases32 al32;
 577  578                          bzero(&al32, sizeof (struct aliases32));
 578  579                          if (copyin(ap, &al32, sizeof (struct aliases32)) != 0) {
 579  580                                  rv = EFAULT;
 580  581                                  goto error;
 581  582                          }
 582  583                          if (al32.a_len > MAXMODCONFNAME) {
 583  584                                  rv = EINVAL;
 584  585                                  goto error;
 585  586                          }
 586  587                          if (copyin((void *)(uintptr_t)al32.a_name,
 587  588                              name, al32.a_len) != 0) {
 588  589                                  rv = EFAULT;
 589  590                                  goto error;
 590  591                          }
 591  592                          if (name[al32.a_len - 1] != '\0') {
 592  593                                  rv = EINVAL;
 593  594                                  goto error;
 594  595                          }
 595  596                          alias.a_next = (void *)(uintptr_t)al32.a_next;
 596  597                  }
 597  598  #endif
 598  599                  check_esc_sequences(name, cname);
 599  600                  aip->alias_name = strdup(cname);
 600  601                  ap = alias.a_next;
 601  602                  aip++;
 602  603          }
 603  604  
 604  605          if (add == 0) {
 605  606                  ap = mc.ap;
 606  607                  resid = 0;
 607  608                  aip = aliases;
 608  609                  /* attempt to unbind all devices bound to each alias */
 609  610                  for (i = 0; i < mc.num_aliases; i++) {
 610  611                          n = i_ddi_unbind_devs_by_alias(
 611  612                              mc.major, aip->alias_name);
 612  613                          resid += n;
 613  614                          aip->alias_resid = n;
 614  615                  }
 615  616  
 616  617                  /*
 617  618                   * If some device bound to an alias remains in use,
 618  619                   * and override wasn't specified, no change is made to
 619  620                   * the binding state and we fail the operation.
 620  621                   */
 621  622                  if (resid > 0 && ((mc.flags & MOD_UNBIND_OVERRIDE) == 0)) {
 622  623                          rv = EBUSY;
 623  624                          goto error;
 624  625                  }
 625  626  
 626  627                  /*
 627  628                   * No device remains bound of any of the aliases,
 628  629                   * or force was requested.  Mark each alias as
 629  630                   * inactive via delete_mbind so no future binds
 630  631                   * to this alias take place and that a new
 631  632                   * binding can be established.
 632  633                   */
 633  634                  aip = aliases;
 634  635                  for (i = 0; i < mc.num_aliases; i++) {
 635  636                          if (moddebug & MODDEBUG_BINDING)
 636  637                                  cmn_err(CE_CONT, "Removing binding for %s "
 637  638                                      "(%d active references)\n",
 638  639                                      aip->alias_name, aip->alias_resid);
 639  640                          delete_mbind(aip->alias_name, mb_hashtab);
 640  641                          aip++;
 641  642                  }
 642  643                  rv = 0;
 643  644          } else {
 644  645                  aip = aliases;
 645  646                  for (i = 0; i < mc.num_aliases; i++) {
 646  647                          if (moddebug & MODDEBUG_BINDING)
 647  648                                  cmn_err(CE_NOTE, "Adding binding for '%s'\n",
 648  649                                      aip->alias_name);
 649  650                          (void) make_mbind(aip->alias_name,
 650  651                              mc.major, NULL, mb_hashtab);
 651  652                          aip++;
 652  653                  }
 653  654                  /*
 654  655                   * Try to establish an mbinding for mc.drvname, and add it to
 655  656                   * devnames. Add class if any after establishing the major
 656  657                   * number.
 657  658                   */
 658  659                  (void) make_mbind(mc.drvname, mc.major, NULL, mb_hashtab);
 659  660                  if ((rv = make_devname(mc.drvname, mc.major,
 660  661                      (mc.flags & MOD_ADDMAJBIND_UPDATE) ?
 661  662                      DN_DRIVER_INACTIVE : 0)) != 0) {
 662  663                          goto error;
 663  664                  }
 664  665  
 665  666                  if (mc.drvclass[0] != '\0')
 666  667                          add_class(mc.drvname, mc.drvclass);
 667  668                  if ((mc.flags & MOD_ADDMAJBIND_UPDATE) == 0) {
 668  669                          (void) i_ddi_load_drvconf(mc.major);
 669  670                  }
 670  671          }
 671  672  
 672  673          /*
 673  674           * Ensure that all nodes are bound to the most appropriate driver
 674  675           * possible, attempting demotion and rebind when a more appropriate
 675  676           * driver now exists.  But not when adding a driver update-only.
 676  677           */
 677  678          if ((add == 0) || ((mc.flags & MOD_ADDMAJBIND_UPDATE) == 0)) {
 678  679                  i_ddi_bind_devs();
 679  680                  i_ddi_di_cache_invalidate();
 680  681          }
 681  682  
 682  683  error:
 683  684          if (mc.num_aliases > 0) {
 684  685                  aip = aliases;
 685  686                  for (i = 0; i < mc.num_aliases; i++) {
 686  687                          if (aip->alias_name != NULL)
 687  688                                  strfree(aip->alias_name);
 688  689                          aip++;
 689  690                  }
 690  691                  kmem_free(aliases, mc.num_aliases * sizeof (struct alias_info));
 691  692          }
 692  693          return (rv);
 693  694  }
 694  695  
 695  696  static int
 696  697  modctl_add_driver_aliases(int *data)
 697  698  {
 698  699          return (modctl_update_driver_aliases(1, data));
 699  700  }
 700  701  
 701  702  static int
 702  703  modctl_remove_driver_aliases(int *data)
 703  704  {
 704  705          return (modctl_update_driver_aliases(0, data));
 705  706  }
 706  707  
 707  708  static int
 708  709  modctl_rem_major(major_t major)
 709  710  {
 710  711          struct devnames *dnp;
 711  712  
 712  713          if (major >= devcnt)
 713  714                  return (EINVAL);
 714  715  
 715  716          /* mark devnames as removed */
 716  717          dnp = &devnamesp[major];
 717  718          LOCK_DEV_OPS(&dnp->dn_lock);
 718  719          if (dnp->dn_name == NULL ||
 719  720              (dnp->dn_flags & (DN_DRIVER_REMOVED | DN_TAKEN_GETUDEV))) {
 720  721                  UNLOCK_DEV_OPS(&dnp->dn_lock);
 721  722                  return (EINVAL);
 722  723          }
 723  724          dnp->dn_flags |= DN_DRIVER_REMOVED;
 724  725          pm_driver_removed(major);
 725  726          UNLOCK_DEV_OPS(&dnp->dn_lock);
 726  727  
 727  728          (void) i_ddi_unload_drvconf(major);
 728  729          i_ddi_unbind_devs(major);
 729  730          i_ddi_bind_devs();
 730  731          i_ddi_di_cache_invalidate();
 731  732  
 732  733          /* purge all the bindings to this driver */
 733  734          purge_mbind(major, mb_hashtab);
 734  735          return (0);
 735  736  }
 736  737  
 737  738  static struct vfs *
 738  739  path_to_vfs(char *name)
 739  740  {
 740  741          vnode_t *vp;
 741  742          struct vfs *vfsp;
 742  743  
 743  744          if (lookupname(name, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp))
 744  745                  return (NULL);
 745  746  
 746  747          vfsp = vp->v_vfsp;
 747  748          VN_RELE(vp);
 748  749          return (vfsp);
 749  750  }
 750  751  
 751  752  static int
 752  753  new_vfs_in_modpath()
 753  754  {
 754  755          static int n_modpath = 0;
 755  756          static char *modpath_copy;
 756  757          static struct pathvfs {
 757  758                  char *path;
 758  759                  struct vfs *vfsp;
 759  760          } *pathvfs;
 760  761  
 761  762          int i, new_vfs = 0;
 762  763          char *tmp, *tmp1;
 763  764          struct vfs *vfsp;
 764  765  
 765  766          if (n_modpath != 0) {
 766  767                  for (i = 0; i < n_modpath; i++) {
 767  768                          vfsp = path_to_vfs(pathvfs[i].path);
 768  769                          if (vfsp != pathvfs[i].vfsp) {
 769  770                                  pathvfs[i].vfsp = vfsp;
 770  771                                  if (vfsp)
 771  772                                          new_vfs = 1;
 772  773                          }
 773  774                  }
 774  775                  return (new_vfs);
 775  776          }
 776  777  
 777  778          /*
 778  779           * First call, initialize the pathvfs structure
 779  780           */
 780  781          modpath_copy = i_ddi_strdup(default_path, KM_SLEEP);
 781  782          tmp = modpath_copy;
 782  783          n_modpath = 1;
 783  784          tmp1 = strchr(tmp, ' ');
 784  785          while (tmp1) {
 785  786                  *tmp1 = '\0';
 786  787                  n_modpath++;
 787  788                  tmp = tmp1 + 1;
 788  789                  tmp1 = strchr(tmp, ' ');
 789  790          }
 790  791  
 791  792          pathvfs = kmem_zalloc(n_modpath * sizeof (struct pathvfs), KM_SLEEP);
 792  793          tmp = modpath_copy;
 793  794          for (i = 0; i < n_modpath; i++) {
 794  795                  pathvfs[i].path = tmp;
 795  796                  vfsp = path_to_vfs(tmp);
 796  797                  pathvfs[i].vfsp = vfsp;
 797  798                  tmp += strlen(tmp) + 1;
 798  799          }
 799  800          return (1);     /* always reread driver.conf the first time */
 800  801  }
 801  802  
 802  803  static int
 803  804  modctl_load_drvconf(major_t major, int flags)
 804  805  {
 805  806          int ret;
 806  807  
 807  808          /*
 808  809           * devfsadm -u - read all new driver.conf files
 809  810           * and bind and configure devices for new drivers.
 810  811           */
 811  812          if (flags & MOD_LOADDRVCONF_RECONF) {
 812  813                  (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE);
 813  814                  i_ddi_bind_devs();
 814  815                  i_ddi_di_cache_invalidate();
 815  816                  return (0);
 816  817          }
 817  818  
 818  819          /*
 819  820           * update_drv <drv> - reload driver.conf for the specified driver
 820  821           */
 821  822          if (major != DDI_MAJOR_T_NONE) {
 822  823                  ret = i_ddi_load_drvconf(major);
 823  824                  if (ret == 0)
 824  825                          i_ddi_bind_devs();
 825  826                  return (ret);
 826  827          }
 827  828  
 828  829          /*
 829  830           * We are invoked to rescan new driver.conf files. It is
 830  831           * only necessary if a new file system was mounted in the
 831  832           * module_path. Because rescanning driver.conf files can
 832  833           * take some time on older platforms (sun4m), the following
 833  834           * code skips unnecessary driver.conf rescans to optimize
 834  835           * boot performance.
 835  836           */
 836  837          if (new_vfs_in_modpath()) {
 837  838                  (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE);
 838  839                  /*
 839  840                   * If we are still initializing io subsystem,
 840  841                   * load drivers with ddi-forceattach property
 841  842                   */
 842  843                  if (!i_ddi_io_initialized())
 843  844                          i_ddi_forceattach_drivers();
 844  845          }
 845  846          return (0);
 846  847  }
 847  848  
 848  849  /*
 849  850   * Unload driver.conf file and follow up by attempting
 850  851   * to rebind devices to more appropriate driver.
 851  852   */
 852  853  static int
 853  854  modctl_unload_drvconf(major_t major)
 854  855  {
 855  856          int ret;
 856  857  
 857  858          if (major >= devcnt)
 858  859                  return (EINVAL);
 859  860  
 860  861          ret = i_ddi_unload_drvconf(major);
 861  862          if (ret != 0)
 862  863                  return (ret);
 863  864          (void) i_ddi_unbind_devs(major);
 864  865          i_ddi_bind_devs();
 865  866  
 866  867          return (0);
 867  868  }
 868  869  
 869  870  static void
 870  871  check_esc_sequences(char *str, char *cstr)
 871  872  {
 872  873          int i;
 873  874          size_t len;
 874  875          char *p;
 875  876  
 876  877          len = strlen(str);
 877  878          for (i = 0; i < len; i++, str++, cstr++) {
 878  879                  if (*str != '\\') {
 879  880                          *cstr = *str;
 880  881                  } else {
 881  882                          p = str + 1;
 882  883                          /*
 883  884                           * we only handle octal escape sequences for SPACE
 884  885                           */
 885  886                          if (*p++ == '0' && *p++ == '4' && *p == '0') {
 886  887                                  *cstr = ' ';
 887  888                                  str += 3;
 888  889                          } else {
 889  890                                  *cstr = *str;
 890  891                          }
 891  892                  }
 892  893          }
 893  894          *cstr = 0;
 894  895  }
 895  896  
 896  897  static int
 897  898  modctl_getmodpathlen(int *data)
 898  899  {
 899  900          int len;
 900  901          len = strlen(default_path);
 901  902          if (copyout(&len, data, sizeof (len)) != 0)
 902  903                  return (EFAULT);
 903  904          return (0);
 904  905  }
 905  906  
 906  907  static int
 907  908  modctl_getmodpath(char *data)
 908  909  {
 909  910          if (copyout(default_path, data, strlen(default_path) + 1) != 0)
 910  911                  return (EFAULT);
 911  912          return (0);
 912  913  }
 913  914  
 914  915  static int
 915  916  modctl_read_sysbinding_file(void)
 916  917  {
 917  918          (void) read_binding_file(sysbind, sb_hashtab, make_mbind);
 918  919          return (0);
 919  920  }
 920  921  
 921  922  static int
 922  923  modctl_getmaj(char *uname, uint_t ulen, int *umajorp)
 923  924  {
 924  925          char name[256];
 925  926          int retval;
 926  927          major_t major;
 927  928  
 928  929          if (ulen == 0)
 929  930                  return (EINVAL);
 930  931          if ((retval = copyinstr(uname, name,
 931  932              (ulen < 256) ? ulen : 256, 0)) != 0)
 932  933                  return (retval);
 933  934          if ((major = mod_name_to_major(name)) == DDI_MAJOR_T_NONE)
 934  935                  return (ENODEV);
 935  936          if (copyout(&major, umajorp, sizeof (major_t)) != 0)
 936  937                  return (EFAULT);
 937  938          return (0);
 938  939  }
 939  940  
 940  941  static char **
 941  942  convert_constraint_string(char *constraints, size_t len)
 942  943  {
 943  944          int     i;
 944  945          int     n;
 945  946          char    *p;
 946  947          char    **array;
 947  948  
 948  949          ASSERT(constraints != NULL);
 949  950          ASSERT(len > 0);
 950  951  
 951  952          for (i = 0, p = constraints; strlen(p) > 0; i++, p += strlen(p) + 1)
 952  953                  ;
 953  954  
 954  955          n = i;
 955  956  
 956  957          if (n == 0) {
 957  958                  kmem_free(constraints, len);
 958  959                  return (NULL);
 959  960          }
 960  961  
 961  962          array = kmem_alloc((n + 1) * sizeof (char *), KM_SLEEP);
 962  963  
 963  964          for (i = 0, p = constraints; i < n; i++, p += strlen(p) + 1) {
 964  965                  array[i] = i_ddi_strdup(p, KM_SLEEP);
 965  966          }
 966  967          array[n] = NULL;
 967  968  
 968  969          kmem_free(constraints, len);
 969  970  
 970  971          return (array);
 971  972  }
 972  973  /*ARGSUSED*/
 973  974  static int
 974  975  modctl_retire(char *path, char *uconstraints, size_t ulen)
 975  976  {
 976  977          char    *pathbuf;
 977  978          char    *devpath;
 978  979          size_t  pathsz;
 979  980          int     retval;
 980  981          char    *constraints;
 981  982          char    **cons_array;
 982  983  
 983  984          if (path == NULL)
 984  985                  return (EINVAL);
 985  986  
 986  987          if ((uconstraints == NULL) ^ (ulen == 0))
 987  988                  return (EINVAL);
 988  989  
 989  990          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 990  991          retval = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
 991  992          if (retval != 0) {
 992  993                  kmem_free(pathbuf, MAXPATHLEN);
 993  994                  return (retval);
 994  995          }
 995  996          devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
 996  997          kmem_free(pathbuf, MAXPATHLEN);
 997  998  
 998  999          /*
 999 1000           * First check if the device is already retired.
1000 1001           * If it is, then persist the retire anyway, just in case the retire
1001 1002           * store has got out of sync with the boot archive.
1002 1003           */
1003 1004          if (e_ddi_device_retired(devpath)) {
1004 1005                  cmn_err(CE_NOTE, "Device: already retired: %s", devpath);
1005 1006                  (void) e_ddi_retire_persist(devpath);
1006 1007                  kmem_free(devpath, strlen(devpath) + 1);
1007 1008                  return (0);
1008 1009          }
1009 1010  
1010 1011          cons_array = NULL;
1011 1012          if (uconstraints) {
1012 1013                  constraints = kmem_alloc(ulen, KM_SLEEP);
1013 1014                  if (copyin(uconstraints, constraints, ulen)) {
1014 1015                          kmem_free(constraints, ulen);
1015 1016                          kmem_free(devpath, strlen(devpath) + 1);
1016 1017                          return (EFAULT);
1017 1018                  }
1018 1019                  cons_array = convert_constraint_string(constraints, ulen);
1019 1020          }
1020 1021  
1021 1022          /*
1022 1023           * Try to retire the device first. The following
1023 1024           * routine will return an error only if the device
1024 1025           * is not retireable i.e. retire constraints forbid
1025 1026           * a retire. A return of success from this routine
1026 1027           * indicates that device is retireable.
1027 1028           */
1028 1029          retval = e_ddi_retire_device(devpath, cons_array);
1029 1030          if (retval != DDI_SUCCESS) {
1030 1031                  cmn_err(CE_WARN, "constraints forbid retire: %s", devpath);
1031 1032                  kmem_free(devpath, strlen(devpath) + 1);
1032 1033                  return (ENOTSUP);
1033 1034          }
1034 1035  
1035 1036          /*
1036 1037           * Ok, the retire succeeded. Persist the retire.
1037 1038           * If retiring a nexus, we need to only persist the
1038 1039           * nexus retire. Any children of a retired nexus
1039 1040           * are automatically covered by the retire store
1040 1041           * code.
1041 1042           */
1042 1043          retval = e_ddi_retire_persist(devpath);
1043 1044          if (retval != 0) {
1044 1045                  cmn_err(CE_WARN, "Failed to persist device retire: error %d: "
1045 1046                      "%s", retval, devpath);
1046 1047                  kmem_free(devpath, strlen(devpath) + 1);
1047 1048                  return (retval);
1048 1049          }
1049 1050          if (moddebug & MODDEBUG_RETIRE)
1050 1051                  cmn_err(CE_NOTE, "Persisted retire of device: %s", devpath);
1051 1052  
1052 1053          kmem_free(devpath, strlen(devpath) + 1);
1053 1054          return (0);
1054 1055  }
1055 1056  
1056 1057  static int
1057 1058  modctl_is_retired(char *path, int *statep)
1058 1059  {
1059 1060          char    *pathbuf;
1060 1061          char    *devpath;
1061 1062          size_t  pathsz;
1062 1063          int     error;
1063 1064          int     status;
1064 1065  
1065 1066          if (path == NULL || statep == NULL)
1066 1067                  return (EINVAL);
1067 1068  
1068 1069          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1069 1070          error = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
1070 1071          if (error != 0) {
1071 1072                  kmem_free(pathbuf, MAXPATHLEN);
1072 1073                  return (error);
1073 1074          }
1074 1075          devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
1075 1076          kmem_free(pathbuf, MAXPATHLEN);
1076 1077  
1077 1078          if (e_ddi_device_retired(devpath))
1078 1079                  status = 1;
1079 1080          else
1080 1081                  status = 0;
1081 1082          kmem_free(devpath, strlen(devpath) + 1);
1082 1083  
1083 1084          return (copyout(&status, statep, sizeof (status)) ? EFAULT : 0);
1084 1085  }
1085 1086  
1086 1087  static int
1087 1088  modctl_unretire(char *path)
1088 1089  {
1089 1090          char    *pathbuf;
1090 1091          char    *devpath;
1091 1092          size_t  pathsz;
1092 1093          int     retired;
1093 1094          int     retval;
1094 1095  
1095 1096          if (path == NULL)
1096 1097                  return (EINVAL);
1097 1098  
1098 1099          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1099 1100          retval = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
1100 1101          if (retval != 0) {
1101 1102                  kmem_free(pathbuf, MAXPATHLEN);
1102 1103                  return (retval);
1103 1104          }
1104 1105          devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
1105 1106          kmem_free(pathbuf, MAXPATHLEN);
1106 1107  
1107 1108          /*
1108 1109           * We check if a device is retired (first) before
1109 1110           * unpersisting the retire, because we use the
1110 1111           * retire store to determine if a device is retired.
1111 1112           * If we unpersist first, the device will always appear
1112 1113           * to be unretired. For the rationale behind unpersisting
1113 1114           * a device that is not retired, see the next comment.
1114 1115           */
1115 1116          retired = e_ddi_device_retired(devpath);
1116 1117  
1117 1118          /*
1118 1119           * We call unpersist unconditionally because the lookup
1119 1120           * for retired devices (e_ddi_device_retired()), skips "bypassed"
1120 1121           * devices. We still want to be able remove "bypassed" entries
1121 1122           * from the persistent store, so we unpersist unconditionally
1122 1123           * i.e. whether or not the entry is found on a lookup.
1123 1124           *
1124 1125           * e_ddi_retire_unpersist() returns 1 if it found and cleared
1125 1126           * an entry from the retire store or 0 otherwise.
1126 1127           */
1127 1128          if (e_ddi_retire_unpersist(devpath))
1128 1129                  if (moddebug & MODDEBUG_RETIRE) {
1129 1130                          cmn_err(CE_NOTE, "Unpersisted retire of device: %s",
1130 1131                              devpath);
1131 1132                  }
1132 1133  
1133 1134          /*
1134 1135           * Check if the device is already unretired. If so,
1135 1136           * the unretire becomes a NOP
1136 1137           */
1137 1138          if (!retired) {
1138 1139                  cmn_err(CE_NOTE, "Not retired: %s", devpath);
1139 1140                  kmem_free(devpath, strlen(devpath) + 1);
1140 1141                  return (0);
1141 1142          }
1142 1143  
1143 1144          retval = e_ddi_unretire_device(devpath);
1144 1145          if (retval != 0) {
1145 1146                  cmn_err(CE_WARN, "cannot unretire device: error %d, path %s\n",
1146 1147                      retval, devpath);
1147 1148          }
1148 1149  
1149 1150          kmem_free(devpath, strlen(devpath) + 1);
1150 1151  
1151 1152          return (retval);
1152 1153  }
1153 1154  
1154 1155  static int
1155 1156  modctl_getname(char *uname, uint_t ulen, int *umajorp)
1156 1157  {
1157 1158          char *name;
1158 1159          major_t major;
1159 1160  
1160 1161          if (copyin(umajorp, &major, sizeof (major)) != 0)
1161 1162                  return (EFAULT);
1162 1163          if ((name = mod_major_to_name(major)) == NULL)
1163 1164                  return (ENODEV);
1164 1165          if ((strlen(name) + 1) > ulen)
1165 1166                  return (ENOSPC);
1166 1167          return (copyoutstr(name, uname, ulen, NULL));
1167 1168  }
1168 1169  
1169 1170  static int
1170 1171  modctl_devt2instance(dev_t dev, int *uinstancep)
1171 1172  {
1172 1173          int     instance;
1173 1174  
1174 1175          if ((instance = dev_to_instance(dev)) == -1)
1175 1176                  return (EINVAL);
1176 1177  
1177 1178          return (copyout(&instance, uinstancep, sizeof (int)));
1178 1179  }
1179 1180  
1180 1181  /*
1181 1182   * Return the sizeof of the device id.
1182 1183   */
1183 1184  static int
1184 1185  modctl_sizeof_devid(dev_t dev, uint_t *len)
1185 1186  {
1186 1187          uint_t          sz;
1187 1188          ddi_devid_t     devid;
1188 1189  
1189 1190          /* get device id */
1190 1191          if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE)
1191 1192                  return (EINVAL);
1192 1193  
1193 1194          sz = ddi_devid_sizeof(devid);
1194 1195          ddi_devid_free(devid);
1195 1196  
1196 1197          /* copyout device id size */
1197 1198          if (copyout(&sz, len, sizeof (sz)) != 0)
1198 1199                  return (EFAULT);
1199 1200  
1200 1201          return (0);
1201 1202  }
1202 1203  
1203 1204  /*
1204 1205   * Return a copy of the device id.
1205 1206   */
1206 1207  static int
1207 1208  modctl_get_devid(dev_t dev, uint_t len, ddi_devid_t udevid)
1208 1209  {
1209 1210          uint_t          sz;
1210 1211          ddi_devid_t     devid;
1211 1212          int             err = 0;
1212 1213  
1213 1214          /* get device id */
1214 1215          if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE)
1215 1216                  return (EINVAL);
1216 1217  
1217 1218          sz = ddi_devid_sizeof(devid);
1218 1219  
1219 1220          /* Error if device id is larger than space allocated */
1220 1221          if (sz > len) {
1221 1222                  ddi_devid_free(devid);
1222 1223                  return (ENOSPC);
1223 1224          }
1224 1225  
1225 1226          /* copy out device id */
1226 1227          if (copyout(devid, udevid, sz) != 0)
1227 1228                  err = EFAULT;
1228 1229          ddi_devid_free(devid);
1229 1230          return (err);
1230 1231  }
1231 1232  
1232 1233  /*
1233 1234   * return the /devices paths associated with the specified devid and
1234 1235   * minor name.
1235 1236   */
1236 1237  /*ARGSUSED*/
1237 1238  static int
1238 1239  modctl_devid2paths(ddi_devid_t udevid, char *uminor_name, uint_t flag,
1239 1240      size_t *ulensp, char *upaths)
1240 1241  {
1241 1242          ddi_devid_t     devid = NULL;
1242 1243          int             devid_len;
1243 1244          char            *minor_name = NULL;
1244 1245          dev_info_t      *dip = NULL;
1245 1246          int             circ;
1246 1247          struct ddi_minor_data   *dmdp;
1247 1248          char            *path = NULL;
1248 1249          int             ulens;
1249 1250          int             lens;
1250 1251          int             len;
1251 1252          dev_t           *devlist = NULL;
1252 1253          int             ndevs;
1253 1254          int             i;
1254 1255          int             ret = 0;
1255 1256  
1256 1257          /*
1257 1258           * If upaths is NULL then we are only computing the amount of space
1258 1259           * needed to hold the paths and returning the value in *ulensp. If we
1259 1260           * are copying out paths then we get the amount of space allocated by
1260 1261           * the caller. If the actual space needed for paths is larger, or
1261 1262           * things are changing out from under us, then we return EAGAIN.
1262 1263           */
1263 1264          if (upaths) {
1264 1265                  if (ulensp == NULL)
1265 1266                          return (EINVAL);
1266 1267                  if (copyin(ulensp, &ulens, sizeof (ulens)) != 0)
1267 1268                          return (EFAULT);
1268 1269          }
1269 1270  
1270 1271          /*
1271 1272           * copyin enough of the devid to determine the length then
1272 1273           * reallocate and copy in the entire devid.
1273 1274           */
1274 1275          devid_len = ddi_devid_sizeof(NULL);
1275 1276          devid = kmem_alloc(devid_len, KM_SLEEP);
1276 1277          if (copyin(udevid, devid, devid_len)) {
1277 1278                  ret = EFAULT;
1278 1279                  goto out;
1279 1280          }
1280 1281          len = devid_len;
1281 1282          devid_len = ddi_devid_sizeof(devid);
1282 1283          kmem_free(devid, len);
1283 1284          devid = kmem_alloc(devid_len, KM_SLEEP);
1284 1285          if (copyin(udevid, devid, devid_len)) {
1285 1286                  ret = EFAULT;
1286 1287                  goto out;
1287 1288          }
1288 1289  
1289 1290          /* copyin the minor name if specified. */
1290 1291          minor_name = uminor_name;
1291 1292          if ((minor_name != DEVID_MINOR_NAME_ALL) &&
1292 1293              (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1293 1294              (minor_name != DEVID_MINOR_NAME_ALL_BLK)) {
1294 1295                  minor_name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1295 1296                  if (copyinstr(uminor_name, minor_name, MAXPATHLEN, 0)) {
1296 1297                          ret = EFAULT;
1297 1298                          goto out;
1298 1299                  }
1299 1300          }
1300 1301  
1301 1302          /*
1302 1303           * Use existing function to resolve the devid into a devlist.
1303 1304           *
1304 1305           * NOTE: there is a loss of spectype information in the current
1305 1306           * ddi_lyr_devid_to_devlist implementation. We work around this by not
1306 1307           * passing down DEVID_MINOR_NAME_ALL here, but reproducing all minor
1307 1308           * node forms in the loop processing the devlist below. It would be
1308 1309           * best if at some point the use of this interface here was replaced
1309 1310           * with a path oriented call.
1310 1311           */
1311 1312          if (ddi_lyr_devid_to_devlist(devid,
1312 1313              (minor_name == DEVID_MINOR_NAME_ALL) ?
1313 1314              DEVID_MINOR_NAME_ALL_CHR : minor_name,
1314 1315              &ndevs, &devlist) != DDI_SUCCESS) {
1315 1316                  ret = EINVAL;
1316 1317                  goto out;
1317 1318          }
1318 1319  
1319 1320          /*
1320 1321           * loop over the devlist, converting each devt to a path and doing
1321 1322           * a copyout of the path and computation of the amount of space
1322 1323           * needed to hold all the paths
1323 1324           */
1324 1325          path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1325 1326          for (i = 0, lens = 0; i < ndevs; i++) {
1326 1327  
1327 1328                  /* find the dip associated with the dev_t */
1328 1329                  if ((dip = e_ddi_hold_devi_by_dev(devlist[i], 0)) == NULL)
1329 1330                          continue;
1330 1331  
1331 1332                  /* loop over all the minor nodes, skipping ones we don't want */
1332 1333                  ndi_devi_enter(dip, &circ);
1333 1334                  for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
1334 1335                          if ((dmdp->ddm_dev != devlist[i]) ||
1335 1336                              (dmdp->type != DDM_MINOR))
1336 1337                                  continue;
1337 1338  
1338 1339                          if ((minor_name != DEVID_MINOR_NAME_ALL) &&
1339 1340                              (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1340 1341                              (minor_name != DEVID_MINOR_NAME_ALL_BLK) &&
1341 1342                              strcmp(minor_name, dmdp->ddm_name))
1342 1343                                  continue;
1343 1344                          else {
1344 1345                                  if ((minor_name == DEVID_MINOR_NAME_ALL_CHR) &&
1345 1346                                      (dmdp->ddm_spec_type != S_IFCHR))
1346 1347                                          continue;
1347 1348                                  if ((minor_name == DEVID_MINOR_NAME_ALL_BLK) &&
1348 1349                                      (dmdp->ddm_spec_type != S_IFBLK))
1349 1350                                          continue;
1350 1351                          }
1351 1352  
1352 1353                          (void) ddi_pathname_minor(dmdp, path);
1353 1354                          len = strlen(path) + 1;
1354 1355                          *(path + len) = '\0';   /* set double termination */
1355 1356                          lens += len;
1356 1357  
1357 1358                          /* copyout the path with double terminations */
1358 1359                          if (upaths) {
1359 1360                                  if (lens > ulens) {
1360 1361                                          ret = EAGAIN;
1361 1362                                          goto out;
1362 1363                                  }
1363 1364                                  if (copyout(path, upaths, len + 1)) {
1364 1365                                          ret = EFAULT;
1365 1366                                          goto out;
1366 1367                                  }
1367 1368                                  upaths += len;
1368 1369                          }
1369 1370                  }
1370 1371                  ndi_devi_exit(dip, circ);
1371 1372                  ddi_release_devi(dip);
1372 1373                  dip = NULL;
1373 1374          }
1374 1375          lens++;         /* add one for double termination */
1375 1376  
1376 1377          /* copy out the amount of space needed to hold the paths */
1377 1378          if (ulensp && copyout(&lens, ulensp, sizeof (lens))) {
1378 1379                  ret = EFAULT;
1379 1380                  goto out;
1380 1381          }
1381 1382          ret = 0;
1382 1383  
1383 1384  out:    if (dip) {
1384 1385                  ndi_devi_exit(dip, circ);
1385 1386                  ddi_release_devi(dip);
1386 1387          }
1387 1388          if (path)
1388 1389                  kmem_free(path, MAXPATHLEN);
1389 1390          if (devlist)
1390 1391                  ddi_lyr_free_devlist(devlist, ndevs);
1391 1392          if (minor_name &&
1392 1393              (minor_name != DEVID_MINOR_NAME_ALL) &&
1393 1394              (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1394 1395              (minor_name != DEVID_MINOR_NAME_ALL_BLK))
1395 1396                  kmem_free(minor_name, MAXPATHLEN);
1396 1397          if (devid)
1397 1398                  kmem_free(devid, devid_len);
1398 1399          return (ret);
1399 1400  }
1400 1401  
1401 1402  /*
1402 1403   * Return the size of the minor name.
1403 1404   */
1404 1405  static int
1405 1406  modctl_sizeof_minorname(dev_t dev, int spectype, uint_t *len)
1406 1407  {
1407 1408          uint_t  sz;
1408 1409          char    *name;
1409 1410  
1410 1411          /* get the minor name */
1411 1412          if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE)
1412 1413                  return (EINVAL);
1413 1414  
1414 1415          sz = strlen(name) + 1;
1415 1416          kmem_free(name, sz);
1416 1417  
1417 1418          /* copy out the size of the minor name */
1418 1419          if (copyout(&sz, len, sizeof (sz)) != 0)
1419 1420                  return (EFAULT);
1420 1421  
1421 1422          return (0);
1422 1423  }
1423 1424  
1424 1425  /*
1425 1426   * Return the minor name.
1426 1427   */
1427 1428  static int
1428 1429  modctl_get_minorname(dev_t dev, int spectype, uint_t len, char *uname)
1429 1430  {
1430 1431          uint_t  sz;
1431 1432          char    *name;
1432 1433          int     err = 0;
1433 1434  
1434 1435          /* get the minor name */
1435 1436          if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE)
1436 1437                  return (EINVAL);
1437 1438  
1438 1439          sz = strlen(name) + 1;
1439 1440  
1440 1441          /* Error if the minor name is larger than the space allocated */
1441 1442          if (sz > len) {
1442 1443                  kmem_free(name, sz);
1443 1444                  return (ENOSPC);
1444 1445          }
1445 1446  
1446 1447          /* copy out the minor name */
1447 1448          if (copyout(name, uname, sz) != 0)
1448 1449                  err = EFAULT;
1449 1450          kmem_free(name, sz);
1450 1451          return (err);
1451 1452  }
1452 1453  
1453 1454  /*
1454 1455   * Return the size of the (dev_t,spectype) devfspath name.
1455 1456   */
1456 1457  static int
1457 1458  modctl_devfspath_len(dev_t dev, int spectype, uint_t *len)
1458 1459  {
1459 1460          uint_t  sz;
1460 1461          char    *name;
1461 1462  
1462 1463          /* get the path name */
1463 1464          name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1464 1465          if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) {
1465 1466                  kmem_free(name, MAXPATHLEN);
1466 1467                  return (EINVAL);
1467 1468          }
1468 1469  
1469 1470          sz = strlen(name) + 1;
1470 1471          kmem_free(name, MAXPATHLEN);
1471 1472  
1472 1473          /* copy out the size of the path name */
1473 1474          if (copyout(&sz, len, sizeof (sz)) != 0)
1474 1475                  return (EFAULT);
1475 1476  
1476 1477          return (0);
1477 1478  }
1478 1479  
1479 1480  /*
1480 1481   * Return the (dev_t,spectype) devfspath name.
1481 1482   */
1482 1483  static int
1483 1484  modctl_devfspath(dev_t dev, int spectype, uint_t len, char *uname)
1484 1485  {
1485 1486          uint_t  sz;
1486 1487          char    *name;
1487 1488          int     err = 0;
1488 1489  
1489 1490          /* get the path name */
1490 1491          name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1491 1492          if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) {
1492 1493                  kmem_free(name, MAXPATHLEN);
1493 1494                  return (EINVAL);
1494 1495          }
1495 1496  
1496 1497          sz = strlen(name) + 1;
1497 1498  
1498 1499          /* Error if the path name is larger than the space allocated */
1499 1500          if (sz > len) {
1500 1501                  kmem_free(name, MAXPATHLEN);
1501 1502                  return (ENOSPC);
1502 1503          }
1503 1504  
1504 1505          /* copy out the path name */
1505 1506          if (copyout(name, uname, sz) != 0)
1506 1507                  err = EFAULT;
1507 1508          kmem_free(name, MAXPATHLEN);
1508 1509          return (err);
1509 1510  }
1510 1511  
1511 1512  /*
1512 1513   * Return the size of the (major,instance) devfspath name.
1513 1514   */
1514 1515  static int
1515 1516  modctl_devfspath_mi_len(major_t major, int instance, uint_t *len)
1516 1517  {
1517 1518          uint_t  sz;
1518 1519          char    *name;
1519 1520  
1520 1521          /* get the path name */
1521 1522          name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1522 1523          if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
1523 1524                  kmem_free(name, MAXPATHLEN);
1524 1525                  return (EINVAL);
1525 1526          }
1526 1527  
1527 1528          sz = strlen(name) + 1;
1528 1529          kmem_free(name, MAXPATHLEN);
1529 1530  
1530 1531          /* copy out the size of the path name */
1531 1532          if (copyout(&sz, len, sizeof (sz)) != 0)
1532 1533                  return (EFAULT);
1533 1534  
1534 1535          return (0);
1535 1536  }
1536 1537  
1537 1538  /*
1538 1539   * Return the (major_instance) devfspath name.
1539 1540   * NOTE: e_ddi_majorinstance_to_path does not require the device to attach to
1540 1541   * return a path - it uses the instance tree.
1541 1542   */
1542 1543  static int
1543 1544  modctl_devfspath_mi(major_t major, int instance, uint_t len, char *uname)
1544 1545  {
1545 1546          uint_t  sz;
1546 1547          char    *name;
1547 1548          int     err = 0;
1548 1549  
1549 1550          /* get the path name */
1550 1551          name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1551 1552          if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
1552 1553                  kmem_free(name, MAXPATHLEN);
1553 1554                  return (EINVAL);
1554 1555          }
1555 1556  
1556 1557          sz = strlen(name) + 1;
1557 1558  
1558 1559          /* Error if the path name is larger than the space allocated */
1559 1560          if (sz > len) {
1560 1561                  kmem_free(name, MAXPATHLEN);
1561 1562                  return (ENOSPC);
1562 1563          }
1563 1564  
1564 1565          /* copy out the path name */
1565 1566          if (copyout(name, uname, sz) != 0)
1566 1567                  err = EFAULT;
1567 1568          kmem_free(name, MAXPATHLEN);
1568 1569          return (err);
1569 1570  }
1570 1571  
1571 1572  static int
1572 1573  modctl_get_fbname(char *path)
1573 1574  {
1574 1575          extern dev_t fbdev;
1575 1576          char *pathname = NULL;
1576 1577          int rval = 0;
1577 1578  
1578 1579          /* make sure fbdev is set before we plunge in */
1579 1580          if (fbdev == NODEV)
1580 1581                  return (ENODEV);
1581 1582  
1582 1583          pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1583 1584          if ((rval = ddi_dev_pathname(fbdev, S_IFCHR,
1584 1585              pathname)) == DDI_SUCCESS) {
1585 1586                  if (copyout(pathname, path, strlen(pathname)+1) != 0) {
1586 1587                          rval = EFAULT;
1587 1588                  }
1588 1589          }
1589 1590          kmem_free(pathname, MAXPATHLEN);
1590 1591          return (rval);
1591 1592  }
1592 1593  
1593 1594  /*
1594 1595   * modctl_reread_dacf()
1595 1596   *      Reread the dacf rules database from the named binding file.
1596 1597   *      If NULL is specified, pass along the NULL, it means 'use the default'.
1597 1598   */
1598 1599  static int
1599 1600  modctl_reread_dacf(char *path)
1600 1601  {
1601 1602          int rval = 0;
1602 1603          char *filename, *filenamep;
1603 1604  
1604 1605          filename = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1605 1606  
1606 1607          if (path == NULL) {
1607 1608                  filenamep = NULL;
1608 1609          } else {
1609 1610                  if (copyinstr(path, filename, MAXPATHLEN, 0) != 0) {
1610 1611                          rval = EFAULT;
1611 1612                          goto out;
1612 1613                  }
1613 1614                  filenamep = filename;
1614 1615                  filenamep[MAXPATHLEN - 1] = '\0';
1615 1616          }
1616 1617  
1617 1618          rval = read_dacf_binding_file(filenamep);
1618 1619  out:
1619 1620          kmem_free(filename, MAXPATHLEN);
1620 1621          return (rval);
1621 1622  }
1622 1623  
1623 1624  /*ARGSUSED*/
1624 1625  static int
1625 1626  modctl_modevents(int subcmd, uintptr_t a2, uintptr_t a3, uintptr_t a4,
1626 1627      uint_t flag)
1627 1628  {
1628 1629          int error = 0;
1629 1630          char *filenamep;
1630 1631  
1631 1632          switch (subcmd) {
1632 1633  
1633 1634          case MODEVENTS_FLUSH:
1634 1635                  /* flush all currently queued events */
1635 1636                  log_sysevent_flushq(subcmd, flag);
1636 1637                  break;
1637 1638  
1638 1639          case MODEVENTS_SET_DOOR_UPCALL_FILENAME:
1639 1640                  /*
1640 1641                   * bind door_upcall to filename
1641 1642                   * this should only be done once per invocation
1642 1643                   * of the event daemon.
1643 1644                   */
1644 1645  
1645 1646                  filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
1646 1647  
1647 1648                  if (copyinstr((char *)a2, filenamep, MOD_MAXPATH, 0)) {
1648 1649                          error = EFAULT;
1649 1650                  } else {
1650 1651                          error = log_sysevent_filename(filenamep);
1651 1652                  }
1652 1653                  kmem_free(filenamep, MOD_MAXPATH);
1653 1654                  break;
1654 1655  
1655 1656          case MODEVENTS_GETDATA:
1656 1657                  error = log_sysevent_copyout_data((sysevent_id_t *)a2,
1657 1658                      (size_t)a3, (caddr_t)a4);
1658 1659                  break;
1659 1660  
1660 1661          case MODEVENTS_FREEDATA:
1661 1662                  error = log_sysevent_free_data((sysevent_id_t *)a2);
1662 1663                  break;
1663 1664          case MODEVENTS_POST_EVENT:
1664 1665                  error = log_usr_sysevent((sysevent_t *)a2, (uint32_t)a3,
1665 1666                      (sysevent_id_t *)a4);
1666 1667                  break;
1667 1668          case MODEVENTS_REGISTER_EVENT:
1668 1669                  error = log_sysevent_register((char *)a2, (char *)a3,
1669 1670                      (se_pubsub_t *)a4);
1670 1671                  break;
1671 1672          default:
1672 1673                  error = EINVAL;
1673 1674          }
1674 1675  
1675 1676          return (error);
1676 1677  }
1677 1678  
1678 1679  static void
1679 1680  free_mperm(mperm_t *mp)
1680 1681  {
1681 1682          int len;
1682 1683  
1683 1684          if (mp->mp_minorname) {
1684 1685                  len = strlen(mp->mp_minorname) + 1;
1685 1686                  kmem_free(mp->mp_minorname, len);
1686 1687          }
1687 1688          kmem_free(mp, sizeof (mperm_t));
1688 1689  }
1689 1690  
1690 1691  #define MP_NO_DRV_ERR   \
1691 1692          "/etc/minor_perm: no driver for %s\n"
1692 1693  
1693 1694  #define MP_EMPTY_MINOR  \
1694 1695          "/etc/minor_perm: empty minor name for driver %s\n"
1695 1696  
1696 1697  #define MP_NO_MINOR     \
1697 1698          "/etc/minor_perm: no minor matching %s for driver %s\n"
1698 1699  
1699 1700  /*
1700 1701   * Remove mperm entry with matching minorname
1701 1702   */
1702 1703  static void
1703 1704  rem_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone)
1704 1705  {
1705 1706          mperm_t **mp_head;
1706 1707          mperm_t *freemp = NULL;
1707 1708          struct devnames *dnp = &devnamesp[major];
1708 1709          mperm_t **wildmp;
1709 1710  
1710 1711          ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0);
1711 1712  
1712 1713          LOCK_DEV_OPS(&dnp->dn_lock);
1713 1714          if (strcmp(mp->mp_minorname, "*") == 0) {
1714 1715                  wildmp = ((is_clone == 0) ?
1715 1716                      &dnp->dn_mperm_wild : &dnp->dn_mperm_clone);
1716 1717                  if (*wildmp)
1717 1718                          freemp = *wildmp;
1718 1719                  *wildmp = NULL;
1719 1720          } else {
1720 1721                  mp_head = &dnp->dn_mperm;
1721 1722                  while (*mp_head) {
1722 1723                          if (strcmp((*mp_head)->mp_minorname,
1723 1724                              mp->mp_minorname) != 0) {
1724 1725                                  mp_head = &(*mp_head)->mp_next;
1725 1726                                  continue;
1726 1727                          }
1727 1728                          /* remove the entry */
1728 1729                          freemp = *mp_head;
1729 1730                          *mp_head = freemp->mp_next;
1730 1731                          break;
1731 1732                  }
1732 1733          }
1733 1734          if (freemp) {
1734 1735                  if (moddebug & MODDEBUG_MINORPERM) {
1735 1736                          cmn_err(CE_CONT, "< %s %s 0%o %d %d\n",
1736 1737                              drvname, freemp->mp_minorname,
1737 1738                              freemp->mp_mode & 0777,
1738 1739                              freemp->mp_uid, freemp->mp_gid);
1739 1740                  }
1740 1741                  free_mperm(freemp);
1741 1742          } else {
1742 1743                  if (moddebug & MODDEBUG_MINORPERM) {
1743 1744                          cmn_err(CE_CONT, MP_NO_MINOR,
1744 1745                              drvname, mp->mp_minorname);
1745 1746                  }
1746 1747          }
1747 1748  
1748 1749          UNLOCK_DEV_OPS(&dnp->dn_lock);
1749 1750  }
1750 1751  
1751 1752  /*
1752 1753   * Add minor perm entry
1753 1754   */
1754 1755  static void
1755 1756  add_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone)
1756 1757  {
1757 1758          mperm_t **mp_head;
1758 1759          mperm_t *freemp = NULL;
1759 1760          struct devnames *dnp = &devnamesp[major];
1760 1761          mperm_t **wildmp;
1761 1762  
1762 1763          ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0);
1763 1764  
1764 1765          /*
1765 1766           * Note that update_drv replace semantics require
1766 1767           * replacing matching entries with the new permissions.
1767 1768           */
1768 1769          LOCK_DEV_OPS(&dnp->dn_lock);
1769 1770          if (strcmp(mp->mp_minorname, "*") == 0) {
1770 1771                  wildmp = ((is_clone == 0) ?
1771 1772                      &dnp->dn_mperm_wild : &dnp->dn_mperm_clone);
1772 1773                  if (*wildmp)
1773 1774                          freemp = *wildmp;
1774 1775                  *wildmp = mp;
1775 1776          } else {
1776 1777                  mperm_t *p, *v = NULL;
1777 1778                  for (p = dnp->dn_mperm; p; v = p, p = p->mp_next) {
1778 1779                          if (strcmp(p->mp_minorname, mp->mp_minorname) == 0) {
1779 1780                                  if (v == NULL)
1780 1781                                          dnp->dn_mperm = mp;
1781 1782                                  else
1782 1783                                          v->mp_next = mp;
1783 1784                                  mp->mp_next = p->mp_next;
1784 1785                                  freemp = p;
1785 1786                                  goto replaced;
1786 1787                          }
1787 1788                  }
1788 1789                  if (p == NULL) {
1789 1790                          mp_head = &dnp->dn_mperm;
1790 1791                          if (*mp_head == NULL) {
1791 1792                                  *mp_head = mp;
1792 1793                          } else {
1793 1794                                  mp->mp_next = *mp_head;
1794 1795                                  *mp_head = mp;
1795 1796                          }
1796 1797                  }
1797 1798          }
1798 1799  replaced:
1799 1800          if (freemp) {
1800 1801                  if (moddebug & MODDEBUG_MINORPERM) {
1801 1802                          cmn_err(CE_CONT, "< %s %s 0%o %d %d\n",
1802 1803                              drvname, freemp->mp_minorname,
1803 1804                              freemp->mp_mode & 0777,
1804 1805                              freemp->mp_uid, freemp->mp_gid);
1805 1806                  }
1806 1807                  free_mperm(freemp);
1807 1808          }
1808 1809          if (moddebug & MODDEBUG_MINORPERM) {
1809 1810                  cmn_err(CE_CONT, "> %s %s 0%o %d %d\n",
1810 1811                      drvname, mp->mp_minorname, mp->mp_mode & 0777,
1811 1812                      mp->mp_uid, mp->mp_gid);
1812 1813          }
1813 1814          UNLOCK_DEV_OPS(&dnp->dn_lock);
1814 1815  }
1815 1816  
1816 1817  
1817 1818  static int
1818 1819  process_minorperm(int cmd, nvlist_t *nvl)
1819 1820  {
1820 1821          char *minor;
1821 1822          major_t major;
1822 1823          mperm_t *mp;
1823 1824          nvpair_t *nvp;
1824 1825          char *name;
1825 1826          int is_clone;
1826 1827          major_t minmaj;
1827 1828  
1828 1829          ASSERT(cmd == MODLOADMINORPERM ||
1829 1830              cmd == MODADDMINORPERM || cmd == MODREMMINORPERM);
1830 1831  
1831 1832          nvp = NULL;
1832 1833          while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1833 1834                  name = nvpair_name(nvp);
1834 1835  
1835 1836                  is_clone = 0;
1836 1837                  (void) nvpair_value_string(nvp, &minor);
1837 1838                  major = ddi_name_to_major(name);
1838 1839                  if (major != DDI_MAJOR_T_NONE) {
1839 1840                          mp = kmem_zalloc(sizeof (*mp), KM_SLEEP);
1840 1841                          if (minor == NULL || strlen(minor) == 0) {
1841 1842                                  if (moddebug & MODDEBUG_MINORPERM) {
1842 1843                                          cmn_err(CE_CONT, MP_EMPTY_MINOR, name);
1843 1844                                  }
1844 1845                                  minor = "*";
1845 1846                          }
1846 1847  
1847 1848                          /*
1848 1849                           * The minor name of a node using the clone
1849 1850                           * driver must be the driver name.  To avoid
1850 1851                           * multiple searches, we map entries in the form
1851 1852                           * clone:<driver> to <driver>:*.  This also allows us
1852 1853                           * to filter out some of the litter in /etc/minor_perm.
1853 1854                           * Minor perm alias entries where the name is not
1854 1855                           * the driver kept on the clone list itself.
1855 1856                           * This all seems very fragile as a driver could
1856 1857                           * be introduced with an existing alias name.
1857 1858                           */
1858 1859                          if (strcmp(name, "clone") == 0) {
1859 1860                                  minmaj = ddi_name_to_major(minor);
1860 1861                                  if (minmaj != DDI_MAJOR_T_NONE) {
1861 1862                                          if (moddebug & MODDEBUG_MINORPERM) {
1862 1863                                                  cmn_err(CE_CONT,
1863 1864                                                      "mapping %s:%s to %s:*\n",
1864 1865                                                      name, minor, minor);
1865 1866                                          }
1866 1867                                          major = minmaj;
1867 1868                                          name = minor;
1868 1869                                          minor = "*";
1869 1870                                          is_clone = 1;
1870 1871                                  }
1871 1872                          }
1872 1873  
1873 1874                          if (mp) {
1874 1875                                  mp->mp_minorname =
1875 1876                                      i_ddi_strdup(minor, KM_SLEEP);
1876 1877                          }
1877 1878                  } else {
1878 1879                          mp = NULL;
1879 1880                          if (moddebug & MODDEBUG_MINORPERM) {
1880 1881                                  cmn_err(CE_CONT, MP_NO_DRV_ERR, name);
1881 1882                          }
1882 1883                  }
1883 1884  
1884 1885                  /* mode */
1885 1886                  nvp = nvlist_next_nvpair(nvl, nvp);
1886 1887                  ASSERT(strcmp(nvpair_name(nvp), "mode") == 0);
1887 1888                  if (mp)
1888 1889                          (void) nvpair_value_int32(nvp, (int *)&mp->mp_mode);
1889 1890                  /* uid */
1890 1891                  nvp = nvlist_next_nvpair(nvl, nvp);
1891 1892                  ASSERT(strcmp(nvpair_name(nvp), "uid") == 0);
1892 1893                  if (mp)
1893 1894                          (void) nvpair_value_uint32(nvp, &mp->mp_uid);
1894 1895                  /* gid */
1895 1896                  nvp = nvlist_next_nvpair(nvl, nvp);
1896 1897                  ASSERT(strcmp(nvpair_name(nvp), "gid") == 0);
1897 1898                  if (mp) {
1898 1899                          (void) nvpair_value_uint32(nvp, &mp->mp_gid);
1899 1900  
1900 1901                          if (cmd == MODREMMINORPERM) {
1901 1902                                  rem_minorperm(major, name, mp, is_clone);
1902 1903                                  free_mperm(mp);
1903 1904                          } else {
1904 1905                                  add_minorperm(major, name, mp, is_clone);
1905 1906                          }
1906 1907                  }
1907 1908          }
1908 1909  
1909 1910          if (cmd == MODLOADMINORPERM)
1910 1911                  minorperm_loaded = 1;
1911 1912  
1912 1913          /*
1913 1914           * Reset permissions of cached dv_nodes
1914 1915           */
1915 1916          (void) devfs_reset_perm(DV_RESET_PERM);
1916 1917  
1917 1918          return (0);
1918 1919  }
1919 1920  
1920 1921  static int
1921 1922  modctl_minorperm(int cmd, char *usrbuf, size_t buflen)
1922 1923  {
1923 1924          int error;
1924 1925          nvlist_t *nvl;
1925 1926          char *buf = kmem_alloc(buflen, KM_SLEEP);
1926 1927  
1927 1928          if ((error = ddi_copyin(usrbuf, buf, buflen, 0)) != 0) {
1928 1929                  kmem_free(buf, buflen);
1929 1930                  return (error);
1930 1931          }
1931 1932  
1932 1933          error = nvlist_unpack(buf, buflen, &nvl, KM_SLEEP);
1933 1934          kmem_free(buf, buflen);
1934 1935          if (error)
1935 1936                  return (error);
1936 1937  
1937 1938          error = process_minorperm(cmd, nvl);
1938 1939          nvlist_free(nvl);
1939 1940          return (error);
1940 1941  }
1941 1942  
1942 1943  struct walk_args {
1943 1944          char            *wa_drvname;
1944 1945          list_t          wa_pathlist;
1945 1946  };
1946 1947  
1947 1948  struct path_elem {
1948 1949          char            *pe_dir;
1949 1950          char            *pe_nodename;
1950 1951          list_node_t     pe_node;
1951 1952          int             pe_dirlen;
1952 1953  };
1953 1954  
1954 1955  /*ARGSUSED*/
1955 1956  static int
1956 1957  modctl_inst_walker(const char *path, in_node_t *np, in_drv_t *dp, void *arg)
1957 1958  {
1958 1959          struct walk_args *wargs = (struct walk_args *)arg;
1959 1960          struct path_elem *pe;
1960 1961          char *nodename;
1961 1962  
1962 1963          /*
1963 1964           * Search may be restricted to a single driver in the case of rem_drv
1964 1965           */
1965 1966          if (wargs->wa_drvname &&
1966 1967              strcmp(dp->ind_driver_name, wargs->wa_drvname) != 0)
1967 1968                  return (INST_WALK_CONTINUE);
1968 1969  
1969 1970          pe = kmem_zalloc(sizeof (*pe), KM_SLEEP);
1970 1971          pe->pe_dir = i_ddi_strdup((char *)path, KM_SLEEP);
1971 1972          pe->pe_dirlen = strlen(pe->pe_dir) + 1;
1972 1973          ASSERT(strrchr(pe->pe_dir, '/') != NULL);
1973 1974          nodename = strrchr(pe->pe_dir, '/');
1974 1975          *nodename++ = 0;
1975 1976          pe->pe_nodename = nodename;
1976 1977          list_insert_tail(&wargs->wa_pathlist, pe);
1977 1978  
1978 1979          return (INST_WALK_CONTINUE);
1979 1980  }
1980 1981  
1981 1982  /*
1982 1983   * /devices attribute nodes clean-up optionally performed
1983 1984   * when removing a driver (rem_drv -C).
1984 1985   *
1985 1986   * Removing attribute nodes allows a machine to be reprovisioned
1986 1987   * without the side-effect of inadvertently picking up stale
1987 1988   * device node ownership or permissions.
1988 1989   *
1989 1990   * Preserving attributes (not performing cleanup) allows devices
1990 1991   * attribute changes to be preserved across upgrades, as
1991 1992   * upgrade rather heavy-handedly does a rem_drv/add_drv cycle.
1992 1993   */
1993 1994  static int
1994 1995  modctl_remdrv_cleanup(const char *u_drvname)
1995 1996  {
1996 1997          struct walk_args *wargs;
1997 1998          struct path_elem *pe;
1998 1999          char *drvname;
1999 2000          int err, rval = 0;
2000 2001  
2001 2002          drvname = kmem_alloc(MAXMODCONFNAME, KM_SLEEP);
2002 2003          if ((err = copyinstr(u_drvname, drvname, MAXMODCONFNAME, 0))) {
2003 2004                  kmem_free(drvname, MAXMODCONFNAME);
2004 2005                  return (err);
2005 2006          }
2006 2007  
2007 2008          /*
2008 2009           * First go through the instance database.  For each
2009 2010           * instance of a device bound to the driver being
2010 2011           * removed, remove any underlying devfs attribute nodes.
2011 2012           *
2012 2013           * This is a two-step process.  First we go through
2013 2014           * the instance data itself, constructing a list of
2014 2015           * the nodes discovered.  The second step is then
2015 2016           * to find and remove any devfs attribute nodes
2016 2017           * for the instances discovered in the first step.
2017 2018           * The two-step process avoids any difficulties
2018 2019           * which could arise by holding the instance data
2019 2020           * lock with simultaneous devfs operations.
2020 2021           */
2021 2022          wargs = kmem_zalloc(sizeof (*wargs), KM_SLEEP);
2022 2023  
2023 2024          wargs->wa_drvname = drvname;
2024 2025          list_create(&wargs->wa_pathlist,
2025 2026              sizeof (struct path_elem), offsetof(struct path_elem, pe_node));
2026 2027  
2027 2028          (void) e_ddi_walk_instances(modctl_inst_walker, (void *)wargs);
2028 2029  
2029 2030          for (pe = list_head(&wargs->wa_pathlist); pe != NULL;
2030 2031              pe = list_next(&wargs->wa_pathlist, pe)) {
2031 2032                  err = devfs_remdrv_cleanup((const char *)pe->pe_dir,
2032 2033                      (const char *)pe->pe_nodename);
2033 2034                  if (rval == 0)
2034 2035                          rval = err;
2035 2036          }
2036 2037  
2037 2038          while ((pe = list_head(&wargs->wa_pathlist)) != NULL) {
2038 2039                  list_remove(&wargs->wa_pathlist, pe);
2039 2040                  kmem_free(pe->pe_dir, pe->pe_dirlen);
2040 2041                  kmem_free(pe, sizeof (*pe));
2041 2042          }
2042 2043          kmem_free(wargs, sizeof (*wargs));
2043 2044  
2044 2045          /*
2045 2046           * Pseudo nodes aren't recorded in the instance database
2046 2047           * so any such nodes need to be handled separately.
2047 2048           */
2048 2049          err = devfs_remdrv_cleanup("pseudo", (const char *)drvname);
2049 2050          if (rval == 0)
2050 2051                  rval = err;
2051 2052  
2052 2053          kmem_free(drvname, MAXMODCONFNAME);
2053 2054          return (rval);
2054 2055  }
2055 2056  
2056 2057  /*
2057 2058   * Perform a cleanup of non-existent /devices attribute nodes,
2058 2059   * similar to rem_drv -C, but for all drivers/devices.
2059 2060   * This is also optional, performed as part of devfsadm -C.
2060 2061   */
2061 2062  void
2062 2063  dev_devices_cleanup()
2063 2064  {
2064 2065          struct walk_args *wargs;
2065 2066          struct path_elem *pe;
2066 2067          dev_info_t *devi;
2067 2068          char *path;
2068 2069          int err;
2069 2070  
2070 2071          /*
2071 2072           * It's expected that all drivers have been loaded and
2072 2073           * module unloading disabled while performing cleanup.
2073 2074           */
2074 2075          ASSERT(modunload_disable_count > 0);
2075 2076  
2076 2077          wargs = kmem_zalloc(sizeof (*wargs), KM_SLEEP);
2077 2078          wargs->wa_drvname = NULL;
2078 2079          list_create(&wargs->wa_pathlist,
2079 2080              sizeof (struct path_elem), offsetof(struct path_elem, pe_node));
2080 2081  
2081 2082          (void) e_ddi_walk_instances(modctl_inst_walker, (void *)wargs);
2082 2083  
2083 2084          path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2084 2085  
2085 2086          for (pe = list_head(&wargs->wa_pathlist); pe != NULL;
2086 2087              pe = list_next(&wargs->wa_pathlist, pe)) {
2087 2088                  (void) snprintf(path, MAXPATHLEN, "%s/%s",
2088 2089                      pe->pe_dir, pe->pe_nodename);
2089 2090                  devi = e_ddi_hold_devi_by_path(path, 0);
2090 2091                  if (devi != NULL) {
2091 2092                          ddi_release_devi(devi);
2092 2093                  } else {
2093 2094                          err = devfs_remdrv_cleanup((const char *)pe->pe_dir,
2094 2095                              (const char *)pe->pe_nodename);
2095 2096                          if (err) {
2096 2097                                  cmn_err(CE_CONT,
2097 2098                                      "devfs: %s: clean-up error %d\n",
2098 2099                                      path, err);
2099 2100                          }
2100 2101                  }
2101 2102          }
2102 2103  
2103 2104          while ((pe = list_head(&wargs->wa_pathlist)) != NULL) {
2104 2105                  list_remove(&wargs->wa_pathlist, pe);
2105 2106                  kmem_free(pe->pe_dir, pe->pe_dirlen);
2106 2107                  kmem_free(pe, sizeof (*pe));
2107 2108          }
2108 2109          kmem_free(wargs, sizeof (*wargs));
2109 2110          kmem_free(path, MAXPATHLEN);
2110 2111  }
2111 2112  
2112 2113  static int
2113 2114  modctl_allocpriv(const char *name)
2114 2115  {
2115 2116          char *pstr = kmem_alloc(PRIVNAME_MAX, KM_SLEEP);
2116 2117          int error;
2117 2118  
2118 2119          if ((error = copyinstr(name, pstr, PRIVNAME_MAX, 0))) {
2119 2120                  kmem_free(pstr, PRIVNAME_MAX);
2120 2121                  return (error);
2121 2122          }
2122 2123          error = priv_getbyname(pstr, PRIV_ALLOC);
2123 2124          if (error < 0)
2124 2125                  error = -error;
2125 2126          else
2126 2127                  error = 0;
2127 2128          kmem_free(pstr, PRIVNAME_MAX);
2128 2129          return (error);
2129 2130  }
2130 2131  
2131 2132  static int
2132 2133  modctl_devexists(const char *upath, int pathlen)
2133 2134  {
2134 2135          char    *path;
2135 2136          int     ret;
2136 2137  
2137 2138          /*
2138 2139           * copy in the path, including the terminating null
2139 2140           */
2140 2141          pathlen++;
2141 2142          if (pathlen <= 1 || pathlen > MAXPATHLEN)
2142 2143                  return (EINVAL);
2143 2144          path = kmem_zalloc(pathlen + 1, KM_SLEEP);
2144 2145          if ((ret = copyinstr(upath, path, pathlen, NULL)) == 0) {
2145 2146                  ret = sdev_modctl_devexists(path);
2146 2147          }
2147 2148  
2148 2149          kmem_free(path, pathlen + 1);
2149 2150          return (ret);
2150 2151  }
2151 2152  
2152 2153  static int
2153 2154  modctl_devreaddir(const char *udir, int udirlen,
2154 2155      char *upaths, int64_t *ulensp)
2155 2156  {
2156 2157          char    *paths = NULL;
2157 2158          char    **dirlist = NULL;
2158 2159          char    *dir;
2159 2160          int64_t ulens;
2160 2161          int64_t lens;
2161 2162          int     i, n;
2162 2163          int     ret = 0;
2163 2164          char    *p;
2164 2165          int     npaths;
2165 2166          int     npaths_alloc;
2166 2167  
2167 2168          /*
2168 2169           * If upaths is NULL then we are only computing the amount of space
2169 2170           * needed to return the paths, with the value returned in *ulensp. If we
2170 2171           * are copying out paths then we get the amount of space allocated by
2171 2172           * the caller. If the actual space needed for paths is larger, or
2172 2173           * things are changing out from under us, then we return EAGAIN.
2173 2174           */
2174 2175          if (upaths) {
2175 2176                  if (ulensp == NULL)
2176 2177                          return (EINVAL);
2177 2178                  if (copyin(ulensp, &ulens, sizeof (ulens)) != 0)
2178 2179                          return (EFAULT);
2179 2180          }
2180 2181  
2181 2182          /*
2182 2183           * copyin the /dev path including terminating null
2183 2184           */
2184 2185          udirlen++;
2185 2186          if (udirlen <= 1 || udirlen > MAXPATHLEN)
2186 2187                  return (EINVAL);
2187 2188          dir = kmem_zalloc(udirlen + 1, KM_SLEEP);
2188 2189          if ((ret = copyinstr(udir, dir, udirlen, NULL)) != 0)
2189 2190                  goto err;
2190 2191  
2191 2192          if ((ret = sdev_modctl_readdir(dir, &dirlist,
2192 2193              &npaths, &npaths_alloc, 0)) != 0) {
2193 2194                  ASSERT(dirlist == NULL);
2194 2195                  goto err;
2195 2196          }
2196 2197  
2197 2198          lens = 0;
2198 2199          for (i = 0; i < npaths; i++) {
2199 2200                  lens += strlen(dirlist[i]) + 1;
2200 2201          }
2201 2202          lens++;         /* add one for double termination */
2202 2203  
2203 2204          if (upaths) {
2204 2205                  if (lens > ulens) {
2205 2206                          ret = EAGAIN;
2206 2207                          goto out;
2207 2208                  }
2208 2209  
2209 2210                  paths = kmem_alloc(lens, KM_SLEEP);
2210 2211  
2211 2212                  p = paths;
2212 2213                  for (i = 0; i < npaths; i++) {
2213 2214                          n = strlen(dirlist[i]) + 1;
2214 2215                          bcopy(dirlist[i], p, n);
2215 2216                          p += n;
2216 2217                  }
2217 2218                  *p = 0;
2218 2219  
2219 2220                  if (copyout(paths, upaths, lens)) {
2220 2221                          ret = EFAULT;
2221 2222                          goto err;
2222 2223                  }
2223 2224          }
2224 2225  
2225 2226  out:
2226 2227          /* copy out the amount of space needed to hold the paths */
2227 2228          if (copyout(&lens, ulensp, sizeof (lens)))
2228 2229                  ret = EFAULT;
2229 2230  
2230 2231  err:
2231 2232          if (dirlist)
2232 2233                  sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
2233 2234          if (paths)
2234 2235                  kmem_free(paths, lens);
2235 2236          kmem_free(dir, udirlen + 1);
2236 2237          return (ret);
2237 2238  }
2238 2239  
2239 2240  static int
2240 2241  modctl_devemptydir(const char *udir, int udirlen, int *uempty)
2241 2242  {
2242 2243          char    *dir;
2243 2244          int     ret;
2244 2245          char    **dirlist = NULL;
2245 2246          int     npaths;
2246 2247          int     npaths_alloc;
2247 2248          int     empty;
2248 2249  
2249 2250          /*
2250 2251           * copyin the /dev path including terminating null
2251 2252           */
2252 2253          udirlen++;
2253 2254          if (udirlen <= 1 || udirlen > MAXPATHLEN)
2254 2255                  return (EINVAL);
2255 2256          dir = kmem_zalloc(udirlen + 1, KM_SLEEP);
2256 2257          if ((ret = copyinstr(udir, dir, udirlen, NULL)) != 0)
2257 2258                  goto err;
2258 2259  
2259 2260          if ((ret = sdev_modctl_readdir(dir, &dirlist,
2260 2261              &npaths, &npaths_alloc, 1)) != 0) {
2261 2262                  goto err;
2262 2263          }
2263 2264  
2264 2265          empty = npaths ? 0 : 1;
2265 2266          if (copyout(&empty, uempty, sizeof (empty)))
2266 2267                  ret = EFAULT;
2267 2268  
2268 2269  err:
2269 2270          if (dirlist)
2270 2271                  sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
2271 2272          kmem_free(dir, udirlen + 1);
2272 2273          return (ret);
2273 2274  }
2274 2275  
2275 2276  static int
2276 2277  modctl_hp(int subcmd, const char *path, char *cn_name, uintptr_t arg,
2277 2278      uintptr_t rval)
2278 2279  {
2279 2280          int error = 0;
2280 2281          size_t pathsz, namesz;
2281 2282          char *devpath, *cn_name_str;
2282 2283  
2283 2284          if (path == NULL)
2284 2285                  return (EINVAL);
2285 2286  
2286 2287          devpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2287 2288          error = copyinstr(path, devpath, MAXPATHLEN, &pathsz);
2288 2289          if (error != 0) {
2289 2290                  kmem_free(devpath, MAXPATHLEN);
2290 2291                  return (EFAULT);
2291 2292          }
2292 2293  
2293 2294          cn_name_str = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2294 2295          error = copyinstr(cn_name, cn_name_str, MAXNAMELEN, &namesz);
2295 2296          if (error != 0) {
2296 2297                  kmem_free(devpath, MAXPATHLEN);
2297 2298                  kmem_free(cn_name_str, MAXNAMELEN);
2298 2299  
2299 2300                  return (EFAULT);
2300 2301          }
2301 2302  
2302 2303          switch (subcmd) {
2303 2304          case MODHPOPS_CHANGE_STATE:
2304 2305                  error = ddihp_modctl(DDI_HPOP_CN_CHANGE_STATE, devpath,
2305 2306                      cn_name_str, arg, 0);
2306 2307                  break;
2307 2308          case MODHPOPS_CREATE_PORT:
2308 2309                  /* Create an empty PORT */
2309 2310                  error = ddihp_modctl(DDI_HPOP_CN_CREATE_PORT, devpath,
2310 2311                      cn_name_str, 0, 0);
2311 2312                  break;
2312 2313          case MODHPOPS_REMOVE_PORT:
2313 2314                  /* Remove an empty PORT */
2314 2315                  error = ddihp_modctl(DDI_HPOP_CN_REMOVE_PORT, devpath,
2315 2316                      cn_name_str, 0, 0);
2316 2317                  break;
2317 2318          case MODHPOPS_BUS_GET:
2318 2319                  error = ddihp_modctl(DDI_HPOP_CN_GET_PROPERTY, devpath,
2319 2320                      cn_name_str, arg, rval);
2320 2321                  break;
2321 2322          case MODHPOPS_BUS_SET:
2322 2323                  error = ddihp_modctl(DDI_HPOP_CN_SET_PROPERTY, devpath,
2323 2324                      cn_name_str, arg, rval);
2324 2325                  break;
2325 2326          default:
2326 2327                  error = ENOTSUP;
2327 2328                  break;
2328 2329          }
2329 2330  
2330 2331          kmem_free(devpath, MAXPATHLEN);
2331 2332          kmem_free(cn_name_str, MAXNAMELEN);
2332 2333  
2333 2334          return (error);
2334 2335  }
2335 2336  
2336 2337  int
2337 2338  modctl_moddevname(int subcmd, uintptr_t a1, uintptr_t a2)
2338 2339  {
2339 2340          int error = 0;
2340 2341  
2341 2342          switch (subcmd) {
2342 2343          case MODDEVNAME_LOOKUPDOOR:
2343 2344                  error = devname_filename_register((char *)a1);
2344 2345                  break;
2345 2346          case MODDEVNAME_PROFILE:
2346 2347                  error = devname_profile_update((char *)a1, (size_t)a2);
2347 2348                  break;
2348 2349          case MODDEVNAME_RECONFIG:
2349 2350                  i_ddi_set_reconfig();
2350 2351                  break;
2351 2352          case MODDEVNAME_SYSAVAIL:
2352 2353                  i_ddi_set_sysavail();
2353 2354                  break;
2354 2355          default:
2355 2356                  error = EINVAL;
2356 2357                  break;
2357 2358          }
2358 2359  
2359 2360          return (error);
2360 2361  }
2361 2362  
2362 2363  /*ARGSUSED5*/
2363 2364  int
2364 2365  modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
2365 2366      uintptr_t a5)
2366 2367  {
2367 2368          int     error = EINVAL;
2368 2369          dev_t   dev;
2369 2370  
2370 2371          if (secpolicy_modctl(CRED(), cmd) != 0)
2371 2372                  return (set_errno(EPERM));
2372 2373  
2373 2374          switch (cmd) {
2374 2375          case MODLOAD:           /* load a module */
2375 2376                  error = modctl_modload((int)a1, (char *)a2, (int *)a3);
2376 2377                  break;
2377 2378  
2378 2379          case MODUNLOAD:         /* unload a module */
2379 2380                  error = modctl_modunload((modid_t)a1);
2380 2381                  break;
2381 2382  
2382 2383          case MODINFO:           /* get module status */
2383 2384                  error = modctl_modinfo((modid_t)a1, (struct modinfo *)a2);
2384 2385                  break;
2385 2386  
2386 2387          case MODRESERVED:       /* get last major number in range */
2387 2388                  error = modctl_modreserve((modid_t)a1, (int *)a2);
2388 2389                  break;
2389 2390  
2390 2391          case MODSETMINIROOT:    /* we are running in miniroot */
2391 2392                  isminiroot = 1;
2392 2393                  error = 0;
2393 2394                  break;
2394 2395  
2395 2396          case MODADDMAJBIND:     /* add major / driver alias bindings */
2396 2397                  error = modctl_add_driver_aliases((int *)a2);
2397 2398                  break;
2398 2399  
2399 2400          case MODGETPATHLEN:     /* get modpath length */
2400 2401                  error = modctl_getmodpathlen((int *)a2);
2401 2402                  break;
2402 2403  
2403 2404          case MODGETPATH:        /* get modpath */
2404 2405                  error = modctl_getmodpath((char *)a2);
2405 2406                  break;
2406 2407  
2407 2408          case MODREADSYSBIND:    /* read system call binding file */
2408 2409                  error = modctl_read_sysbinding_file();
2409 2410                  break;
2410 2411  
2411 2412          case MODGETMAJBIND:     /* get major number for named device */
2412 2413                  error = modctl_getmaj((char *)a1, (uint_t)a2, (int *)a3);
2413 2414                  break;
2414 2415  
2415 2416          case MODGETNAME:        /* get name of device given major number */
2416 2417                  error = modctl_getname((char *)a1, (uint_t)a2, (int *)a3);
2417 2418                  break;
2418 2419  
2419 2420          case MODDEVT2INSTANCE:
2420 2421                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2421 2422                          dev = (dev_t)a1;
2422 2423                  }
2423 2424  #ifdef _SYSCALL32_IMPL
2424 2425                  else {
2425 2426                          dev = expldev(a1);
2426 2427                  }
2427 2428  #endif
2428 2429                  error = modctl_devt2instance(dev, (int *)a2);
2429 2430                  break;
2430 2431  
2431 2432          case MODSIZEOF_DEVID:   /* sizeof device id of device given dev_t */
2432 2433                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2433 2434                          dev = (dev_t)a1;
2434 2435                  }
2435 2436  #ifdef _SYSCALL32_IMPL
2436 2437                  else {
2437 2438                          dev = expldev(a1);
2438 2439                  }
2439 2440  #endif
2440 2441                  error = modctl_sizeof_devid(dev, (uint_t *)a2);
2441 2442                  break;
2442 2443  
2443 2444          case MODGETDEVID:       /* get device id of device given dev_t */
2444 2445                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2445 2446                          dev = (dev_t)a1;
2446 2447                  }
2447 2448  #ifdef _SYSCALL32_IMPL
2448 2449                  else {
2449 2450                          dev = expldev(a1);
2450 2451                  }
2451 2452  #endif
2452 2453                  error = modctl_get_devid(dev, (uint_t)a2, (ddi_devid_t)a3);
2453 2454                  break;
2454 2455  
2455 2456          case MODSIZEOF_MINORNAME:       /* sizeof minor nm (dev_t,spectype) */
2456 2457                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2457 2458                          error = modctl_sizeof_minorname((dev_t)a1, (int)a2,
2458 2459                              (uint_t *)a3);
2459 2460                  }
2460 2461  #ifdef _SYSCALL32_IMPL
2461 2462                  else {
2462 2463                          error = modctl_sizeof_minorname(expldev(a1), (int)a2,
2463 2464                              (uint_t *)a3);
2464 2465                  }
2465 2466  
2466 2467  #endif
2467 2468                  break;
2468 2469  
2469 2470          case MODGETMINORNAME:           /* get minor name of (dev_t,spectype) */
2470 2471                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2471 2472                          error = modctl_get_minorname((dev_t)a1, (int)a2,
2472 2473                              (uint_t)a3, (char *)a4);
2473 2474                  }
2474 2475  #ifdef _SYSCALL32_IMPL
2475 2476                  else {
2476 2477                          error = modctl_get_minorname(expldev(a1), (int)a2,
2477 2478                              (uint_t)a3, (char *)a4);
2478 2479                  }
2479 2480  #endif
2480 2481                  break;
2481 2482  
2482 2483          case MODGETDEVFSPATH_LEN:       /* sizeof path nm of (dev_t,spectype) */
2483 2484                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2484 2485                          error = modctl_devfspath_len((dev_t)a1, (int)a2,
2485 2486                              (uint_t *)a3);
2486 2487                  }
2487 2488  #ifdef _SYSCALL32_IMPL
2488 2489                  else {
2489 2490                          error = modctl_devfspath_len(expldev(a1), (int)a2,
2490 2491                              (uint_t *)a3);
2491 2492                  }
2492 2493  
2493 2494  #endif
2494 2495                  break;
2495 2496  
2496 2497          case MODGETDEVFSPATH:           /* get path name of (dev_t,spec) type */
2497 2498                  if (get_udatamodel() == DATAMODEL_NATIVE) {
2498 2499                          error = modctl_devfspath((dev_t)a1, (int)a2,
2499 2500                              (uint_t)a3, (char *)a4);
2500 2501                  }
2501 2502  #ifdef _SYSCALL32_IMPL
2502 2503                  else {
2503 2504                          error = modctl_devfspath(expldev(a1), (int)a2,
2504 2505                              (uint_t)a3, (char *)a4);
2505 2506                  }
2506 2507  #endif
2507 2508                  break;
2508 2509  
2509 2510          case MODGETDEVFSPATH_MI_LEN:    /* sizeof path nm of (major,instance) */
2510 2511                  error = modctl_devfspath_mi_len((major_t)a1, (int)a2,
2511 2512                      (uint_t *)a3);
2512 2513                  break;
2513 2514  
2514 2515          case MODGETDEVFSPATH_MI:        /* get path name of (major,instance) */
2515 2516                  error = modctl_devfspath_mi((major_t)a1, (int)a2,
2516 2517                      (uint_t)a3, (char *)a4);
2517 2518                  break;
2518 2519  
2519 2520  
2520 2521          case MODEVENTS:
2521 2522                  error = modctl_modevents((int)a1, a2, a3, a4, (uint_t)a5);
2522 2523                  break;
2523 2524  
2524 2525          case MODGETFBNAME:      /* get the framebuffer name */
2525 2526                  error = modctl_get_fbname((char *)a1);
2526 2527                  break;
2527 2528  
2528 2529          case MODREREADDACF:     /* reread dacf rule database from given file */
2529 2530                  error = modctl_reread_dacf((char *)a1);
2530 2531                  break;
2531 2532  
2532 2533          case MODLOADDRVCONF:    /* load driver.conf file for major */
2533 2534                  error = modctl_load_drvconf((major_t)a1, (int)a2);
2534 2535                  break;
2535 2536  
2536 2537          case MODUNLOADDRVCONF:  /* unload driver.conf file for major */
2537 2538                  error = modctl_unload_drvconf((major_t)a1);
2538 2539                  break;
2539 2540  
2540 2541          case MODREMMAJBIND:     /* remove a major binding */
2541 2542                  error = modctl_rem_major((major_t)a1);
2542 2543                  break;
2543 2544  
2544 2545          case MODREMDRVALIAS:    /* remove a major/alias binding */
2545 2546                  error = modctl_remove_driver_aliases((int *)a2);
2546 2547                  break;
2547 2548  
2548 2549          case MODDEVID2PATHS:    /* get paths given devid */
2549 2550                  error = modctl_devid2paths((ddi_devid_t)a1, (char *)a2,
2550 2551                      (uint_t)a3, (size_t *)a4, (char *)a5);
2551 2552                  break;
2552 2553  
2553 2554          case MODSETDEVPOLICY:   /* establish device policy */
2554 2555                  error = devpolicy_load((int)a1, (size_t)a2, (devplcysys_t *)a3);
2555 2556                  break;
2556 2557  
2557 2558          case MODGETDEVPOLICY:   /* get device policy */
2558 2559                  error = devpolicy_get((int *)a1, (size_t)a2,
2559 2560                      (devplcysys_t *)a3);
2560 2561                  break;
2561 2562  
2562 2563          case MODALLOCPRIV:
2563 2564                  error = modctl_allocpriv((const char *)a1);
2564 2565                  break;
2565 2566  
2566 2567          case MODGETDEVPOLICYBYNAME:
2567 2568                  error = devpolicy_getbyname((size_t)a1,
2568 2569                      (devplcysys_t *)a2, (char *)a3);
2569 2570                  break;
2570 2571  
2571 2572          case MODLOADMINORPERM:
2572 2573          case MODADDMINORPERM:
2573 2574          case MODREMMINORPERM:
2574 2575                  error = modctl_minorperm(cmd, (char *)a1, (size_t)a2);
2575 2576                  break;
2576 2577  
2577 2578          case MODREMDRVCLEANUP:
2578 2579                  error = modctl_remdrv_cleanup((const char *)a1);
2579 2580                  break;
2580 2581  
2581 2582          case MODDEVEXISTS:      /* non-reconfiguring /dev lookup */
2582 2583                  error = modctl_devexists((const char *)a1, (size_t)a2);
2583 2584                  break;
2584 2585  
2585 2586          case MODDEVREADDIR:     /* non-reconfiguring /dev readdir */
2586 2587                  error = modctl_devreaddir((const char *)a1, (size_t)a2,
2587 2588                      (char *)a3, (int64_t *)a4);
2588 2589                  break;
2589 2590  
2590 2591          case MODDEVEMPTYDIR:    /* non-reconfiguring /dev emptydir */
2591 2592                  error = modctl_devemptydir((const char *)a1, (size_t)a2,
2592 2593                      (int *)a3);
2593 2594                  break;
2594 2595  
2595 2596          case MODDEVNAME:
2596 2597                  error = modctl_moddevname((int)a1, a2, a3);
2597 2598                  break;
2598 2599  
2599 2600          case MODRETIRE: /* retire device named by physpath a1 */
2600 2601                  error = modctl_retire((char *)a1, (char *)a2, (size_t)a3);
2601 2602                  break;
2602 2603  
2603 2604          case MODISRETIRED:  /* check if a device is retired. */
2604 2605                  error = modctl_is_retired((char *)a1, (int *)a2);
2605 2606                  break;
2606 2607  
2607 2608          case MODUNRETIRE:       /* unretire device named by physpath a1 */
2608 2609                  error = modctl_unretire((char *)a1);
2609 2610                  break;
2610 2611  
2611 2612          case MODHPOPS:  /* hotplug operations */
2612 2613                  /* device named by physpath a2 and Connection name a3 */
2613 2614                  error = modctl_hp((int)a1, (char *)a2, (char *)a3, a4, a5);
2614 2615                  break;
2615 2616  
2616 2617          default:
2617 2618                  error = EINVAL;
2618 2619                  break;
2619 2620          }
2620 2621  
2621 2622          return (error ? set_errno(error) : 0);
2622 2623  }
2623 2624  
2624 2625  /*
2625 2626   * Calls to kobj_load_module()() are handled off to this routine in a
2626 2627   * separate thread.
2627 2628   */
2628 2629  static void
2629 2630  modload_thread(struct loadmt *ltp)
2630 2631  {
2631 2632          /* load the module and signal the creator of this thread */
2632 2633          kmutex_t        cpr_lk;
2633 2634          callb_cpr_t     cpr_i;
2634 2635  
2635 2636          mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
2636 2637          CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "modload");
2637 2638          /* borrow the devi lock from thread which invoked us */
2638 2639          pm_borrow_lock(ltp->owner);
2639 2640          ltp->retval = kobj_load_module(ltp->mp, ltp->usepath);
2640 2641          pm_return_lock();
2641 2642          sema_v(<p->sema);
2642 2643          mutex_enter(&cpr_lk);
2643 2644          CALLB_CPR_EXIT(&cpr_i);
2644 2645          mutex_destroy(&cpr_lk);
2645 2646          thread_exit();
2646 2647  }
2647 2648  
2648 2649  /*
2649 2650   * load a module, adding a reference if caller specifies rmodp.  If rmodp
2650 2651   * is specified then an errno is returned, otherwise a module index is
2651 2652   * returned (-1 on error).
2652 2653   */
2653 2654  static int
2654 2655  modrload(const char *subdir, const char *filename, struct modctl **rmodp)
2655 2656  {
2656 2657          struct modctl *modp;
2657 2658          size_t size;
2658 2659          char *fullname;
2659 2660          int retval = EINVAL;
2660 2661          int id = -1;
2661 2662  
2662 2663          if (rmodp)
2663 2664                  *rmodp = NULL;                  /* avoid garbage */
2664 2665  
2665 2666          if (subdir != NULL) {
2666 2667                  /*
2667 2668                   * refuse / in filename to prevent "../" escapes.
2668 2669                   */
2669 2670                  if (strchr(filename, '/') != NULL)
2670 2671                          return (rmodp ? retval : id);
2671 2672  
2672 2673                  /*
2673 2674                   * allocate enough space for <subdir>/<filename><NULL>
2674 2675                   */
2675 2676                  size = strlen(subdir) + strlen(filename) + 2;
2676 2677                  fullname = kmem_zalloc(size, KM_SLEEP);
2677 2678                  (void) sprintf(fullname, "%s/%s", subdir, filename);
2678 2679          } else {
2679 2680                  fullname = (char *)filename;
2680 2681          }
2681 2682  
2682 2683          modp = mod_hold_installed_mod(fullname, 1, 0, &retval);
2683 2684          if (modp != NULL) {
2684 2685                  id = modp->mod_id;
2685 2686                  if (rmodp) {
2686 2687                          /* add mod_ref and return *rmodp */
2687 2688                          mutex_enter(&mod_lock);
2688 2689                          modp->mod_ref++;
2689 2690                          mutex_exit(&mod_lock);
2690 2691                          *rmodp = modp;
2691 2692                  }
2692 2693                  mod_release_mod(modp);
2693 2694                  CPU_STATS_ADDQ(CPU, sys, modload, 1);
2694 2695          }
2695 2696  
2696 2697  done:   if (subdir != NULL)
2697 2698                  kmem_free(fullname, size);
2698 2699          return (rmodp ? retval : id);
2699 2700  }
2700 2701  
2701 2702  /*
2702 2703   * This is the primary kernel interface to load a module. It loads and
2703 2704   * installs the named module.  It does not hold mod_ref of the module, so
2704 2705   * a module unload attempt can occur at any time - it is up to the
2705 2706   * _fini/mod_remove implementation to determine if unload will succeed.
2706 2707   */
2707 2708  int
2708 2709  modload(const char *subdir, const char *filename)
2709 2710  {
2710 2711          return (modrload(subdir, filename, NULL));
2711 2712  }
2712 2713  
2713 2714  /*
2714 2715   * Load a module using a series of qualified names from most specific to least
2715 2716   * specific, e.g. for subdir "foo", p1 "bar", p2 "baz", we might try:
2716 2717   *                      Value returned in *chosen
2717 2718   * foo/bar.baz.1.2.3    3
2718 2719   * foo/bar.baz.1.2      2
2719 2720   * foo/bar.baz.1        1
2720 2721   * foo/bar.baz          0
2721 2722   *
2722 2723   * Return the module ID on success; -1 if no module was loaded.  On success
2723 2724   * and if 'chosen' is not NULL we also return the number of suffices that
2724 2725   * were in the module we chose to load.
2725 2726   */
2726 2727  int
2727 2728  modload_qualified(const char *subdir, const char *p1,
2728 2729      const char *p2, const char *delim, uint_t suffv[], int suffc, int *chosen)
2729 2730  {
2730 2731          char path[MOD_MAXPATH];
2731 2732          size_t n, resid = sizeof (path);
2732 2733          char *p = path;
2733 2734  
2734 2735          char **dotv;
2735 2736          int i, rc, id;
2736 2737          modctl_t *mp;
2737 2738  
2738 2739          if (p2 != NULL)
2739 2740                  n = snprintf(p, resid, "%s/%s%s%s", subdir, p1, delim, p2);
2740 2741          else
2741 2742                  n = snprintf(p, resid, "%s/%s", subdir, p1);
2742 2743  
2743 2744          if (n >= resid)
2744 2745                  return (-1);
2745 2746  
2746 2747          p += n;
2747 2748          resid -= n;
2748 2749          dotv = kmem_alloc(sizeof (char *) * (suffc + 1), KM_SLEEP);
2749 2750  
2750 2751          for (i = 0; i < suffc; i++) {
2751 2752                  dotv[i] = p;
2752 2753                  n = snprintf(p, resid, "%s%u", delim, suffv[i]);
2753 2754  
2754 2755                  if (n >= resid) {
2755 2756                          kmem_free(dotv, sizeof (char *) * (suffc + 1));
2756 2757                          return (-1);
2757 2758                  }
2758 2759  
2759 2760                  p += n;
2760 2761                  resid -= n;
2761 2762          }
2762 2763  
2763 2764          dotv[suffc] = p;
2764 2765  
2765 2766          for (i = suffc; i >= 0; i--) {
2766 2767                  dotv[i][0] = '\0';
2767 2768                  mp = mod_hold_installed_mod(path, 1, 1, &rc);
2768 2769  
2769 2770                  if (mp != NULL) {
2770 2771                          kmem_free(dotv, sizeof (char *) * (suffc + 1));
2771 2772                          id = mp->mod_id;
2772 2773                          mod_release_mod(mp);
2773 2774                          if (chosen != NULL)
2774 2775                                  *chosen = i;
2775 2776                          return (id);
2776 2777                  }
2777 2778          }
2778 2779  
2779 2780          kmem_free(dotv, sizeof (char *) * (suffc + 1));
2780 2781          return (-1);
2781 2782  }
2782 2783  
2783 2784  /*
2784 2785   * Load a module.
2785 2786   */
2786 2787  int
2787 2788  modloadonly(const char *subdir, const char *filename)
2788 2789  {
2789 2790          struct modctl *modp;
2790 2791          char *fullname;
2791 2792          size_t size;
2792 2793          int id, retval;
2793 2794  
2794 2795          if (subdir != NULL) {
2795 2796                  /*
2796 2797                   * allocate enough space for <subdir>/<filename><NULL>
2797 2798                   */
2798 2799                  size = strlen(subdir) + strlen(filename) + 2;
2799 2800                  fullname = kmem_zalloc(size, KM_SLEEP);
2800 2801                  (void) sprintf(fullname, "%s/%s", subdir, filename);
2801 2802          } else {
2802 2803                  fullname = (char *)filename;
2803 2804          }
2804 2805  
2805 2806          id = -1;
2806 2807          modp = mod_hold_loaded_mod(NULL, fullname, &retval);
2807 2808          if (modp) {
2808 2809                  id = modp->mod_id;
2809 2810                  mod_release_mod(modp);
2810 2811          }
2811 2812  
2812 2813          if (subdir != NULL)
2813 2814                  kmem_free(fullname, size);
2814 2815  
2815 2816          if (retval == 0)
2816 2817                  return (id);
2817 2818          return (-1);
2818 2819  }
2819 2820  
2820 2821  /*
2821 2822   * Try to uninstall and unload a module, removing a reference if caller
2822 2823   * specifies rmodp.
2823 2824   */
2824 2825  static int
2825 2826  modunrload(modid_t id, struct modctl **rmodp, int unload)
2826 2827  {
2827 2828          struct modctl   *modp;
2828 2829          int             retval;
2829 2830  
2830 2831          if (rmodp)
2831 2832                  *rmodp = NULL;                  /* avoid garbage */
2832 2833  
2833 2834          if ((modp = mod_hold_by_id((modid_t)id)) == NULL)
2834 2835                  return (EINVAL);
2835 2836  
2836 2837          if (rmodp) {
2837 2838                  mutex_enter(&mod_lock);
2838 2839                  modp->mod_ref--;
2839 2840                  if (modp->mod_ref == 0)
2840 2841                          mod_uninstall_ref_zero++;
2841 2842                  mutex_exit(&mod_lock);
2842 2843                  *rmodp = modp;
2843 2844          }
2844 2845  
2845 2846          if (unload) {
2846 2847                  retval = moduninstall(modp);
2847 2848                  if (retval == 0) {
2848 2849                          mod_unload(modp);
2849 2850                          CPU_STATS_ADDQ(CPU, sys, modunload, 1);
2850 2851                  } else if (retval == EALREADY)
2851 2852                          retval = 0;     /* already unloaded, not an error */
2852 2853          } else
2853 2854                  retval = 0;
2854 2855  
2855 2856          mod_release_mod(modp);
2856 2857          return (retval);
2857 2858  }
2858 2859  
2859 2860  /*
2860 2861   * Uninstall and unload a module.
2861 2862   */
2862 2863  int
2863 2864  modunload(modid_t id)
2864 2865  {
2865 2866          int             retval;
2866 2867  
2867 2868          /* synchronize with any active modunload_disable() */
2868 2869          modunload_begin();
2869 2870          if (ddi_root_node())
2870 2871                  (void) devfs_clean(ddi_root_node(), NULL, 0);
2871 2872          retval = modunrload(id, NULL, 1);
2872 2873          modunload_end();
2873 2874          return (retval);
2874 2875  }
2875 2876  
2876 2877  /*
2877 2878   * Return status of a loaded module.
2878 2879   */
2879 2880  static int
2880 2881  modinfo(modid_t id, struct modinfo *modinfop)
2881 2882  {
2882 2883          struct modctl   *modp;
2883 2884          modid_t         mid;
2884 2885          int             i;
2885 2886  
2886 2887          mid = modinfop->mi_id;
2887 2888          if (modinfop->mi_info & MI_INFO_ALL) {
2888 2889                  while ((modp = mod_hold_next_by_id(mid++)) != NULL) {
2889 2890                          if ((modinfop->mi_info & MI_INFO_CNT) ||
2890 2891                              modp->mod_installed)
2891 2892                                  break;
2892 2893                          mod_release_mod(modp);
2893 2894                  }
2894 2895                  if (modp == NULL)
2895 2896                          return (EINVAL);
2896 2897          } else {
2897 2898                  modp = mod_hold_by_id(id);
2898 2899                  if (modp == NULL)
2899 2900                          return (EINVAL);
2900 2901                  if (!(modinfop->mi_info & MI_INFO_CNT) &&
2901 2902                      (modp->mod_installed == 0)) {
2902 2903                          mod_release_mod(modp);
2903 2904                          return (EINVAL);
2904 2905                  }
2905 2906          }
2906 2907  
2907 2908          modinfop->mi_rev = 0;
2908 2909          modinfop->mi_state = 0;
2909 2910          for (i = 0; i < MODMAXLINK; i++) {
2910 2911                  modinfop->mi_msinfo[i].msi_p0 = -1;
2911 2912                  modinfop->mi_msinfo[i].msi_linkinfo[0] = 0;
2912 2913          }
2913 2914          if (modp->mod_loaded) {
2914 2915                  modinfop->mi_state = MI_LOADED;
2915 2916                  kobj_getmodinfo(modp->mod_mp, modinfop);
2916 2917          }
2917 2918          if (modp->mod_installed) {
2918 2919                  modinfop->mi_state |= MI_INSTALLED;
2919 2920  
2920 2921                  (void) mod_getinfo(modp, modinfop);
2921 2922          }
2922 2923  
2923 2924          modinfop->mi_id = modp->mod_id;
2924 2925          modinfop->mi_loadcnt = modp->mod_loadcnt;
2925 2926          (void) strcpy(modinfop->mi_name, modp->mod_modname);
2926 2927  
2927 2928          mod_release_mod(modp);
2928 2929          return (0);
2929 2930  }
2930 2931  
2931 2932  static char mod_stub_err[] = "mod_hold_stub: Couldn't load stub module %s";
2932 2933  static char no_err[] = "No error function for weak stub %s";
2933 2934  
2934 2935  /*
2935 2936   * used by the stubs themselves to load and hold a module.
2936 2937   * Returns  0 if the module is successfully held;
2937 2938   *          the stub needs to call mod_release_stub().
2938 2939   *          -1 if the stub should just call the err_fcn.
2939 2940   * Note that this code is stretched out so that we avoid subroutine calls
2940 2941   * and optimize for the most likely case.  That is, the case where the
2941 2942   * module is loaded and installed and not held.  In that case we just inc
2942 2943   * the mod_ref count and continue.
2943 2944   */
2944 2945  int
2945 2946  mod_hold_stub(struct mod_stub_info *stub)
2946 2947  {
2947 2948          struct modctl *mp;
2948 2949          struct mod_modinfo *mip;
2949 2950  
2950 2951          mip = stub->mods_modinfo;
2951 2952  
2952 2953          mutex_enter(&mod_lock);
2953 2954  
2954 2955          /* we do mod_hold_by_modctl inline for speed */
2955 2956  
2956 2957  mod_check_again:
2957 2958          if ((mp = mip->mp) != NULL) {
2958 2959                  if (mp->mod_busy == 0) {
2959 2960                          if (mp->mod_installed) {
2960 2961                                  /* increment the reference count */
2961 2962                                  mp->mod_ref++;
2962 2963                                  ASSERT(mp->mod_ref && mp->mod_installed);
2963 2964                                  mutex_exit(&mod_lock);
2964 2965                                  return (0);
2965 2966                          } else {
2966 2967                                  mp->mod_busy = 1;
2967 2968                                  mp->mod_inprogress_thread =
2968 2969                                      (curthread == NULL ?
2969 2970                                      (kthread_id_t)-1 : curthread);
2970 2971                          }
2971 2972                  } else {
2972 2973                          /*
2973 2974                           * wait one time and then go see if someone
2974 2975                           * else has resolved the stub (set mip->mp).
2975 2976                           */
2976 2977                          if (mod_hold_by_modctl(mp,
2977 2978                              MOD_WAIT_ONCE | MOD_LOCK_HELD))
2978 2979                                  goto mod_check_again;
2979 2980  
2980 2981                          /*
2981 2982                           * what we have now may have been unloaded!, in
2982 2983                           * that case, mip->mp will be NULL, we'll hit this
2983 2984                           * module and load again..
2984 2985                           */
2985 2986                          cmn_err(CE_PANIC, "mod_hold_stub should have blocked");
2986 2987                  }
2987 2988                  mutex_exit(&mod_lock);
2988 2989          } else {
2989 2990                  /* first time we've hit this module */
2990 2991                  mutex_exit(&mod_lock);
2991 2992                  mp = mod_hold_by_name(mip->modm_module_name);
2992 2993                  mip->mp = mp;
2993 2994          }
2994 2995  
2995 2996          /*
2996 2997           * If we are here, it means that the following conditions
2997 2998           * are satisfied.
2998 2999           *
2999 3000           * mip->mp != NULL
3000 3001           * this thread has set the mp->mod_busy = 1
3001 3002           * mp->mod_installed = 0
3002 3003           *
3003 3004           */
3004 3005          ASSERT(mp != NULL);
3005 3006          ASSERT(mp->mod_busy == 1);
3006 3007  
3007 3008          if (mp->mod_installed == 0) {
3008 3009                  /* Module not loaded, if weak stub don't load it */
3009 3010                  if (stub->mods_flag & MODS_WEAK) {
3010 3011                          if (stub->mods_errfcn == NULL) {
3011 3012                                  mod_release_mod(mp);
3012 3013                                  cmn_err(CE_PANIC, no_err,
3013 3014                                      mip->modm_module_name);
3014 3015                          }
3015 3016                  } else {
3016 3017                          /* Not a weak stub so load the module */
3017 3018  
3018 3019                          if (mod_load(mp, 1) != 0 || modinstall(mp) != 0) {
3019 3020                                  /*
3020 3021                                   * If mod_load() was successful
3021 3022                                   * and modinstall() failed, then
3022 3023                                   * unload the module.
3023 3024                                   */
3024 3025                                  if (mp->mod_loaded)
3025 3026                                          mod_unload(mp);
3026 3027  
3027 3028                                  mod_release_mod(mp);
3028 3029                                  if (stub->mods_errfcn == NULL) {
3029 3030                                          cmn_err(CE_PANIC, mod_stub_err,
3030 3031                                              mip->modm_module_name);
3031 3032                                  } else {
3032 3033                                          return (-1);
3033 3034                                  }
3034 3035                          }
3035 3036                  }
3036 3037          }
3037 3038  
3038 3039          /*
3039 3040           * At this point module is held and loaded. Release
3040 3041           * the mod_busy and mod_inprogress_thread before
3041 3042           * returning. We actually call mod_release() here so
3042 3043           * that if another stub wants to access this module,
3043 3044           * it can do so. mod_ref is incremented before mod_release()
3044 3045           * is called to prevent someone else from snatching the
3045 3046           * module from this thread.
3046 3047           */
3047 3048          mutex_enter(&mod_lock);
3048 3049          mp->mod_ref++;
3049 3050          ASSERT(mp->mod_ref &&
3050 3051              (mp->mod_loaded || (stub->mods_flag & MODS_WEAK)));
3051 3052          mod_release(mp);
3052 3053          mutex_exit(&mod_lock);
3053 3054          return (0);
3054 3055  }
3055 3056  
3056 3057  void
3057 3058  mod_release_stub(struct mod_stub_info *stub)
3058 3059  {
3059 3060          struct modctl *mp = stub->mods_modinfo->mp;
3060 3061  
3061 3062          /* inline mod_release_mod */
3062 3063          mutex_enter(&mod_lock);
3063 3064          ASSERT(mp->mod_ref &&
3064 3065              (mp->mod_loaded || (stub->mods_flag & MODS_WEAK)));
3065 3066          mp->mod_ref--;
3066 3067          if (mp->mod_ref == 0)
3067 3068                  mod_uninstall_ref_zero++;
3068 3069          if (mp->mod_want) {
3069 3070                  mp->mod_want = 0;
3070 3071                  cv_broadcast(&mod_cv);
3071 3072          }
3072 3073          mutex_exit(&mod_lock);
3073 3074  }
3074 3075  
3075 3076  static struct modctl *
3076 3077  mod_hold_loaded_mod(struct modctl *dep, char *filename, int *status)
3077 3078  {
3078 3079          struct modctl *modp;
3079 3080          int retval;
3080 3081  
3081 3082          /*
3082 3083           * Hold the module.
3083 3084           */
3084 3085          modp = mod_hold_by_name_requisite(dep, filename);
3085 3086          if (modp) {
3086 3087                  retval = mod_load(modp, 1);
3087 3088                  if (retval != 0) {
3088 3089                          mod_release_mod(modp);
3089 3090                          modp = NULL;
3090 3091                  }
3091 3092                  *status = retval;
3092 3093          } else {
3093 3094                  *status = ENOSPC;
3094 3095          }
3095 3096  
3096 3097          /*
3097 3098           * if dep is not NULL, clear the module dependency information.
3098 3099           * This information is set in mod_hold_by_name_common().
3099 3100           */
3100 3101          if (dep != NULL && dep->mod_requisite_loading != NULL) {
3101 3102                  ASSERT(dep->mod_busy);
3102 3103                  dep->mod_requisite_loading = NULL;
3103 3104          }
3104 3105  
3105 3106          return (modp);
3106 3107  }
3107 3108  
3108 3109  /*
3109 3110   * hold, load, and install the named module
3110 3111   */
3111 3112  static struct modctl *
3112 3113  mod_hold_installed_mod(char *name, int usepath, int forcecheck, int *r)
3113 3114  {
3114 3115          struct modctl *modp;
3115 3116          int retval;
3116 3117  
3117 3118          /*
3118 3119           * Verify that that module in question actually exists on disk
3119 3120           * before allocation of module structure by mod_hold_by_name.
3120 3121           */
3121 3122          if (modrootloaded && swaploaded || forcecheck) {
3122 3123                  if (!kobj_path_exists(name, usepath)) {
3123 3124                          *r = ENOENT;
3124 3125                          return (NULL);
3125 3126                  }
3126 3127          }
3127 3128  
3128 3129          /*
3129 3130           * Hold the module.
3130 3131           */
3131 3132          modp = mod_hold_by_name(name);
3132 3133          if (modp) {
3133 3134                  retval = mod_load(modp, usepath);
3134 3135                  if (retval != 0) {
3135 3136                          mod_release_mod(modp);
3136 3137                          modp = NULL;
3137 3138                          *r = retval;
3138 3139                  } else {
3139 3140                          if ((*r = modinstall(modp)) != 0) {
3140 3141                                  /*
3141 3142                                   * We loaded it, but failed to _init() it.
3142 3143                                   * Be kind to developers -- force it
3143 3144                                   * out of memory now so that the next
3144 3145                                   * attempt to use the module will cause
3145 3146                                   * a reload.  See 1093793.
3146 3147                                   */
3147 3148                                  mod_unload(modp);
3148 3149                                  mod_release_mod(modp);
3149 3150                                  modp = NULL;
3150 3151                          }
3151 3152                  }
3152 3153          } else {
3153 3154                  *r = ENOSPC;
3154 3155          }
3155 3156          return (modp);
3156 3157  }
3157 3158  
3158 3159  static char mod_excl_msg[] =
3159 3160          "module %s(%s) is EXCLUDED and will not be loaded\n";
3160 3161  static char mod_init_msg[] = "loadmodule:%s(%s): _init() error %d\n";
3161 3162  
3162 3163  /*
3163 3164   * This routine is needed for dependencies.  Users specify dependencies
3164 3165   * by declaring a character array initialized to filenames of dependents.
3165 3166   * So the code that handles dependents deals with filenames (and not
3166 3167   * module names) because that's all it has.  We load by filename and once
3167 3168   * we've loaded a file we can get the module name.
3168 3169   * Unfortunately there isn't a single unified filename/modulename namespace.
3169 3170   * C'est la vie.
3170 3171   *
3171 3172   * We allow the name being looked up to be prepended by an optional
3172 3173   * subdirectory e.g. we can lookup (NULL, "fs/ufs") or ("fs", "ufs")
3173 3174   */
3174 3175  struct modctl *
3175 3176  mod_find_by_filename(char *subdir, char *filename)
3176 3177  {
3177 3178          struct modctl   *mp;
3178 3179          size_t          sublen;
3179 3180  
3180 3181          ASSERT(!MUTEX_HELD(&mod_lock));
3181 3182          if (subdir != NULL)
3182 3183                  sublen = strlen(subdir);
3183 3184          else
3184 3185                  sublen = 0;
3185 3186  
3186 3187          mutex_enter(&mod_lock);
3187 3188          mp = &modules;
3188 3189          do {
3189 3190                  if (sublen) {
3190 3191                          char *mod_filename = mp->mod_filename;
3191 3192  
3192 3193                          if (strncmp(subdir, mod_filename, sublen) == 0 &&
3193 3194                              mod_filename[sublen] == '/' &&
3194 3195                              strcmp(filename, &mod_filename[sublen + 1]) == 0) {
3195 3196                                  mutex_exit(&mod_lock);
3196 3197                                  return (mp);
3197 3198                          }
3198 3199                  } else if (strcmp(filename, mp->mod_filename) == 0) {
3199 3200                          mutex_exit(&mod_lock);
3200 3201                          return (mp);
3201 3202                  }
3202 3203          } while ((mp = mp->mod_next) != &modules);
3203 3204          mutex_exit(&mod_lock);
3204 3205          return (NULL);
3205 3206  }
3206 3207  
3207 3208  /*
3208 3209   * Check for circular dependencies.  This is called from do_dependents()
3209 3210   * in kobj.c.  If we are the thread already loading this module, then
3210 3211   * we're trying to load a dependent that we're already loading which
3211 3212   * means the user specified circular dependencies.
3212 3213   */
3213 3214  static int
3214 3215  mod_circdep(struct modctl *modp)
3215 3216  {
3216 3217          struct modctl   *rmod;
3217 3218  
3218 3219          ASSERT(MUTEX_HELD(&mod_lock));
3219 3220  
3220 3221          /*
3221 3222           * Check the mod_inprogress_thread first.
3222 3223           * mod_inprogress_thread is used in mod_hold_stub()
3223 3224           * directly to improve performance.
3224 3225           */
3225 3226          if (modp->mod_inprogress_thread == curthread)
3226 3227                  return (1);
3227 3228  
3228 3229          /*
3229 3230           * Check the module circular dependencies.
3230 3231           */
3231 3232          for (rmod = modp; rmod != NULL; rmod = rmod->mod_requisite_loading) {
3232 3233                  /*
3233 3234                   * Check if there is a module circular dependency.
3234 3235                   */
3235 3236                  if (rmod->mod_requisite_loading == modp)
3236 3237                          return (1);
3237 3238          }
3238 3239          return (0);
3239 3240  }
3240 3241  
3241 3242  static int
3242 3243  mod_getinfo(struct modctl *modp, struct modinfo *modinfop)
3243 3244  {
3244 3245          int (*func)(struct modinfo *);
3245 3246          int retval;
3246 3247  
3247 3248          ASSERT(modp->mod_busy);
3248 3249  
3249 3250          /* primary modules don't do getinfo */
3250 3251          if (modp->mod_prim)
3251 3252                  return (0);
3252 3253  
3253 3254          func = (int (*)(struct modinfo *))kobj_lookup(modp->mod_mp, "_info");
3254 3255  
3255 3256          if (kobj_addrcheck(modp->mod_mp, (caddr_t)func)) {
3256 3257                  cmn_err(CE_WARN, "_info() not defined properly in %s",
3257 3258                      modp->mod_filename);
3258 3259                  /*
3259 3260                   * The semantics of mod_info(9F) are that 0 is failure
3260 3261                   * and non-zero is success.
3261 3262                   */
3262 3263                  retval = 0;
3263 3264          } else
3264 3265                  retval = (*func)(modinfop);     /* call _info() function */
3265 3266  
3266 3267          if (moddebug & MODDEBUG_USERDEBUG)
3267 3268                  printf("Returned from _info, retval = %x\n", retval);
3268 3269  
3269 3270          return (retval);
3270 3271  }
3271 3272  
3272 3273  static void
3273 3274  modadd(struct modctl *mp)
3274 3275  {
3275 3276          ASSERT(MUTEX_HELD(&mod_lock));
3276 3277  
3277 3278          mp->mod_id = last_module_id++;
3278 3279          mp->mod_next = &modules;
3279 3280          mp->mod_prev = modules.mod_prev;
3280 3281          modules.mod_prev->mod_next = mp;
3281 3282          modules.mod_prev = mp;
3282 3283  }
3283 3284  
3284 3285  /*ARGSUSED*/
3285 3286  static struct modctl *
3286 3287  allocate_modp(const char *filename, const char *modname)
3287 3288  {
3288 3289          struct modctl *mp;
3289 3290  
3290 3291          mp = kobj_zalloc(sizeof (*mp), KM_SLEEP);
3291 3292          mp->mod_modname = kobj_zalloc(strlen(modname) + 1, KM_SLEEP);
3292 3293          (void) strcpy(mp->mod_modname, modname);
3293 3294          return (mp);
3294 3295  }
3295 3296  
3296 3297  /*
3297 3298   * Get the value of a symbol.  This is a wrapper routine that
3298 3299   * calls kobj_getsymvalue().  kobj_getsymvalue() may go away but this
3299 3300   * wrapper will prevent callers from noticing.
3300 3301   */
3301 3302  uintptr_t
3302 3303  modgetsymvalue(char *name, int kernelonly)
3303 3304  {
3304 3305          return (kobj_getsymvalue(name, kernelonly));
3305 3306  }
3306 3307  
3307 3308  /*
3308 3309   * Get the symbol nearest an address.  This is a wrapper routine that
3309 3310   * calls kobj_getsymname().  kobj_getsymname() may go away but this
3310 3311   * wrapper will prevent callers from noticing.
3311 3312   */
3312 3313  char *
3313 3314  modgetsymname(uintptr_t value, ulong_t *offset)
3314 3315  {
3315 3316          return (kobj_getsymname(value, offset));
3316 3317  }
3317 3318  
3318 3319  /*
3319 3320   * Lookup a symbol in a specified module.  These are wrapper routines that
3320 3321   * call kobj_lookup().  kobj_lookup() may go away but these wrappers will
3321 3322   * prevent callers from noticing.
3322 3323   */
3323 3324  uintptr_t
3324 3325  modlookup(const char *modname, const char *symname)
3325 3326  {
3326 3327          struct modctl *modp;
3327 3328          uintptr_t val;
3328 3329  
3329 3330          if ((modp = mod_hold_by_name(modname)) == NULL)
3330 3331                  return (0);
3331 3332          val = kobj_lookup(modp->mod_mp, symname);
3332 3333          mod_release_mod(modp);
3333 3334          return (val);
3334 3335  }
3335 3336  
3336 3337  uintptr_t
3337 3338  modlookup_by_modctl(modctl_t *modp, const char *symname)
3338 3339  {
3339 3340          ASSERT(modp->mod_ref > 0 || modp->mod_busy);
3340 3341  
3341 3342          return (kobj_lookup(modp->mod_mp, symname));
3342 3343  }
3343 3344  
3344 3345  /*
3345 3346   * Ask the user for the name of the system file and the default path
3346 3347   * for modules.
3347 3348   */
3348 3349  void
3349 3350  mod_askparams()
3350 3351  {
3351 3352          static char s0[64];
3352 3353          intptr_t fd;
3353 3354  
3354 3355          if ((fd = kobj_open(systemfile)) != -1L)
3355 3356                  kobj_close(fd);
3356 3357          else
3357 3358                  systemfile = self_assembly = NULL;
3358 3359  
3359 3360          /*CONSTANTCONDITION*/
3360 3361          while (1) {
3361 3362                  printf("Name of system file [%s]:  ",
3362 3363                      systemfile ? systemfile : "/dev/null");
3363 3364  
3364 3365                  console_gets(s0, sizeof (s0));
3365 3366  
3366 3367                  if (s0[0] == '\0')
3367 3368                          break;
3368 3369                  else if (strcmp(s0, "/dev/null") == 0) {
3369 3370                          systemfile = self_assembly = NULL;
3370 3371                          break;
3371 3372                  } else {
3372 3373                          if ((fd = kobj_open(s0)) != -1L) {
3373 3374                                  kobj_close(fd);
3374 3375                                  systemfile = s0;
3375 3376                                  self_assembly = NULL;
3376 3377                                  break;
3377 3378                          }
3378 3379                  }
3379 3380                  printf("can't find file %s\n", s0);
3380 3381          }
3381 3382  }
3382 3383  
3383 3384  static char loading_msg[] = "loading '%s' id %d\n";
3384 3385  static char load_msg[] = "load '%s' id %d loaded @ 0x%p/0x%p size %d/%d\n";
3385 3386  
3386 3387  /*
3387 3388   * Common code for loading a module (but not installing it).
3388 3389   * Handoff the task of module loading to a separate thread
3389 3390   * with a large stack if possible, since this code may recurse a few times.
3390 3391   * Return zero if there are no errors or an errno value.
3391 3392   */
3392 3393  static int
3393 3394  mod_load(struct modctl *mp, int usepath)
3394 3395  {
3395 3396          int             retval;
3396 3397          struct modinfo  *modinfop = NULL;
3397 3398          struct loadmt   lt;
3398 3399  
3399 3400          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3400 3401          ASSERT(mp->mod_busy);
3401 3402  
3402 3403          if (mp->mod_loaded)
3403 3404                  return (0);
3404 3405  
3405 3406          if (mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_modname) != 0 ||
3406 3407              mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_filename) != 0) {
3407 3408                  if (moddebug & MODDEBUG_LOADMSG) {
3408 3409                          printf(mod_excl_msg, mp->mod_filename,
3409 3410                              mp->mod_modname);
3410 3411                  }
3411 3412                  return (ENXIO);
3412 3413          }
3413 3414          if (moddebug & MODDEBUG_LOADMSG2)
3414 3415                  printf(loading_msg, mp->mod_filename, mp->mod_id);
3415 3416  
3416 3417          if (curthread != &t0) {
3417 3418                  lt.mp = mp;
3418 3419                  lt.usepath = usepath;
3419 3420                  lt.owner = curthread;
3420 3421                  sema_init(<.sema, 0, NULL, SEMA_DEFAULT, NULL);
3421 3422  
3422 3423                  /* create thread to hand of call to */
3423 3424                  (void) thread_create(NULL, DEFAULTSTKSZ * 2,
3424 3425                      modload_thread, <, 0, &p0, TS_RUN, maxclsyspri);
3425 3426  
3426 3427                  /* wait for thread to complete kobj_load_module */
3427 3428                  sema_p(<.sema);
3428 3429  
3429 3430                  sema_destroy(<.sema);
3430 3431                  retval = lt.retval;
3431 3432          } else
3432 3433                  retval = kobj_load_module(mp, usepath);
3433 3434  
3434 3435          if (mp->mod_mp) {
3435 3436                  ASSERT(retval == 0);
3436 3437                  mp->mod_loaded = 1;
3437 3438                  mp->mod_loadcnt++;
3438 3439                  if (moddebug & MODDEBUG_LOADMSG) {
3439 3440                          printf(load_msg, mp->mod_filename, mp->mod_id,
3440 3441                              (void *)((struct module *)mp->mod_mp)->text,
3441 3442                              (void *)((struct module *)mp->mod_mp)->data,
3442 3443                              ((struct module *)mp->mod_mp)->text_size,
3443 3444                              ((struct module *)mp->mod_mp)->data_size);
3444 3445                  }
3445 3446  
3446 3447                  /*
3447 3448                   * XXX - There should be a better way to get this.
3448 3449                   */
3449 3450                  modinfop = kmem_zalloc(sizeof (struct modinfo), KM_SLEEP);
3450 3451                  modinfop->mi_info = MI_INFO_LINKAGE;
3451 3452                  if (mod_getinfo(mp, modinfop) == 0)
3452 3453                          mp->mod_linkage = NULL;
3453 3454                  else {
3454 3455                          mp->mod_linkage = (void *)modinfop->mi_base;
3455 3456                          ASSERT(mp->mod_linkage->ml_rev == MODREV_1);
3456 3457                  }
3457 3458  
3458 3459                  /*
3459 3460                   * DCS: bootstrapping code. If the driver is loaded
3460 3461                   * before root mount, it is assumed that the driver
3461 3462                   * may be used before mounting root. In order to
3462 3463                   * access mappings of global to local minor no.'s
3463 3464                   * during installation/open of the driver, we load
3464 3465                   * them into memory here while the BOP_interfaces
3465 3466                   * are still up.
  
    | 
      ↓ open down ↓ | 
    3432 lines elided | 
    
      ↑ open up ↑ | 
  
3466 3467                   */
3467 3468                  if ((cluster_bootflags & CLUSTER_BOOTED) && !modrootloaded) {
3468 3469                          retval = clboot_modload(mp);
3469 3470                  }
3470 3471  
3471 3472                  kmem_free(modinfop, sizeof (struct modinfo));
3472 3473                  (void) mod_sysctl(SYS_SET_MVAR, (void *)mp);
3473 3474                  retval = install_stubs_by_name(mp, mp->mod_modname);
3474 3475  
3475 3476                  /*
     3477 +                 * Perform hotinlines before module is started.
     3478 +                 */
     3479 +                do_hotinlines(mp->mod_mp);
     3480 +
     3481 +                /*
3476 3482                   * Now that the module is loaded, we need to give DTrace
3477 3483                   * a chance to notify its providers.  This is done via
3478 3484                   * the dtrace_modload function pointer.
3479 3485                   */
3480 3486                  if (strcmp(mp->mod_modname, "dtrace") != 0) {
3481 3487                          struct modctl *dmp = mod_hold_by_name("dtrace");
3482 3488  
3483 3489                          if (dmp != NULL && dtrace_modload != NULL)
3484 3490                                  (*dtrace_modload)(mp);
3485 3491  
3486 3492                          mod_release_mod(dmp);
3487 3493                  }
3488 3494  
3489 3495          } else {
3490 3496                  /*
3491 3497                   * If load failed then we need to release any requisites
3492 3498                   * that we had established.
3493 3499                   */
3494 3500                  ASSERT(retval);
3495 3501                  mod_release_requisites(mp);
3496 3502  
3497 3503                  if (moddebug & MODDEBUG_ERRMSG)
3498 3504                          printf("error loading '%s', error %d\n",
3499 3505                              mp->mod_filename, retval);
3500 3506          }
3501 3507          return (retval);
3502 3508  }
3503 3509  
3504 3510  static char unload_msg[] = "unloading %s, module id %d, loadcnt %d.\n";
3505 3511  
3506 3512  static void
3507 3513  mod_unload(struct modctl *mp)
3508 3514  {
3509 3515          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3510 3516          ASSERT(mp->mod_busy);
3511 3517          ASSERT((mp->mod_loaded && (mp->mod_installed == 0)) &&
3512 3518              ((mp->mod_prim == 0) && (mp->mod_ref >= 0)));
3513 3519  
3514 3520          if (moddebug & MODDEBUG_LOADMSG)
3515 3521                  printf(unload_msg, mp->mod_modname,
3516 3522                      mp->mod_id, mp->mod_loadcnt);
3517 3523  
3518 3524          /*
3519 3525           * If mod_ref is not zero, it means some modules might still refer
3520 3526           * to this module. Then you can't unload this module right now.
3521 3527           * Instead, set 1 to mod_delay_unload to notify the system of
3522 3528           * unloading this module later when it's not required any more.
3523 3529           */
3524 3530          if (mp->mod_ref > 0) {
3525 3531                  mp->mod_delay_unload = 1;
3526 3532                  if (moddebug & MODDEBUG_LOADMSG2) {
3527 3533                          printf("module %s not unloaded,"
3528 3534                              " non-zero reference count (%d)",
3529 3535                              mp->mod_modname, mp->mod_ref);
3530 3536                  }
3531 3537                  return;
3532 3538          }
3533 3539  
3534 3540          if (((mp->mod_loaded == 0) || mp->mod_installed) ||
3535 3541              (mp->mod_ref || mp->mod_prim)) {
3536 3542                  /*
3537 3543                   * A DEBUG kernel would ASSERT panic above, the code is broken
3538 3544                   * if we get this warning.
3539 3545                   */
3540 3546                  cmn_err(CE_WARN, "mod_unload: %s in incorrect state: %d %d %d",
3541 3547                      mp->mod_filename, mp->mod_installed, mp->mod_loaded,
3542 3548                      mp->mod_ref);
3543 3549                  return;
3544 3550          }
3545 3551  
3546 3552          /* reset stub functions to call the binder again */
3547 3553          reset_stubs(mp);
3548 3554  
3549 3555          /*
3550 3556           * mark module as unloaded before the modctl structure is freed.
3551 3557           * This is required not to reuse the modctl structure before
3552 3558           * the module is marked as unloaded.
3553 3559           */
3554 3560          mp->mod_loaded = 0;
3555 3561          mp->mod_linkage = NULL;
3556 3562  
3557 3563          /* free the memory */
3558 3564          kobj_unload_module(mp);
3559 3565  
3560 3566          if (mp->mod_delay_unload) {
3561 3567                  mp->mod_delay_unload = 0;
3562 3568                  if (moddebug & MODDEBUG_LOADMSG2) {
3563 3569                          printf("deferred unload of module %s"
3564 3570                              " (id %d) successful",
3565 3571                              mp->mod_modname, mp->mod_id);
3566 3572                  }
3567 3573          }
3568 3574  
3569 3575          /* release hold on requisites */
3570 3576          mod_release_requisites(mp);
3571 3577  
3572 3578          /*
3573 3579           * Now that the module is gone, we need to give DTrace a chance to
3574 3580           * remove any probes that it may have had in the module.  This is
3575 3581           * done via the dtrace_modunload function pointer.
3576 3582           */
3577 3583          if (strcmp(mp->mod_modname, "dtrace") != 0) {
3578 3584                  struct modctl *dmp = mod_hold_by_name("dtrace");
3579 3585  
3580 3586                  if (dmp != NULL && dtrace_modunload != NULL)
3581 3587                          (*dtrace_modunload)(mp);
3582 3588  
3583 3589                  mod_release_mod(dmp);
3584 3590          }
3585 3591  }
3586 3592  
3587 3593  static int
3588 3594  modinstall(struct modctl *mp)
3589 3595  {
3590 3596          int val;
3591 3597          int (*func)(void);
3592 3598  
3593 3599          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3594 3600          ASSERT(mp->mod_busy && mp->mod_loaded);
3595 3601  
3596 3602          if (mp->mod_installed)
3597 3603                  return (0);
3598 3604          /*
3599 3605           * If mod_delay_unload is on, it means the system chose the deferred
3600 3606           * unload for this module. Then you can't install this module until
3601 3607           * it's unloaded from the system.
3602 3608           */
3603 3609          if (mp->mod_delay_unload)
3604 3610                  return (ENXIO);
3605 3611  
3606 3612          if (moddebug & MODDEBUG_LOADMSG)
3607 3613                  printf("installing %s, module id %d.\n",
3608 3614                      mp->mod_modname, mp->mod_id);
3609 3615  
3610 3616          ASSERT(mp->mod_mp != NULL);
3611 3617          if (mod_install_requisites(mp) != 0) {
3612 3618                  /*
3613 3619                   * Note that we can't call mod_unload(mp) here since
3614 3620                   * if modinstall() was called by mod_install_requisites(),
3615 3621                   * we won't be able to hold the dependent modules
3616 3622                   * (otherwise there would be a deadlock).
3617 3623                   */
3618 3624                  return (ENXIO);
3619 3625          }
3620 3626  
3621 3627          if (moddebug & MODDEBUG_ERRMSG) {
3622 3628                  printf("init '%s' id %d loaded @ 0x%p/0x%p size %lu/%lu\n",
3623 3629                      mp->mod_filename, mp->mod_id,
3624 3630                      (void *)((struct module *)mp->mod_mp)->text,
3625 3631                      (void *)((struct module *)mp->mod_mp)->data,
3626 3632                      ((struct module *)mp->mod_mp)->text_size,
3627 3633                      ((struct module *)mp->mod_mp)->data_size);
3628 3634          }
3629 3635  
3630 3636          func = (int (*)())kobj_lookup(mp->mod_mp, "_init");
3631 3637  
3632 3638          if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) {
3633 3639                  cmn_err(CE_WARN, "_init() not defined properly in %s",
3634 3640                      mp->mod_filename);
3635 3641                  return (EFAULT);
3636 3642          }
3637 3643  
3638 3644          if (moddebug & MODDEBUG_USERDEBUG) {
3639 3645                  printf("breakpoint before calling %s:_init()\n",
3640 3646                      mp->mod_modname);
3641 3647                  if (DEBUGGER_PRESENT)
3642 3648                          debug_enter("_init");
3643 3649          }
3644 3650  
3645 3651          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3646 3652          ASSERT(mp->mod_busy && mp->mod_loaded);
3647 3653          val = (*func)();                /* call _init */
3648 3654  
3649 3655          if (moddebug & MODDEBUG_USERDEBUG)
3650 3656                  printf("Returned from _init, val = %x\n", val);
3651 3657  
3652 3658          if (val == 0) {
3653 3659                  /*
3654 3660                   * Set the MODS_INSTALLED flag to enable this module
3655 3661                   * being called now.
3656 3662                   */
3657 3663                  install_stubs(mp);
3658 3664                  mp->mod_installed = 1;
3659 3665          } else if (moddebug & MODDEBUG_ERRMSG)
3660 3666                  printf(mod_init_msg, mp->mod_filename, mp->mod_modname, val);
3661 3667  
3662 3668          return (val);
3663 3669  }
3664 3670  
3665 3671  int     detach_driver_unconfig = 0;
3666 3672  
3667 3673  static int
3668 3674  detach_driver(char *name)
3669 3675  {
3670 3676          major_t major;
3671 3677          int error;
3672 3678  
3673 3679          /*
3674 3680           * If being called from mod_uninstall_all() then the appropriate
3675 3681           * driver detaches (leaf only) have already been done.
3676 3682           */
3677 3683          if (mod_in_autounload())
3678 3684                  return (0);
3679 3685  
3680 3686          major = ddi_name_to_major(name);
3681 3687          if (major == DDI_MAJOR_T_NONE)
3682 3688                  return (0);
3683 3689  
3684 3690          error = ndi_devi_unconfig_driver(ddi_root_node(),
3685 3691              NDI_DETACH_DRIVER | detach_driver_unconfig, major);
3686 3692          return (error == NDI_SUCCESS ? 0 : -1);
3687 3693  }
3688 3694  
3689 3695  static char finiret_msg[] = "Returned from _fini for %s, status = %x\n";
3690 3696  
3691 3697  static int
3692 3698  moduninstall(struct modctl *mp)
3693 3699  {
3694 3700          int status = 0;
3695 3701          int (*func)(void);
3696 3702  
3697 3703          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3698 3704          ASSERT(mp->mod_busy);
3699 3705  
3700 3706          /*
3701 3707           * Verify that we need to do something and can uninstall the module.
3702 3708           *
3703 3709           * If we should not uninstall the module or if the module is not in
3704 3710           * the correct state to start an uninstall we return EBUSY to prevent
3705 3711           * us from progressing to mod_unload.  If the module has already been
3706 3712           * uninstalled and unloaded we return EALREADY.
3707 3713           */
3708 3714          if (mp->mod_prim || mp->mod_ref || mp->mod_nenabled != 0)
3709 3715                  return (EBUSY);
3710 3716          if ((mp->mod_installed == 0) || (mp->mod_loaded == 0))
3711 3717                  return (EALREADY);
3712 3718  
3713 3719          /*
3714 3720           * To avoid devinfo / module deadlock we must release this module
3715 3721           * prior to initiating the detach_driver, otherwise the detach_driver
3716 3722           * might deadlock on a devinfo node held by another thread
3717 3723           * coming top down and involving the module we have locked.
3718 3724           *
3719 3725           * When we regrab the module we must reverify that it is OK
3720 3726           * to proceed with the uninstall operation.
3721 3727           */
3722 3728          mod_release_mod(mp);
3723 3729          status = detach_driver(mp->mod_modname);
3724 3730          (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
3725 3731  
3726 3732          /* check detach status and reverify state with lock */
3727 3733          mutex_enter(&mod_lock);
3728 3734          if ((status != 0) || mp->mod_prim || mp->mod_ref) {
3729 3735                  mutex_exit(&mod_lock);
3730 3736                  return (EBUSY);
3731 3737          }
3732 3738          if ((mp->mod_installed == 0) || (mp->mod_loaded == 0)) {
3733 3739                  mutex_exit(&mod_lock);
3734 3740                  return (EALREADY);
3735 3741          }
3736 3742          mutex_exit(&mod_lock);
3737 3743  
3738 3744          if (moddebug & MODDEBUG_LOADMSG2)
3739 3745                  printf("uninstalling %s\n", mp->mod_modname);
3740 3746  
3741 3747          /*
3742 3748           * lookup _fini, return EBUSY if not defined.
3743 3749           *
3744 3750           * The MODDEBUG_FINI_EBUSY is usefull in resolving leaks in
3745 3751           * detach(9E) - it allows bufctl addresses to be resolved.
3746 3752           */
3747 3753          func = (int (*)())kobj_lookup(mp->mod_mp, "_fini");
3748 3754          if ((func == NULL) || (mp->mod_loadflags & MOD_NOUNLOAD) ||
3749 3755              (moddebug & MODDEBUG_FINI_EBUSY))
3750 3756                  return (EBUSY);
3751 3757  
3752 3758          /* verify that _fini is in this module */
3753 3759          if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) {
3754 3760                  cmn_err(CE_WARN, "_fini() not defined properly in %s",
3755 3761                      mp->mod_filename);
3756 3762                  return (EFAULT);
3757 3763          }
3758 3764  
3759 3765          /* call _fini() */
3760 3766          ASSERT(MUTEX_NOT_HELD(&mod_lock));
3761 3767          ASSERT(mp->mod_busy && mp->mod_loaded && mp->mod_installed);
3762 3768  
3763 3769          status = (*func)();
3764 3770  
3765 3771          if (status == 0) {
3766 3772                  /* _fini returned success, the module is no longer installed */
3767 3773                  if (moddebug & MODDEBUG_LOADMSG)
3768 3774                          printf("uninstalled %s\n", mp->mod_modname);
3769 3775  
3770 3776                  /*
3771 3777                   * Even though we only set mod_installed to zero here, a zero
3772 3778                   * return value means we are committed to a code path were
3773 3779                   * mod_loaded will also end up as zero - we have no other
3774 3780                   * way to get the module data and bss back to the pre _init
3775 3781                   * state except a reload. To ensure this, after return,
3776 3782                   * mod_busy must stay set until mod_loaded is cleared.
3777 3783                   */
3778 3784                  mp->mod_installed = 0;
3779 3785  
3780 3786                  /*
3781 3787                   * Clear the MODS_INSTALLED flag not to call functions
3782 3788                   * in the module directly from now on.
3783 3789                   */
3784 3790                  uninstall_stubs(mp);
3785 3791          } else {
3786 3792                  if (moddebug & MODDEBUG_USERDEBUG)
3787 3793                          printf(finiret_msg, mp->mod_filename, status);
3788 3794                  /*
3789 3795                   * By definition _fini is only allowed to return EBUSY or the
3790 3796                   * result of mod_remove (EBUSY or EINVAL).  In the off chance
3791 3797                   * that a driver returns EALREADY we convert this to EINVAL
3792 3798                   * since to our caller EALREADY means module was already
3793 3799                   * removed.
3794 3800                   */
3795 3801                  if (status == EALREADY)
3796 3802                          status = EINVAL;
3797 3803          }
3798 3804  
3799 3805          return (status);
3800 3806  }
3801 3807  
3802 3808  /*
3803 3809   * Uninstall all modules.
3804 3810   */
3805 3811  static void
3806 3812  mod_uninstall_all(void)
3807 3813  {
3808 3814          struct modctl   *mp;
3809 3815          int             pass;
3810 3816          modid_t         modid;
3811 3817  
3812 3818          /* synchronize with any active modunload_disable() */
3813 3819          modunload_begin();
3814 3820  
3815 3821          /* mark this thread as doing autounloading */
3816 3822          (void) tsd_set(mod_autounload_key, (void *)1);
3817 3823  
3818 3824          (void) devfs_clean(ddi_root_node(), NULL, 0);
3819 3825          (void) ndi_devi_unconfig(ddi_root_node(), NDI_AUTODETACH);
3820 3826  
3821 3827          /*
3822 3828           * Loop up to max times if we keep producing unreferenced modules.
3823 3829           * A new unreferenced module is an opportunity to unload.
3824 3830           */
3825 3831          for (pass = 0; pass < mod_uninstall_pass_max; pass++) {
3826 3832  
3827 3833                  /* zero count of modules that go unreferenced during pass */
3828 3834                  mod_uninstall_ref_zero = 0;
3829 3835  
3830 3836                  modid = 0;
3831 3837                  while ((mp = mod_hold_next_by_id(modid)) != NULL) {
3832 3838                          modid = mp->mod_id;
3833 3839  
3834 3840                          /*
3835 3841                           * Skip modules with the MOD_NOAUTOUNLOAD flag set
3836 3842                           */
3837 3843                          if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
3838 3844                                  mod_release_mod(mp);
3839 3845                                  continue;
3840 3846                          }
3841 3847  
3842 3848                          if (moduninstall(mp) == 0) {
3843 3849                                  mod_unload(mp);
3844 3850                                  CPU_STATS_ADDQ(CPU, sys, modunload, 1);
3845 3851                          }
3846 3852                          mod_release_mod(mp);
3847 3853                  }
3848 3854  
3849 3855                  /* break if no modules went unreferenced during pass */
3850 3856                  if (mod_uninstall_ref_zero == 0)
3851 3857                          break;
3852 3858          }
3853 3859          if (pass >= mod_uninstall_pass_max)
3854 3860                  mod_uninstall_pass_exc++;
3855 3861  
3856 3862          (void) tsd_set(mod_autounload_key, NULL);
3857 3863          modunload_end();
3858 3864  }
3859 3865  
3860 3866  /* wait for unloads that have begun before registering disable */
3861 3867  void
3862 3868  modunload_disable(void)
3863 3869  {
3864 3870          mutex_enter(&modunload_wait_mutex);
3865 3871          while (modunload_active_count) {
3866 3872                  modunload_wait++;
3867 3873                  cv_wait(&modunload_wait_cv, &modunload_wait_mutex);
3868 3874                  modunload_wait--;
3869 3875          }
3870 3876          modunload_disable_count++;
3871 3877          mutex_exit(&modunload_wait_mutex);
3872 3878  }
3873 3879  
3874 3880  /* mark end of disable and signal waiters */
3875 3881  void
3876 3882  modunload_enable(void)
3877 3883  {
3878 3884          mutex_enter(&modunload_wait_mutex);
3879 3885          modunload_disable_count--;
3880 3886          if ((modunload_disable_count == 0) && modunload_wait)
3881 3887                  cv_broadcast(&modunload_wait_cv);
3882 3888          mutex_exit(&modunload_wait_mutex);
3883 3889  }
3884 3890  
3885 3891  /* wait for disables to complete before begining unload */
3886 3892  void
3887 3893  modunload_begin()
3888 3894  {
3889 3895          mutex_enter(&modunload_wait_mutex);
3890 3896          while (modunload_disable_count) {
3891 3897                  modunload_wait++;
3892 3898                  cv_wait(&modunload_wait_cv, &modunload_wait_mutex);
3893 3899                  modunload_wait--;
3894 3900          }
3895 3901          modunload_active_count++;
3896 3902          mutex_exit(&modunload_wait_mutex);
3897 3903  }
3898 3904  
3899 3905  /* mark end of unload and signal waiters */
3900 3906  void
3901 3907  modunload_end()
3902 3908  {
3903 3909          mutex_enter(&modunload_wait_mutex);
3904 3910          modunload_active_count--;
3905 3911          if ((modunload_active_count == 0) && modunload_wait)
3906 3912                  cv_broadcast(&modunload_wait_cv);
3907 3913          mutex_exit(&modunload_wait_mutex);
3908 3914  }
3909 3915  
3910 3916  void
3911 3917  mod_uninstall_daemon(void)
3912 3918  {
3913 3919          callb_cpr_t     cprinfo;
3914 3920          clock_t         ticks;
3915 3921  
3916 3922          mod_aul_thread = curthread;
3917 3923  
3918 3924          CALLB_CPR_INIT(&cprinfo, &mod_uninstall_lock, callb_generic_cpr, "mud");
3919 3925          for (;;) {
3920 3926                  mutex_enter(&mod_uninstall_lock);
3921 3927                  CALLB_CPR_SAFE_BEGIN(&cprinfo);
3922 3928                  /*
3923 3929                   * In DEBUG kernels, unheld drivers are uninstalled periodically
3924 3930                   * every mod_uninstall_interval seconds.  Periodic uninstall can
3925 3931                   * be disabled by setting mod_uninstall_interval to 0 which is
3926 3932                   * the default for a non-DEBUG kernel.
3927 3933                   */
3928 3934                  if (mod_uninstall_interval) {
3929 3935                          ticks = drv_usectohz(mod_uninstall_interval * 1000000);
3930 3936                          (void) cv_reltimedwait(&mod_uninstall_cv,
3931 3937                              &mod_uninstall_lock, ticks, TR_CLOCK_TICK);
3932 3938                  } else {
3933 3939                          cv_wait(&mod_uninstall_cv, &mod_uninstall_lock);
3934 3940                  }
3935 3941                  /*
3936 3942                   * The whole daemon is safe for CPR except we don't want
3937 3943                   * the daemon to run if FREEZE is issued and this daemon
3938 3944                   * wakes up from the cv_wait above. In this case, it'll be
3939 3945                   * blocked in CALLB_CPR_SAFE_END until THAW is issued.
3940 3946                   *
3941 3947                   * The reason of calling CALLB_CPR_SAFE_BEGIN twice is that
3942 3948                   * mod_uninstall_lock is used to protect cprinfo and
3943 3949                   * CALLB_CPR_SAFE_BEGIN assumes that this lock is held when
3944 3950                   * called.
3945 3951                   */
3946 3952                  CALLB_CPR_SAFE_END(&cprinfo, &mod_uninstall_lock);
3947 3953                  CALLB_CPR_SAFE_BEGIN(&cprinfo);
3948 3954                  mutex_exit(&mod_uninstall_lock);
3949 3955                  if ((modunload_disable_count == 0) &&
3950 3956                      ((moddebug & MODDEBUG_NOAUTOUNLOAD) == 0)) {
3951 3957                          mod_uninstall_all();
3952 3958                  }
3953 3959          }
3954 3960  }
3955 3961  
3956 3962  /*
3957 3963   * Unload all uninstalled modules.
3958 3964   */
3959 3965  void
3960 3966  modreap(void)
3961 3967  {
3962 3968          mutex_enter(&mod_uninstall_lock);
3963 3969          cv_broadcast(&mod_uninstall_cv);
3964 3970          mutex_exit(&mod_uninstall_lock);
3965 3971  }
3966 3972  
3967 3973  /*
3968 3974   * Hold the specified module. This is the module holding primitive.
3969 3975   *
3970 3976   * If MOD_LOCK_HELD then the caller already holds the mod_lock.
3971 3977   *
3972 3978   * Return values:
3973 3979   *       0 ==> the module is held
3974 3980   *       1 ==> the module is not held and the MOD_WAIT_ONCE caller needs
3975 3981   *              to determine how to retry.
3976 3982   */
3977 3983  int
3978 3984  mod_hold_by_modctl(struct modctl *mp, int f)
3979 3985  {
3980 3986          ASSERT((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) &&
3981 3987              ((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) !=
3982 3988              (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)));
3983 3989          ASSERT((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) &&
3984 3990              ((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) !=
3985 3991              (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)));
3986 3992          ASSERT((f & MOD_LOCK_NOT_HELD) || MUTEX_HELD(&mod_lock));
3987 3993  
3988 3994          if (f & MOD_LOCK_NOT_HELD)
3989 3995                  mutex_enter(&mod_lock);
3990 3996  
3991 3997          while (mp->mod_busy) {
3992 3998                  mp->mod_want = 1;
3993 3999                  cv_wait(&mod_cv, &mod_lock);
3994 4000                  /*
3995 4001                   * Module may be unloaded by daemon.
3996 4002                   * Nevertheless, modctl structure is still in linked list
3997 4003                   * (i.e., off &modules), not freed!
3998 4004                   * Caller is not supposed to assume "mp" is valid, but there
3999 4005                   * is no reasonable way to detect this but using
4000 4006                   * mp->mod_modinfo->mp == NULL check (follow the back pointer)
4001 4007                   *   (or similar check depending on calling context)
4002 4008                   * DON'T free modctl structure, it will be very very
4003 4009                   * problematic.
4004 4010                   */
4005 4011                  if (f & MOD_WAIT_ONCE) {
4006 4012                          if (f & MOD_LOCK_NOT_HELD)
4007 4013                                  mutex_exit(&mod_lock);
4008 4014                          return (1);     /* caller decides how to retry */
4009 4015                  }
4010 4016          }
4011 4017  
4012 4018          mp->mod_busy = 1;
4013 4019          mp->mod_inprogress_thread =
4014 4020              (curthread == NULL ? (kthread_id_t)-1 : curthread);
4015 4021  
4016 4022          if (f & MOD_LOCK_NOT_HELD)
4017 4023                  mutex_exit(&mod_lock);
4018 4024          return (0);
4019 4025  }
4020 4026  
4021 4027  static struct modctl *
4022 4028  mod_hold_by_name_common(struct modctl *dep, const char *filename)
4023 4029  {
4024 4030          const char      *modname;
4025 4031          struct modctl   *mp;
4026 4032          char            *curname, *newname;
4027 4033          int             found = 0;
4028 4034  
4029 4035          mutex_enter(&mod_lock);
4030 4036  
4031 4037          if ((modname = strrchr(filename, '/')) == NULL)
4032 4038                  modname = filename;
4033 4039          else
4034 4040                  modname++;
4035 4041  
4036 4042          mp = &modules;
4037 4043          do {
4038 4044                  if (strcmp(modname, mp->mod_modname) == 0) {
4039 4045                          found = 1;
4040 4046                          break;
4041 4047                  }
4042 4048          } while ((mp = mp->mod_next) != &modules);
4043 4049  
4044 4050          if (found == 0) {
4045 4051                  mp = allocate_modp(filename, modname);
4046 4052                  modadd(mp);
4047 4053          }
4048 4054  
4049 4055          /*
4050 4056           * if dep is not NULL, set the mp in mod_requisite_loading for
4051 4057           * the module circular dependency check. This field is used in
4052 4058           * mod_circdep(), but it's cleard in mod_hold_loaded_mod().
4053 4059           */
4054 4060          if (dep != NULL) {
4055 4061                  ASSERT(dep->mod_busy && dep->mod_requisite_loading == NULL);
4056 4062                  dep->mod_requisite_loading = mp;
4057 4063          }
4058 4064  
4059 4065          /*
4060 4066           * If the module was held, then it must be us who has it held.
4061 4067           */
4062 4068          if (mod_circdep(mp))
4063 4069                  mp = NULL;
4064 4070          else {
4065 4071                  (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4066 4072  
4067 4073                  /*
4068 4074                   * If the name hadn't been set or has changed, allocate
4069 4075                   * space and set it.  Free space used by previous name.
4070 4076                   *
4071 4077                   * Do not change the name of primary modules, for primary
4072 4078                   * modules the mod_filename was allocated in standalone mode:
4073 4079                   * it is illegal to kobj_alloc in standalone mode and kobj_free
4074 4080                   * in non-standalone mode.
4075 4081                   */
4076 4082                  curname = mp->mod_filename;
4077 4083                  if (curname == NULL ||
4078 4084                      ((mp->mod_prim == 0) &&
4079 4085                      (curname != filename) &&
4080 4086                      (modname != filename) &&
4081 4087                      (strcmp(curname, filename) != 0))) {
4082 4088                          newname = kobj_zalloc(strlen(filename) + 1, KM_SLEEP);
4083 4089                          (void) strcpy(newname, filename);
4084 4090                          mp->mod_filename = newname;
4085 4091                          if (curname != NULL)
4086 4092                                  kobj_free(curname, strlen(curname) + 1);
4087 4093                  }
4088 4094          }
4089 4095  
4090 4096          mutex_exit(&mod_lock);
4091 4097          if (mp && moddebug & MODDEBUG_LOADMSG2)
4092 4098                  printf("Holding %s\n", mp->mod_filename);
4093 4099          if (mp == NULL && moddebug & MODDEBUG_LOADMSG2)
4094 4100                  printf("circular dependency loading %s\n", filename);
4095 4101          return (mp);
4096 4102  }
4097 4103  
4098 4104  static struct modctl *
4099 4105  mod_hold_by_name_requisite(struct modctl *dep, char *filename)
4100 4106  {
4101 4107          return (mod_hold_by_name_common(dep, filename));
4102 4108  }
4103 4109  
4104 4110  struct modctl *
4105 4111  mod_hold_by_name(const char *filename)
4106 4112  {
4107 4113          return (mod_hold_by_name_common(NULL, filename));
4108 4114  }
4109 4115  
4110 4116  struct modctl *
4111 4117  mod_hold_by_id(modid_t modid)
4112 4118  {
4113 4119          struct modctl   *mp;
4114 4120          int             found = 0;
4115 4121  
4116 4122          mutex_enter(&mod_lock);
4117 4123          mp = &modules;
4118 4124          do {
4119 4125                  if (mp->mod_id == modid) {
4120 4126                          found = 1;
4121 4127                          break;
4122 4128                  }
4123 4129          } while ((mp = mp->mod_next) != &modules);
4124 4130  
4125 4131          if ((found == 0) || mod_circdep(mp))
4126 4132                  mp = NULL;
4127 4133          else
4128 4134                  (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4129 4135  
4130 4136          mutex_exit(&mod_lock);
4131 4137          return (mp);
4132 4138  }
4133 4139  
4134 4140  static struct modctl *
4135 4141  mod_hold_next_by_id(modid_t modid)
4136 4142  {
4137 4143          struct modctl   *mp;
4138 4144          int             found = 0;
4139 4145  
4140 4146          if (modid < -1)
4141 4147                  return (NULL);
4142 4148  
4143 4149          mutex_enter(&mod_lock);
4144 4150  
4145 4151          mp = &modules;
4146 4152          do {
4147 4153                  if (mp->mod_id > modid) {
4148 4154                          found = 1;
4149 4155                          break;
4150 4156                  }
4151 4157          } while ((mp = mp->mod_next) != &modules);
4152 4158  
4153 4159          if ((found == 0) || mod_circdep(mp))
4154 4160                  mp = NULL;
4155 4161          else
4156 4162                  (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4157 4163  
4158 4164          mutex_exit(&mod_lock);
4159 4165          return (mp);
4160 4166  }
4161 4167  
4162 4168  static void
4163 4169  mod_release(struct modctl *mp)
4164 4170  {
4165 4171          ASSERT(MUTEX_HELD(&mod_lock));
4166 4172          ASSERT(mp->mod_busy);
4167 4173  
4168 4174          mp->mod_busy = 0;
4169 4175          mp->mod_inprogress_thread = NULL;
4170 4176          if (mp->mod_want) {
4171 4177                  mp->mod_want = 0;
4172 4178                  cv_broadcast(&mod_cv);
4173 4179          }
4174 4180  }
4175 4181  
4176 4182  void
4177 4183  mod_release_mod(struct modctl *mp)
4178 4184  {
4179 4185          if (moddebug & MODDEBUG_LOADMSG2)
4180 4186                  printf("Releasing %s\n", mp->mod_filename);
4181 4187          mutex_enter(&mod_lock);
4182 4188          mod_release(mp);
4183 4189          mutex_exit(&mod_lock);
4184 4190  }
4185 4191  
4186 4192  modid_t
4187 4193  mod_name_to_modid(char *filename)
4188 4194  {
4189 4195          char            *modname;
4190 4196          struct modctl   *mp;
4191 4197  
4192 4198          mutex_enter(&mod_lock);
4193 4199  
4194 4200          if ((modname = strrchr(filename, '/')) == NULL)
4195 4201                  modname = filename;
4196 4202          else
4197 4203                  modname++;
4198 4204  
4199 4205          mp = &modules;
4200 4206          do {
4201 4207                  if (strcmp(modname, mp->mod_modname) == 0) {
4202 4208                          mutex_exit(&mod_lock);
4203 4209                          return (mp->mod_id);
4204 4210                  }
4205 4211          } while ((mp = mp->mod_next) != &modules);
4206 4212  
4207 4213          mutex_exit(&mod_lock);
4208 4214          return (-1);
4209 4215  }
4210 4216  
4211 4217  
4212 4218  int
4213 4219  mod_remove_by_name(char *name)
4214 4220  {
4215 4221          struct modctl *mp;
4216 4222          int retval;
4217 4223  
4218 4224          mp = mod_hold_by_name(name);
4219 4225  
4220 4226          if (mp == NULL)
4221 4227                  return (EINVAL);
4222 4228  
4223 4229          if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
4224 4230                  /*
4225 4231                   * Do not unload forceloaded modules
4226 4232                   */
4227 4233                  mod_release_mod(mp);
4228 4234                  return (0);
4229 4235          }
4230 4236  
4231 4237          if ((retval = moduninstall(mp)) == 0) {
4232 4238                  mod_unload(mp);
4233 4239                  CPU_STATS_ADDQ(CPU, sys, modunload, 1);
4234 4240          } else if (retval == EALREADY)
4235 4241                  retval = 0;             /* already unloaded, not an error */
4236 4242          mod_release_mod(mp);
4237 4243          return (retval);
4238 4244  }
4239 4245  
4240 4246  /*
4241 4247   * Record that module "dep" is dependent on module "on_mod."
4242 4248   */
4243 4249  static void
4244 4250  mod_make_requisite(struct modctl *dependent, struct modctl *on_mod)
4245 4251  {
4246 4252          struct modctl_list **pmlnp;     /* previous next pointer */
4247 4253          struct modctl_list *mlp;
4248 4254          struct modctl_list *new;
4249 4255  
4250 4256          ASSERT(dependent->mod_busy && on_mod->mod_busy);
4251 4257          mutex_enter(&mod_lock);
4252 4258  
4253 4259          /*
4254 4260           * Search dependent's requisite list to see if on_mod is recorded.
4255 4261           * List is ordered by id.
4256 4262           */
4257 4263          for (pmlnp = &dependent->mod_requisites, mlp = *pmlnp;
4258 4264              mlp; pmlnp = &mlp->modl_next, mlp = *pmlnp)
4259 4265                  if (mlp->modl_modp->mod_id >= on_mod->mod_id)
4260 4266                          break;
4261 4267  
4262 4268          /* Create and insert if not already recorded */
4263 4269          if ((mlp == NULL) || (mlp->modl_modp->mod_id != on_mod->mod_id)) {
4264 4270                  new = kobj_zalloc(sizeof (*new), KM_SLEEP);
4265 4271                  new->modl_modp = on_mod;
4266 4272                  new->modl_next = mlp;
4267 4273                  *pmlnp = new;
4268 4274  
4269 4275                  /*
4270 4276                   * Increment the mod_ref count in our new requisite module.
4271 4277                   * This is what keeps a module that has other modules
4272 4278                   * which are dependent on it from being uninstalled and
4273 4279                   * unloaded. "on_mod"'s mod_ref count decremented in
4274 4280                   * mod_release_requisites when the "dependent" module
4275 4281                   * unload is complete.  "on_mod" must be loaded, but may not
4276 4282                   * yet be installed.
4277 4283                   */
4278 4284                  on_mod->mod_ref++;
4279 4285                  ASSERT(on_mod->mod_ref && on_mod->mod_loaded);
4280 4286          }
4281 4287  
4282 4288          mutex_exit(&mod_lock);
4283 4289  }
4284 4290  
4285 4291  /*
4286 4292   * release the hold associated with mod_make_requisite mod_ref++
4287 4293   * as part of unload.
4288 4294   */
4289 4295  void
4290 4296  mod_release_requisites(struct modctl *modp)
4291 4297  {
4292 4298          struct modctl_list *modl;
4293 4299          struct modctl_list *next;
4294 4300          struct modctl *req;
4295 4301          struct modctl_list *start = NULL, *mod_garbage;
4296 4302  
4297 4303          ASSERT(!quiesce_active);
4298 4304          ASSERT(modp->mod_busy);
4299 4305          ASSERT(MUTEX_NOT_HELD(&mod_lock));
4300 4306  
4301 4307          mutex_enter(&mod_lock);         /* needed for manipulation of req */
4302 4308          for (modl = modp->mod_requisites; modl; modl = next) {
4303 4309                  next = modl->modl_next;
4304 4310                  req = modl->modl_modp;
4305 4311                  ASSERT(req->mod_ref >= 1 && req->mod_loaded);
4306 4312                  req->mod_ref--;
4307 4313                  if (req->mod_ref == 0)
4308 4314                          mod_uninstall_ref_zero++;
4309 4315  
4310 4316                  /*
4311 4317                   * Check if the module has to be unloaded or not.
4312 4318                   */
4313 4319                  if (req->mod_ref == 0 && req->mod_delay_unload) {
4314 4320                          struct modctl_list *new;
4315 4321                          /*
4316 4322                           * Allocate the modclt_list holding the garbage
4317 4323                           * module which should be unloaded later.
4318 4324                           */
4319 4325                          new = kobj_zalloc(sizeof (struct modctl_list),
4320 4326                              KM_SLEEP);
4321 4327                          new->modl_modp = req;
4322 4328  
4323 4329                          if (start == NULL)
4324 4330                                  mod_garbage = start = new;
4325 4331                          else {
4326 4332                                  mod_garbage->modl_next = new;
4327 4333                                  mod_garbage = new;
4328 4334                          }
4329 4335                  }
4330 4336  
4331 4337                  /* free the list as we go */
4332 4338                  kobj_free(modl, sizeof (*modl));
4333 4339          }
4334 4340          modp->mod_requisites = NULL;
4335 4341          mutex_exit(&mod_lock);
4336 4342  
4337 4343          /*
4338 4344           * Unload the garbage modules.
4339 4345           */
4340 4346          for (mod_garbage = start; mod_garbage != NULL; /* nothing */) {
4341 4347                  struct modctl_list *old = mod_garbage;
4342 4348                  struct modctl *mp = mod_garbage->modl_modp;
4343 4349                  ASSERT(mp != NULL);
4344 4350  
4345 4351                  /*
4346 4352                   * Hold this module until it's unloaded completely.
4347 4353                   */
4348 4354                  (void) mod_hold_by_modctl(mp,
4349 4355                      MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
4350 4356                  /*
4351 4357                   * Check if the module is not unloaded yet and nobody requires
4352 4358                   * the module. If it's unloaded already or somebody still
4353 4359                   * requires the module, don't unload it now.
4354 4360                   */
4355 4361                  if (mp->mod_loaded && mp->mod_ref == 0)
4356 4362                          mod_unload(mp);
4357 4363                  ASSERT((mp->mod_loaded == 0 && mp->mod_delay_unload == 0) ||
4358 4364                      (mp->mod_ref > 0));
4359 4365                  mod_release_mod(mp);
4360 4366  
4361 4367                  mod_garbage = mod_garbage->modl_next;
4362 4368                  kobj_free(old, sizeof (struct modctl_list));
4363 4369          }
4364 4370  }
4365 4371  
4366 4372  /*
4367 4373   * Process dependency of the module represented by "dep" on the
4368 4374   * module named by "on."
4369 4375   *
4370 4376   * Called from kobj_do_dependents() to load a module "on" on which
4371 4377   * "dep" depends.
4372 4378   */
4373 4379  struct modctl *
4374 4380  mod_load_requisite(struct modctl *dep, char *on)
4375 4381  {
4376 4382          struct modctl *on_mod;
4377 4383          int retval;
4378 4384  
4379 4385          if ((on_mod = mod_hold_loaded_mod(dep, on, &retval)) != NULL) {
4380 4386                  mod_make_requisite(dep, on_mod);
4381 4387          } else if (moddebug & MODDEBUG_ERRMSG) {
4382 4388                  printf("error processing %s on which module %s depends\n",
4383 4389                      on, dep->mod_modname);
4384 4390          }
4385 4391          return (on_mod);
4386 4392  }
4387 4393  
4388 4394  static int
4389 4395  mod_install_requisites(struct modctl *modp)
4390 4396  {
4391 4397          struct modctl_list *modl;
4392 4398          struct modctl *req;
4393 4399          int status = 0;
4394 4400  
4395 4401          ASSERT(MUTEX_NOT_HELD(&mod_lock));
4396 4402          ASSERT(modp->mod_busy);
4397 4403  
4398 4404          for (modl = modp->mod_requisites; modl; modl = modl->modl_next) {
4399 4405                  req = modl->modl_modp;
4400 4406                  (void) mod_hold_by_modctl(req,
4401 4407                      MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
4402 4408                  status = modinstall(req);
4403 4409                  mod_release_mod(req);
4404 4410  
4405 4411                  if (status != 0)
4406 4412                          break;
4407 4413          }
4408 4414          return (status);
4409 4415  }
4410 4416  
4411 4417  /*
4412 4418   * returns 1 if this thread is doing autounload, 0 otherwise.
4413 4419   * see mod_uninstall_all.
4414 4420   */
4415 4421  int
4416 4422  mod_in_autounload()
4417 4423  {
4418 4424          return ((int)(uintptr_t)tsd_get(mod_autounload_key));
4419 4425  }
4420 4426  
4421 4427  /*
4422 4428   * gmatch adapted from libc, stripping the wchar stuff
4423 4429   */
4424 4430  #define popchar(p, c)   { \
4425 4431                  c = *p++; \
4426 4432                  if (c == 0) { \
4427 4433                          return (0); \
4428 4434                  } \
4429 4435          }
4430 4436  
4431 4437  int
4432 4438  gmatch(const char *s, const char *p)
4433 4439  {
4434 4440          int c, sc;
4435 4441          int ok, lc, notflag;
4436 4442  
4437 4443          sc = *s++;
4438 4444          c = *p++;
4439 4445          if (c == 0)
4440 4446                  return (sc == c);       /* nothing matches nothing */
4441 4447  
4442 4448          switch (c) {
4443 4449          case '\\':
4444 4450                  /* skip to quoted character */
4445 4451                  popchar(p, c);
4446 4452                  /*FALLTHRU*/
4447 4453  
4448 4454          default:
4449 4455                  /* straight comparison */
4450 4456                  if (c != sc)
4451 4457                          return (0);
4452 4458                  /*FALLTHRU*/
4453 4459  
4454 4460          case '?':
4455 4461                  /* first char matches, move to remainder */
4456 4462                  return (sc != '\0' ? gmatch(s, p) : 0);
4457 4463  
4458 4464  
4459 4465          case '*':
4460 4466                  while (*p == '*')
4461 4467                          p++;
4462 4468  
4463 4469                  /* * matches everything */
4464 4470                  if (*p == 0)
4465 4471                          return (1);
4466 4472  
4467 4473                  /* undo skip at the beginning & iterate over substrings */
4468 4474                  --s;
4469 4475                  while (*s) {
4470 4476                          if (gmatch(s, p))
4471 4477                                  return (1);
4472 4478                          s++;
4473 4479                  }
4474 4480                  return (0);
4475 4481  
4476 4482          case '[':
4477 4483                  /* match any char within [] */
4478 4484                  if (sc == 0)
4479 4485                          return (0);
4480 4486  
4481 4487                  ok = lc = notflag = 0;
4482 4488  
4483 4489                  if (*p == '!') {
4484 4490                          notflag = 1;
4485 4491                          p++;
4486 4492                  }
4487 4493                  popchar(p, c);
4488 4494  
4489 4495                  do {
4490 4496                          if (c == '-' && lc && *p != ']') {
4491 4497                                  /* test sc against range [c1-c2] */
4492 4498                                  popchar(p, c);
4493 4499                                  if (c == '\\') {
4494 4500                                          popchar(p, c);
4495 4501                                  }
4496 4502  
4497 4503                                  if (notflag) {
4498 4504                                          /* return 0 on mismatch */
4499 4505                                          if (lc <= sc && sc <= c)
4500 4506                                                  return (0);
4501 4507                                          ok++;
4502 4508                                  } else if (lc <= sc && sc <= c) {
4503 4509                                          ok++;
4504 4510                                  }
4505 4511                                  /* keep going, may get a match next */
4506 4512                          } else if (c == '\\') {
4507 4513                                  /* skip to quoted character */
4508 4514                                  popchar(p, c);
4509 4515                          }
4510 4516                          lc = c;
4511 4517                          if (notflag) {
4512 4518                                  if (sc == lc)
4513 4519                                          return (0);
4514 4520                                  ok++;
4515 4521                          } else if (sc == lc) {
4516 4522                                  ok++;
4517 4523                          }
4518 4524                          popchar(p, c);
4519 4525                  } while (c != ']');
4520 4526  
4521 4527                  /* recurse on remainder of string */
4522 4528                  return (ok ? gmatch(s, p) : 0);
4523 4529          }
4524 4530          /*NOTREACHED*/
4525 4531  }
4526 4532  
4527 4533  
4528 4534  /*
4529 4535   * Get default perm for device from /etc/minor_perm. Return 0 if match found.
4530 4536   *
4531 4537   * Pure wild-carded patterns are handled separately so the ordering of
4532 4538   * these patterns doesn't matter.  We're still dependent on ordering
4533 4539   * however as the first matching entry is the one returned.
4534 4540   * Not ideal but all existing examples and usage do imply this
4535 4541   * ordering implicitly.
4536 4542   *
4537 4543   * Drivers using the clone driver are always good for some entertainment.
4538 4544   * Clone nodes under pseudo have the form clone@0:<driver>.  Some minor
4539 4545   * perm entries have the form clone:<driver>, others use <driver>:*
4540 4546   * Examples are clone:llc1 vs. llc2:*, for example.
4541 4547   *
4542 4548   * Minor perms in the clone:<driver> form are mapped to the drivers's
4543 4549   * mperm list, not the clone driver, as wildcard entries for clone
4544 4550   * reference only.  In other words, a clone wildcard will match
4545 4551   * references for clone@0:<driver> but never <driver>@<minor>.
4546 4552   *
4547 4553   * Additional minor perms in the standard form are also supported,
4548 4554   * for mixed usage, ie a node with an entry clone:<driver> could
4549 4555   * provide further entries <driver>:<minor>.
4550 4556   *
4551 4557   * Finally, some uses of clone use an alias as the minor name rather
4552 4558   * than the driver name, with the alias as the minor perm entry.
4553 4559   * This case is handled by attaching the driver to bring its
4554 4560   * minor list into existence, then discover the alias via DDI_ALIAS.
4555 4561   * The clone device's minor perm list can then be searched for
4556 4562   * that alias.
4557 4563   */
4558 4564  
4559 4565  static int
4560 4566  dev_alias_minorperm(dev_info_t *dip, char *minor_name, mperm_t *rmp)
4561 4567  {
4562 4568          major_t                 major;
4563 4569          struct devnames         *dnp;
4564 4570          mperm_t                 *mp;
4565 4571          char                    *alias = NULL;
4566 4572          dev_info_t              *cdevi;
4567 4573          int                     circ;
4568 4574          struct ddi_minor_data   *dmd;
4569 4575  
4570 4576          major = ddi_name_to_major(minor_name);
4571 4577  
4572 4578          ASSERT(dip == clone_dip);
4573 4579          ASSERT(major != DDI_MAJOR_T_NONE);
4574 4580  
4575 4581          /*
4576 4582           * Attach the driver named by the minor node, then
4577 4583           * search its first instance's minor list for an
4578 4584           * alias node.
4579 4585           */
4580 4586          if (ddi_hold_installed_driver(major) == NULL)
4581 4587                  return (1);
4582 4588  
4583 4589          dnp = &devnamesp[major];
4584 4590          LOCK_DEV_OPS(&dnp->dn_lock);
4585 4591  
4586 4592          if ((cdevi = dnp->dn_head) != NULL) {
4587 4593                  ndi_devi_enter(cdevi, &circ);
4588 4594                  for (dmd = DEVI(cdevi)->devi_minor; dmd; dmd = dmd->next) {
4589 4595                          if (dmd->type == DDM_ALIAS) {
4590 4596                                  alias = i_ddi_strdup(dmd->ddm_name, KM_SLEEP);
4591 4597                                  break;
4592 4598                          }
4593 4599                  }
4594 4600                  ndi_devi_exit(cdevi, circ);
4595 4601          }
4596 4602  
4597 4603          UNLOCK_DEV_OPS(&dnp->dn_lock);
4598 4604          ddi_rele_driver(major);
4599 4605  
4600 4606          if (alias == NULL) {
4601 4607                  if (moddebug & MODDEBUG_MINORPERM)
4602 4608                          cmn_err(CE_CONT, "dev_minorperm: "
4603 4609                              "no alias for %s\n", minor_name);
4604 4610                  return (1);
4605 4611          }
4606 4612  
4607 4613          major = ddi_driver_major(clone_dip);
4608 4614          dnp = &devnamesp[major];
4609 4615          LOCK_DEV_OPS(&dnp->dn_lock);
4610 4616  
4611 4617          /*
4612 4618           * Go through the clone driver's mperm list looking
4613 4619           * for a match for the specified alias.
4614 4620           */
4615 4621          for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) {
4616 4622                  if (strcmp(alias, mp->mp_minorname) == 0) {
4617 4623                          break;
4618 4624                  }
4619 4625          }
4620 4626  
4621 4627          if (mp) {
4622 4628                  if (moddebug & MODDEBUG_MP_MATCH) {
4623 4629                          cmn_err(CE_CONT,
4624 4630                              "minor perm defaults: %s %s 0%o %d %d (aliased)\n",
4625 4631                              minor_name, alias, mp->mp_mode,
4626 4632                              mp->mp_uid, mp->mp_gid);
4627 4633                  }
4628 4634                  rmp->mp_uid = mp->mp_uid;
4629 4635                  rmp->mp_gid = mp->mp_gid;
4630 4636                  rmp->mp_mode = mp->mp_mode;
4631 4637          }
4632 4638          UNLOCK_DEV_OPS(&dnp->dn_lock);
4633 4639  
4634 4640          kmem_free(alias, strlen(alias)+1);
4635 4641  
4636 4642          return (mp == NULL);
4637 4643  }
4638 4644  
4639 4645  int
4640 4646  dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp)
4641 4647  {
4642 4648          major_t major;
4643 4649          char *minor_name;
4644 4650          struct devnames *dnp;
4645 4651          mperm_t *mp;
4646 4652          int is_clone = 0;
4647 4653  
4648 4654          if (!minorperm_loaded) {
4649 4655                  if (moddebug & MODDEBUG_MINORPERM)
4650 4656                          cmn_err(CE_CONT,
4651 4657                              "%s: minor perm not yet loaded\n", name);
4652 4658                  return (1);
4653 4659          }
4654 4660  
4655 4661          minor_name = strchr(name, ':');
4656 4662          if (minor_name == NULL)
4657 4663                  return (1);
4658 4664          minor_name++;
4659 4665  
4660 4666          /*
4661 4667           * If it's the clone driver, search the driver as named
4662 4668           * by the minor.  All clone minor perm entries other than
4663 4669           * alias nodes are actually installed on the real driver's list.
4664 4670           */
4665 4671          if (dip == clone_dip) {
4666 4672                  major = ddi_name_to_major(minor_name);
4667 4673                  if (major == DDI_MAJOR_T_NONE) {
4668 4674                          if (moddebug & MODDEBUG_MINORPERM)
4669 4675                                  cmn_err(CE_CONT, "dev_minorperm: "
4670 4676                                      "%s: no such driver\n", minor_name);
4671 4677                          return (1);
4672 4678                  }
4673 4679                  is_clone = 1;
4674 4680          } else {
4675 4681                  major = ddi_driver_major(dip);
4676 4682                  ASSERT(major != DDI_MAJOR_T_NONE);
4677 4683          }
4678 4684  
4679 4685          dnp = &devnamesp[major];
4680 4686          LOCK_DEV_OPS(&dnp->dn_lock);
4681 4687  
4682 4688          /*
4683 4689           * Go through the driver's mperm list looking for
4684 4690           * a match for the specified minor.  If there's
4685 4691           * no matching pattern, use the wild card.
4686 4692           * Defer to the clone wild for clone if specified,
4687 4693           * otherwise fall back to the normal form.
4688 4694           */
4689 4695          for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) {
4690 4696                  if (gmatch(minor_name, mp->mp_minorname) != 0) {
4691 4697                          break;
4692 4698                  }
4693 4699          }
4694 4700          if (mp == NULL) {
4695 4701                  if (is_clone)
4696 4702                          mp = dnp->dn_mperm_clone;
4697 4703                  if (mp == NULL)
4698 4704                          mp = dnp->dn_mperm_wild;
4699 4705          }
4700 4706  
4701 4707          if (mp) {
4702 4708                  if (moddebug & MODDEBUG_MP_MATCH) {
4703 4709                          cmn_err(CE_CONT,
4704 4710                              "minor perm defaults: %s %s 0%o %d %d\n",
4705 4711                              name, mp->mp_minorname, mp->mp_mode,
4706 4712                              mp->mp_uid, mp->mp_gid);
4707 4713                  }
4708 4714                  rmp->mp_uid = mp->mp_uid;
4709 4715                  rmp->mp_gid = mp->mp_gid;
4710 4716                  rmp->mp_mode = mp->mp_mode;
4711 4717          }
4712 4718          UNLOCK_DEV_OPS(&dnp->dn_lock);
4713 4719  
4714 4720          /*
4715 4721           * If no match can be found for a clone node,
4716 4722           * search for a possible match for an alias.
4717 4723           * One such example is /dev/ptmx -> /devices/pseudo/clone@0:ptm,
4718 4724           * with minor perm entry clone:ptmx.
4719 4725           */
4720 4726          if (mp == NULL && is_clone) {
4721 4727                  return (dev_alias_minorperm(dip, minor_name, rmp));
4722 4728          }
4723 4729  
4724 4730          return (mp == NULL);
4725 4731  }
4726 4732  
4727 4733  /*
4728 4734   * dynamicaly reference load a dl module/library, returning handle
4729 4735   */
4730 4736  /*ARGSUSED*/
4731 4737  ddi_modhandle_t
4732 4738  ddi_modopen(const char *modname, int mode, int *errnop)
4733 4739  {
4734 4740          char            *subdir;
4735 4741          char            *mod;
4736 4742          int             subdirlen;
4737 4743          struct modctl   *hmodp = NULL;
4738 4744          int             retval = EINVAL;
4739 4745  
4740 4746          ASSERT(modname && (mode == KRTLD_MODE_FIRST));
4741 4747          if ((modname == NULL) || (mode != KRTLD_MODE_FIRST))
4742 4748                  goto out;
4743 4749  
4744 4750          /* find last '/' in modname */
4745 4751          mod = strrchr(modname, '/');
4746 4752  
4747 4753          if (mod) {
4748 4754                  /* for subdir string without modification to argument */
4749 4755                  mod++;
4750 4756                  subdirlen = mod - modname;
4751 4757                  subdir = kmem_alloc(subdirlen, KM_SLEEP);
4752 4758                  (void) strlcpy(subdir, modname, subdirlen);
4753 4759          } else {
4754 4760                  subdirlen = 0;
4755 4761                  subdir = "misc";
4756 4762                  mod = (char *)modname;
4757 4763          }
4758 4764  
4759 4765          /* reference load with errno return value */
4760 4766          retval = modrload(subdir, mod, &hmodp);
4761 4767  
4762 4768          if (subdirlen)
4763 4769                  kmem_free(subdir, subdirlen);
4764 4770  
4765 4771  out:    if (errnop)
4766 4772                  *errnop = retval;
4767 4773  
4768 4774          if (moddebug & MODDEBUG_DDI_MOD)
4769 4775                  printf("ddi_modopen %s mode %x: %s %p %d\n",
4770 4776                      modname ? modname : "<unknown>", mode,
4771 4777                      hmodp ? hmodp->mod_filename : "<unknown>",
4772 4778                      (void *)hmodp, retval);
4773 4779  
4774 4780          return ((ddi_modhandle_t)hmodp);
4775 4781  }
4776 4782  
4777 4783  /* lookup "name" in open dl module/library */
4778 4784  void *
4779 4785  ddi_modsym(ddi_modhandle_t h, const char *name, int *errnop)
4780 4786  {
4781 4787          struct modctl   *hmodp = (struct modctl *)h;
4782 4788          void            *f;
4783 4789          int             retval;
4784 4790  
4785 4791          ASSERT(hmodp && name && hmodp->mod_installed && (hmodp->mod_ref >= 1));
4786 4792          if ((hmodp == NULL) || (name == NULL) ||
4787 4793              (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) {
4788 4794                  f = NULL;
4789 4795                  retval = EINVAL;
4790 4796          } else {
4791 4797                  f = (void *)kobj_lookup(hmodp->mod_mp, (char *)name);
4792 4798                  if (f)
4793 4799                          retval = 0;
4794 4800                  else
4795 4801                          retval = ENOTSUP;
4796 4802          }
4797 4803  
4798 4804          if (moddebug & MODDEBUG_DDI_MOD)
4799 4805                  printf("ddi_modsym in %s of %s: %d %p\n",
4800 4806                      hmodp ? hmodp->mod_modname : "<unknown>",
4801 4807                      name ? name : "<unknown>", retval, f);
4802 4808  
4803 4809          if (errnop)
4804 4810                  *errnop = retval;
4805 4811          return (f);
4806 4812  }
4807 4813  
4808 4814  /* dynamic (un)reference unload of an open dl module/library */
4809 4815  int
4810 4816  ddi_modclose(ddi_modhandle_t h)
4811 4817  {
4812 4818          struct modctl   *hmodp = (struct modctl *)h;
4813 4819          struct modctl   *modp = NULL;
4814 4820          int             retval;
4815 4821  
4816 4822          ASSERT(hmodp && hmodp->mod_installed && (hmodp->mod_ref >= 1));
4817 4823          if ((hmodp == NULL) ||
4818 4824              (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) {
4819 4825                  retval = EINVAL;
4820 4826                  goto out;
4821 4827          }
4822 4828  
4823 4829          retval = modunrload(hmodp->mod_id, &modp, ddi_modclose_unload);
4824 4830          if (retval == EBUSY)
4825 4831                  retval = 0;     /* EBUSY is not an error */
4826 4832  
4827 4833          if (retval == 0) {
4828 4834                  ASSERT(hmodp == modp);
4829 4835                  if (hmodp != modp)
4830 4836                          retval = EINVAL;
4831 4837          }
4832 4838  
4833 4839  out:    if (moddebug & MODDEBUG_DDI_MOD)
4834 4840                  printf("ddi_modclose %s: %d\n",
4835 4841                      hmodp ? hmodp->mod_modname : "<unknown>", retval);
4836 4842  
4837 4843          return (retval);
4838 4844  }
  
    | 
      ↓ open down ↓ | 
    1353 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX