XXXX introduce drv_sectohz

   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * routines to invoke user level name lookup services
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/param.h>
  32 #include <sys/t_lock.h>
  33 #include <sys/systm.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/user.h>
  36 #include <sys/time.h>
  37 #include <sys/vfs.h>
  38 #include <sys/vnode.h>
  39 #include <sys/file.h>
  40 #include <sys/fcntl.h>
  41 #include <sys/flock.h>
  42 #include <sys/kmem.h>
  43 #include <sys/uio.h>
  44 #include <sys/errno.h>
  45 #include <sys/stat.h>
  46 #include <sys/cred.h>
  47 #include <sys/dirent.h>
  48 #include <sys/pathname.h>
  49 #include <sys/cmn_err.h>
  50 #include <sys/debug.h>
  51 #include <sys/mode.h>
  52 #include <sys/policy.h>
  53 #include <sys/disp.h>
  54 #include <sys/door.h>
  55 #include <fs/fs_subr.h>
  56 #include <sys/mount.h>
  57 #include <sys/fs/snode.h>
  58 #include <sys/fs/dv_node.h>
  59 #include <sys/fs/sdev_impl.h>
  60 #include <sys/sunndi.h>
  61 #include <sys/sunddi.h>
  62 #include <sys/sunmdi.h>
  63 #include <sys/conf.h>
  64 #include <sys/modctl.h>
  65 #include <sys/ddi.h>
  66 
  67 /* default timeout to wait for devfsadm response in seconds */
  68 #define DEV_DEVFSADM_STARTUP    (1 * 60)
  69 #define DEV_NODE_WAIT_TIMEOUT   (5 * 60)
  70 
  71 /* atomic bitset for devfsadm status */
  72 volatile uint_t devfsadm_state;
  73 
  74 static kmutex_t devfsadm_lock;
  75 static kcondvar_t devfsadm_cv;
  76 
  77 static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT;
  78 static int dev_devfsadm_startup =  DEV_DEVFSADM_STARTUP;
  79 
  80 /*
  81  * Door used to communicate with devfsadmd
  82  */
  83 static door_handle_t    sdev_upcall_door = NULL;        /* Door for upcalls */
  84 static char             *sdev_door_upcall_filename = NULL;
  85 static int              sdev_upcall_door_revoked = 0;
  86 static int              sdev_door_upcall_filename_size;
  87 
  88 static int sdev_devfsadm_revoked(void);
  89 static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *);
  90 
  91 void
  92 sdev_devfsadm_lockinit(void)
  93 {
  94         mutex_init(&devfsadm_lock, NULL, MUTEX_DEFAULT, NULL);
  95         cv_init(&devfsadm_cv, NULL, CV_DEFAULT, NULL);
  96 }
  97 
  98 void
  99 sdev_devfsadm_lockdestroy(void)
 100 {
 101         mutex_destroy(&devfsadm_lock);
 102         cv_destroy(&devfsadm_cv);
 103 }
 104 
 105 /*
 106  * Wait for node to be created
 107  */
 108 int
 109 sdev_wait4lookup(struct sdev_node *dv, int cmd)
 110 {
 111         clock_t expire;
 112         clock_t rv;
 113         clock_t wakeup = drv_sectohz(2);
 114         int rval = ENOENT;
 115         int is_lookup = (cmd == SDEV_LOOKUP);
 116 
 117         ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR);
 118         ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
 119 
 120         /* tick value at which wait expires */
 121         expire = ddi_get_lbolt() +
 122             drv_sectohz(dev_node_wait_timeout);
 123 
 124         sdcmn_err6(("wait4lookup %s %s, %ld %d\n",
 125             is_lookup ? "lookup" : "readdir",
 126             dv->sdev_name, expire - ddi_get_lbolt(), dv->sdev_state));
 127 
 128         if (SDEV_IS_LGWAITING(dv)) {
 129                 /* devfsadm nodes */
 130                 while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) &&
 131                     !sdev_devfsadm_revoked()) {
 132                         /* wait 2 sec and check devfsadm completion */
 133                         rv = cv_reltimedwait_sig(&dv->sdev_lookup_cv,
 134                             &dv->sdev_lookup_lock, wakeup, TR_CLOCK_TICK);
 135 
 136                         if (is_lookup && (rv > 0)) {
 137                                 /* was this node constructed ? */
 138                                 if (dv->sdev_state == SDEV_READY) {
 139                                         rval = 0;
 140                                 }
 141                                 sdcmn_err6(("%s: wait done, %screated %d\n",
 142                                     dv->sdev_name, rval ? "not " : "",
 143                                     dv->sdev_state));
 144                                 break;
 145                         } else if (rv == 0) {
 146                                 /* interrupted */
 147                                 sdcmn_err6(("%s: wait interrupted\n",
 148                                     dv->sdev_name));
 149                                 break;
 150                         } else if ((rv == -1) &&
 151                             (ddi_get_lbolt() >= expire)) {
 152                                 sdcmn_err6(("%s: wait time is up\n",
 153                                     dv->sdev_name));
 154                                 break;
 155                         }
 156                         sdcmn_err6(("%s: wait "
 157                             "rv %ld state 0x%x expire %ld\n",
 158                             dv->sdev_name, rv, devfsadm_state,
 159                             expire - ddi_get_lbolt()));
 160                 }
 161         } else {
 162                 /*
 163                  * for the nodes created by
 164                  * devname_lookup_func callback
 165                  * or plug-in modules
 166                  */
 167                 while (SDEV_IS_LOOKUP(dv) || SDEV_IS_READDIR(dv)) {
 168                         cv_wait(&dv->sdev_lookup_cv, &dv->sdev_lookup_lock);
 169                 }
 170                 rval = 0;
 171         }
 172 
 173         sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n",
 174             dv->sdev_name, devfsadm_state, dv->sdev_state));
 175 
 176         if (is_lookup) {
 177                 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
 178         } else {
 179                 SDEV_UNBLOCK_OTHERS(dv, SDEV_READDIR);
 180         }
 181 
 182         return (rval);
 183 }
 184 
 185 void
 186 sdev_unblock_others(struct sdev_node *dv, uint_t cmd)
 187 {
 188         ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
 189 
 190         SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd);
 191         if (SDEV_IS_LGWAITING(dv)) {
 192                 SDEV_CLEAR_LOOKUP_FLAGS(dv, SDEV_LGWAITING);
 193         }
 194         cv_broadcast(&dv->sdev_lookup_cv);
 195 }
 196 
 197 /*
 198  * In the case devfsadmd is down, it is re-started by syseventd
 199  * upon receiving an event subscribed to by devfsadmd.
 200  */
 201 static int
 202 sdev_start_devfsadmd()
 203 {
 204         int             se_err = 0;
 205         sysevent_t      *ev;
 206         sysevent_id_t   eid;
 207 
 208         ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_START, EP_DDI, SE_SLEEP);
 209         ASSERT(ev);
 210         if ((se_err = log_sysevent(ev, SE_SLEEP, &eid)) != 0) {
 211                 switch (se_err) {
 212                 case SE_NO_TRANSPORT:
 213                         cmn_err(CE_WARN, "unable to start devfsadm - "
 214                             "syseventd may not be responding\n");
 215                         break;
 216                 default:
 217                         cmn_err(CE_WARN, "unable to start devfsadm - "
 218                             "sysevent error %d\n", se_err);
 219                         break;
 220                 }
 221         }
 222 
 223         sysevent_free(ev);
 224         return (se_err);
 225 }
 226 
 227 static int
 228 sdev_open_upcall_door()
 229 {
 230         int error;
 231         clock_t rv;
 232         clock_t expire;
 233 
 234         ASSERT(sdev_upcall_door == NULL);
 235 
 236         /* timeout expires this many ticks in the future */
 237         expire = ddi_get_lbolt() + drv_sectohz(dev_devfsadm_startup);
 238 
 239         if (sdev_door_upcall_filename == NULL) {
 240                 if ((error = sdev_start_devfsadmd()) != 0) {
 241                         return (error);
 242                 }
 243 
 244                 /* wait for devfsadmd start */
 245                 mutex_enter(&devfsadm_lock);
 246                 while (sdev_door_upcall_filename == NULL) {
 247                         sdcmn_err6(("waiting for dev_door creation, %ld\n",
 248                             expire - ddi_get_lbolt()));
 249                         rv = cv_timedwait_sig(&devfsadm_cv, &devfsadm_lock,
 250                             expire);
 251                         sdcmn_err6(("dev_door wait rv %ld\n", rv));
 252                         if (rv <= 0) {
 253                                 sdcmn_err6(("devfsadmd startup error\n"));
 254                                 mutex_exit(&devfsadm_lock);
 255                                 return (EBADF);
 256                         }
 257                 }
 258                 sdcmn_err6(("devfsadmd is ready\n"));
 259                 mutex_exit(&devfsadm_lock);
 260         }
 261 
 262         if ((error = door_ki_open(sdev_door_upcall_filename,
 263             &sdev_upcall_door)) != 0) {
 264                 sdcmn_err6(("upcall_lookup: door open error %d\n",
 265                     error));
 266                 return (error);
 267         }
 268 
 269         return (0);
 270 }
 271 
 272 static void
 273 sdev_release_door()
 274 {
 275         if (sdev_upcall_door) {
 276                 door_ki_rele(sdev_upcall_door);
 277                 sdev_upcall_door = NULL;
 278         }
 279         if (sdev_door_upcall_filename) {
 280                 kmem_free(sdev_door_upcall_filename,
 281                     sdev_door_upcall_filename_size);
 282                 sdev_door_upcall_filename = NULL;
 283         }
 284 }
 285 
 286 static int
 287 sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp)
 288 {
 289         door_arg_t      darg, save_arg;
 290         int             error;
 291         int             retry;
 292 
 293         if (((sdev_upcall_door == NULL) &&
 294             ((error = sdev_open_upcall_door()) != 0)) ||
 295             sdev_devfsadm_revoked()) {
 296                 sdcmn_err6(("call_devfsadm: upcall lookup error\n"));
 297                 return (error);
 298         }
 299 
 300         ASSERT(argp);
 301         darg.data_ptr = (char *)argp;
 302         darg.data_size = sizeof (struct sdev_door_arg);
 303         darg.desc_ptr = NULL;
 304         darg.desc_num = 0;
 305         darg.rbuf = (char *)(resultp);
 306         darg.rsize = sizeof (struct sdev_door_res);
 307 
 308         ASSERT(sdev_upcall_door);
 309         save_arg = darg;
 310         for (retry = 0; ; retry++) {
 311                 sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry));
 312                 if ((error = door_ki_upcall_limited(sdev_upcall_door, &darg,
 313                     NULL, SIZE_MAX, 0)) == 0) {
 314                         sdcmn_err6(("call devfsadm: upcall lookup ok\n"));
 315                         break;
 316                 }
 317 
 318                 /*
 319                  * handle door call errors
 320                  */
 321                 if (sdev_devfsadm_revoked()) {
 322                         sdcmn_err6(("upcall lookup door revoked, "
 323                             "error %d\n", error));
 324                         return (error);
 325                 }
 326 
 327                 switch (error) {
 328                 case EINTR:
 329                         /* return error here? */
 330                         sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
 331                         delay(hz);
 332                         break;
 333                 case EAGAIN:
 334                         sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
 335                         delay(2 * hz);
 336                         break;
 337                 case EBADF:
 338                         if (retry > 4) {
 339                                 sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
 340                                 return (EBADF);
 341                         }
 342                         sdcmn_err6((
 343                             "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
 344                         sdev_release_door();
 345                         delay(retry * hz);
 346                         error = sdev_open_upcall_door();
 347                         if (error != 0) {
 348                                 sdcmn_err6(("sdev_ki_call_devfsadm: "
 349                                     "EBADF lookup error %d\n", error));
 350                                 if (!sdev_devfsadm_revoked())
 351                                         cmn_err(CE_NOTE,
 352                                             "?unable to invoke devfsadm - "
 353                                             "please run manually\n");
 354                                 return (EBADF);
 355                         }
 356                         break;
 357                 case EINVAL:
 358                 default:
 359                         cmn_err(CE_CONT,
 360                             "?sdev: door_ki_upcall unexpected result %d\n",
 361                             error);
 362                         return (error);
 363                 }
 364 
 365                 darg = save_arg;
 366         }
 367 
 368         if (!error) {
 369                 ASSERT((struct sdev_door_res *)(intptr_t)darg.rbuf == resultp);
 370                 if (resultp->devfsadm_error != 0) {
 371                         sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n",
 372                             resultp->devfsadm_error));
 373                         error = resultp->devfsadm_error;
 374                 }
 375         } else {
 376                 sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error));
 377         }
 378 
 379         return (error);
 380 }
 381 
 382 static int
 383 sdev_devfsadm_revoked(void)
 384 {
 385         struct door_info info;
 386         int rv;
 387         extern int sys_shutdown;
 388 
 389         if (sys_shutdown) {
 390                 sdcmn_err6(("dev: shutdown observed\n"));
 391                 return (1);
 392         }
 393 
 394         if (sdev_upcall_door && !sdev_upcall_door_revoked) {
 395                 rv = door_ki_info(sdev_upcall_door, &info);
 396                 if ((rv == 0) && info.di_attributes & DOOR_REVOKED) {
 397                         sdcmn_err6(("lookup door: revoked\n"));
 398                         sdev_upcall_door_revoked = 1;
 399                 }
 400         }
 401 
 402         return (sdev_upcall_door_revoked);
 403 }
 404 
 405 /*ARGSUSED*/
 406 static void
 407 sdev_config_all_thread(struct sdev_node *dv)
 408 {
 409         int32_t error = 0;
 410         sdev_door_arg_t *argp;
 411         sdev_door_res_t result;
 412 
 413         argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
 414         argp->devfsadm_cmd = DEVFSADMD_RUN_ALL;
 415 
 416         error = sdev_ki_call_devfsadmd(argp, &result);
 417         if (!error) {
 418                 sdcmn_err6(("devfsadm result error: %d\n",
 419                     result.devfsadm_error));
 420                 if (!result.devfsadm_error) {
 421                         DEVNAME_DEVFSADM_SET_RUN(devfsadm_state);
 422                 } else {
 423                         DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
 424                 }
 425         } else {
 426                 DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
 427         }
 428 
 429         kmem_free(argp, sizeof (sdev_door_arg_t));
 430 done:
 431         sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
 432             devfsadm_state));
 433         thread_exit();
 434 }
 435 
 436 /*
 437  * launch an asynchronous thread to do the devfsadm dev_config_all
 438  */
 439 /*ARGSUSED*/
 440 void
 441 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv,
 442     struct cred *cred)
 443 {
 444         ASSERT(i_ddi_io_initialized());
 445         DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state);
 446         (void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0,
 447             &p0, TS_RUN, MINCLSYSPRI);
 448 }
 449 
 450 int
 451 devname_filename_register(char *name)
 452 {
 453         int error = 0;
 454         char *strbuf;
 455         char *namep;
 456         int n;
 457 
 458         strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
 459 
 460         if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
 461                 sdcmn_err6(("error copyin \n"));
 462                 error = EFAULT;
 463         } else {
 464                 sdcmn_err6(("file %s is registering\n", strbuf));
 465                 /* handling the daemon re-start situations */
 466                 n = strlen(strbuf) + 1;
 467                 namep = i_ddi_strdup(strbuf, KM_SLEEP);
 468                 mutex_enter(&devfsadm_lock);
 469                 sdev_release_door();
 470                 sdev_door_upcall_filename_size = n;
 471                 sdev_door_upcall_filename = namep;
 472                 sdcmn_err6(("size %d file name %s\n",
 473                     sdev_door_upcall_filename_size,
 474                     sdev_door_upcall_filename));
 475                 cv_broadcast(&devfsadm_cv);
 476                 mutex_exit(&devfsadm_lock);
 477         }
 478 
 479         kmem_free(strbuf, MOD_MAXPATH);
 480         return (error);
 481 }
--- EOF ---