int smbfsinit(int fstyp, char *name) { int error; error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); if (error != 0) { zcmn_err(GLOBAL_ZONEID, CE_WARN, "smbfsinit: bad vfs ops template"); return (error); } error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); if (error != 0) { (void) vfs_freevfsops_by_type(fstyp); zcmn_err(GLOBAL_ZONEID, CE_WARN, "smbfsinit: bad vnode ops template"); return (error); } smbfsfstyp = fstyp; return (0); }
/* * Converts a utf8 string to a C string. * allocs a new string if not supplied */ char * utf8_to_str(utf8string *str, uint_t *lenp, char *s) { char *sp; char *u8p; int len; int i; ASSERT(lenp != NULL); if (str == NULL) return (NULL); u8p = str->utf8string_val; len = str->utf8string_len; if (len <= 0 || u8p == NULL) { if (s) *s = '\0'; return (NULL); } sp = s; if (sp == NULL) { sp = calloc(1, len + 1); if (sp == NULL) return (NULL); } /* * At least check for embedded nulls */ for (i = 0; i < len; i++) { sp[i] = u8p[i]; if (u8p[i] == '\0') { #ifdef DEBUG zcmn_err(getzoneid(), CE_WARN, "Embedded NULL in UTF-8 string"); #endif if (s == NULL) free(sp); return (NULL); } } sp[len] = '\0'; *lenp = len + 1; return (sp); }
/* * We have seen a case that the fh passed in is for "." which * should be a VROOT node, however, the fh is different from the * root fh stored in the mntinfo4_t. The invalid fh might be * from a misbehaved server and will panic the client system at * a later time. To avoid the panic, we drop the bad fh, use * the root fh from mntinfo4_t, and print an error message * for attention. */ nfs4_sharedfh_t * badrootfh_check(nfs4_sharedfh_t *fh, nfs4_fname_t *nm, mntinfo4_t *mi, int *wasbad) { char *s; *wasbad = 0; s = fn_name(nm); ASSERT(strcmp(s, "..") != 0); if ((s[0] == '.' && s[1] == '\0') && fh && !SFH4_SAME(mi->mi_rootfh, fh)) { #ifdef DEBUG nfs4_fhandle_t fhandle; zcmn_err(mi->mi_zone->zone_id, CE_WARN, "Server %s returns a different " "root filehandle for the path %s:", mi->mi_curr_serv->sv_hostname, mi->mi_curr_serv->sv_path); /* print the bad fh */ fhandle.fh_len = fh->sfh_fh.nfs_fh4_len; bcopy(fh->sfh_fh.nfs_fh4_val, fhandle.fh_buf, fhandle.fh_len); nfs4_printfhandle(&fhandle); /* print mi_rootfh */ fhandle.fh_len = mi->mi_rootfh->sfh_fh.nfs_fh4_len; bcopy(mi->mi_rootfh->sfh_fh.nfs_fh4_val, fhandle.fh_buf, fhandle.fh_len); nfs4_printfhandle(&fhandle); #endif /* use mi_rootfh instead; fh will be rele by the caller */ fh = mi->mi_rootfh; *wasbad = 1; } kmem_free(s, MAXNAMELEN); return (fh); }
int nfs4_rnode_init(void) { ulong_t nrnode4_max; int i; /* * Compute the size of the rnode4 hash table */ if (nrnode <= 0) nrnode = ncsize; nrnode4_max = (ulong_t)((kmem_maxavail() >> 2) / sizeof (struct rnode4)); if (nrnode > nrnode4_max || (nrnode == 0 && ncsize == 0)) { zcmn_err(GLOBAL_ZONEID, CE_NOTE, "setting nrnode to max value of %ld", nrnode4_max); nrnode = nrnode4_max; } rtable4size = 1 << highbit(nrnode / rnode4_hashlen); rtable4mask = rtable4size - 1; /* * Allocate and initialize the hash buckets */ rtable4 = kmem_alloc(rtable4size * sizeof (*rtable4), KM_SLEEP); for (i = 0; i < rtable4size; i++) { rtable4[i].r_hashf = (rnode4_t *)(&rtable4[i]); rtable4[i].r_hashb = (rnode4_t *)(&rtable4[i]); rw_init(&rtable4[i].r_lock, NULL, RW_DEFAULT, NULL); } rnode4_cache = kmem_cache_create("rnode4_cache", sizeof (rnode4_t), 0, NULL, NULL, nfs4_reclaim, NULL, NULL, 0); return (0); }
/* * Called by proc_exit() when a zone's init exits, presumably because * it failed. As long as the given zone is still in the "running" * state, we will re-exec() init, but first we need to reset things * which are usually inherited across exec() but will break init's * assumption that it is being exec()'d from a virgin process. Most * importantly this includes closing all file descriptors (exec only * closes those marked close-on-exec) and resetting signals (exec only * resets handled signals, and we need to clear any signals which * killed init). Anything else that exec(2) says would be inherited, * but would affect the execution of init, needs to be reset. */ static int restart_init(int what, int why) { kthread_t *t = curthread; klwp_t *lwp = ttolwp(t); proc_t *p = ttoproc(t); user_t *up = PTOU(p); vnode_t *oldcd, *oldrd; int i, err; char reason_buf[64]; /* * Let zone admin (and global zone admin if this is for a non-global * zone) know that init has failed and will be restarted. */ zcmn_err(p->p_zone->zone_id, CE_WARN, "init(1M) %s: restarting automatically", exit_reason(reason_buf, sizeof (reason_buf), what, why)); if (!INGLOBALZONE(p)) { cmn_err(CE_WARN, "init(1M) for zone %s (pid %d) %s: " "restarting automatically", p->p_zone->zone_name, p->p_pid, reason_buf); } /* * Remove any fpollinfo_t's for this (last) thread from our file * descriptors so closeall() can ASSERT() that they're all gone. * Then close all open file descriptors in the process. */ pollcleanup(); closeall(P_FINFO(p)); /* * Grab p_lock and begin clearing miscellaneous global process * state that needs to be reset before we exec the new init(1M). */ mutex_enter(&p->p_lock); prbarrier(p); p->p_flag &= ~(SKILLED | SEXTKILLED | SEXITING | SDOCORE); up->u_cmask = CMASK; sigemptyset(&t->t_hold); sigemptyset(&t->t_sig); sigemptyset(&t->t_extsig); sigemptyset(&p->p_sig); sigemptyset(&p->p_extsig); sigdelq(p, t, 0); sigdelq(p, NULL, 0); if (p->p_killsqp) { siginfofree(p->p_killsqp); p->p_killsqp = NULL; } /* * Reset any signals that are ignored back to the default disposition. * Other u_signal members will be cleared when exec calls sigdefault(). */ for (i = 1; i < NSIG; i++) { if (up->u_signal[i - 1] == SIG_IGN) { up->u_signal[i - 1] = SIG_DFL; sigemptyset(&up->u_sigmask[i - 1]); } } /* * Clear the current signal, any signal info associated with it, and * any signal information from contracts and/or contract templates. */ lwp->lwp_cursig = 0; lwp->lwp_extsig = 0; if (lwp->lwp_curinfo != NULL) { siginfofree(lwp->lwp_curinfo); lwp->lwp_curinfo = NULL; } lwp_ctmpl_clear(lwp); /* * Reset both the process root directory and the current working * directory to the root of the zone just as we do during boot. */ VN_HOLD(p->p_zone->zone_rootvp); oldrd = up->u_rdir; up->u_rdir = p->p_zone->zone_rootvp; VN_HOLD(p->p_zone->zone_rootvp); oldcd = up->u_cdir; up->u_cdir = p->p_zone->zone_rootvp; if (up->u_cwd != NULL) { refstr_rele(up->u_cwd); up->u_cwd = NULL; } mutex_exit(&p->p_lock); if (oldrd != NULL) VN_RELE(oldrd); if (oldcd != NULL) VN_RELE(oldcd); /* Free the controlling tty. (freectty() always assumes curproc.) */ ASSERT(p == curproc); (void) freectty(B_TRUE); /* * Now exec() the new init(1M) on top of the current process. If we * succeed, the caller will treat this like a successful system call. * If we fail, we issue messages and the caller will proceed with exit. */ err = exec_init(p->p_zone->zone_initname, NULL); if (err == 0) return (0); zcmn_err(p->p_zone->zone_id, CE_WARN, "failed to restart init(1M) (err=%d): system reboot required", err); if (!INGLOBALZONE(p)) { cmn_err(CE_WARN, "failed to restart init(1M) for zone %s " "(pid %d, err=%d): zoneadm(1M) boot required", p->p_zone->zone_name, p->p_pid, err); } return (-1); }
/* * Construct a stack for init containing the arguments to it, then * pass control to exec_common. */ int exec_init(const char *initpath, const char *args) { caddr32_t ucp; caddr32_t *uap; caddr32_t *argv; caddr32_t exec_fnamep; char *scratchargs; int i, sarg; size_t argvlen, alen; boolean_t in_arg; int argc = 0; int error = 0, count = 0; proc_t *p = ttoproc(curthread); klwp_t *lwp = ttolwp(curthread); int brand_action; if (args == NULL) args = ""; alen = strlen(initpath) + 1 + strlen(args) + 1; scratchargs = kmem_alloc(alen, KM_SLEEP); (void) snprintf(scratchargs, alen, "%s %s", initpath, args); /* * We do a quick two state parse of the string to sort out how big * argc should be. */ in_arg = B_FALSE; for (i = 0; i < strlen(scratchargs); i++) { if (scratchargs[i] == ' ' || scratchargs[i] == '\0') { if (in_arg) { in_arg = B_FALSE; argc++; } } else { in_arg = B_TRUE; } } argvlen = sizeof (caddr32_t) * (argc + 1); argv = kmem_zalloc(argvlen, KM_SLEEP); /* * We pull off a bit of a hack here. We work our way through the * args string, putting nulls at the ends of space delimited tokens * (boot args don't support quoting at this time). Then we just * copy the whole mess to userland in one go. In other words, we * transform this: "init -s -r\0" into this on the stack: * * -0x00 \0 * -0x01 r * -0x02 - <--------. * -0x03 \0 | * -0x04 s | * -0x05 - <------. | * -0x06 \0 | | * -0x07 t | | * -0x08 i | | * -0x09 n | | * -0x0a i <---. | | * -0x10 NULL | | | (argv[3]) * -0x14 -----|--|-' (argv[2]) * -0x18 ------|--' (argv[1]) * -0x1c -------' (argv[0]) * * Since we know the value of ucp at the beginning of this process, * we can trivially compute the argv[] array which we also need to * place in userland: argv[i] = ucp - sarg(i), where ucp is the * stack ptr, and sarg is the string index of the start of the * argument. */ ucp = (caddr32_t)(uintptr_t)p->p_usrstack; argc = 0; in_arg = B_FALSE; sarg = 0; for (i = 0; i < alen; i++) { if (scratchargs[i] == ' ' || scratchargs[i] == '\0') { if (in_arg == B_TRUE) { in_arg = B_FALSE; scratchargs[i] = '\0'; argv[argc++] = ucp - (alen - sarg); } } else if (in_arg == B_FALSE) { in_arg = B_TRUE; sarg = i; } } ucp -= alen; error |= copyout(scratchargs, (caddr_t)(uintptr_t)ucp, alen); uap = (caddr32_t *)P2ALIGN((uintptr_t)ucp, sizeof (caddr32_t)); uap--; /* advance to be below the word we're in */ uap -= (argc + 1); /* advance argc words down, plus one for NULL */ error |= copyout(argv, uap, argvlen); if (error != 0) { zcmn_err(p->p_zone->zone_id, CE_WARN, "Could not construct stack for init.\n"); kmem_free(argv, argvlen); kmem_free(scratchargs, alen); return (EFAULT); } exec_fnamep = argv[0]; kmem_free(argv, argvlen); kmem_free(scratchargs, alen); /* * Point at the arguments. */ lwp->lwp_ap = lwp->lwp_arg; lwp->lwp_arg[0] = (uintptr_t)exec_fnamep; lwp->lwp_arg[1] = (uintptr_t)uap; lwp->lwp_arg[2] = NULL; curthread->t_post_sys = 1; curthread->t_sysnum = SYS_execve; /* * If we are executing init from zsched, we may have inherited its * parent process's signal mask. Clear it now so that we behave in * the same way as when started from the global zone. */ sigemptyset(&curthread->t_hold); brand_action = ZONE_IS_BRANDED(p->p_zone) ? EBA_BRAND : EBA_NONE; again: error = exec_common((const char *)(uintptr_t)exec_fnamep, (const char **)(uintptr_t)uap, NULL, brand_action); /* * Normally we would just set lwp_argsaved and t_post_sys and * let post_syscall reset lwp_ap for us. Unfortunately, * exec_init isn't always called from a system call. Instead * of making a mess of trap_cleanup, we just reset the args * pointer here. */ reset_syscall_args(); switch (error) { case 0: return (0); case ENOENT: zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed (file not found).\n", initpath); return (ENOENT); case EAGAIN: case EINTR: ++count; if (count < 5) { zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed with errno %d. Retrying...\n", initpath, error); goto again; } } zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed with errno %d.", initpath, error); return (error); }
void r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode, hrtime_t t, cred_t *cr, int index) { int is_stub; vattr_t *attr; /* * Don't add to attrcache if time overflow, but * no need to check because either attr is null or the time * values in it were processed by nfs4_time_ntov(), which checks * for time overflows. */ attr = garp ? &garp->n4g_va : NULL; if (attr) { if (!newnode) { rw_exit(&rtable4[index].r_lock); #ifdef DEBUG if (vp->v_type != attr->va_type && vp->v_type != VNON && attr->va_type != VNON) { zcmn_err(VTOMI4(vp)->mi_zone->zone_id, CE_WARN, "makenfs4node: type (%d) doesn't " "match type of found node at %p (%d)", attr->va_type, (void *)vp, vp->v_type); } #endif nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL); } else { rnode4_t *rp = VTOR4(vp); vp->v_type = attr->va_type; vp->v_rdev = attr->va_rdev; /* * Turn this object into a "stub" object if we * crossed an underlying server fs boundary. * To make this check, during mount we save the * fsid of the server object being mounted. * Here we compare this object's server fsid * with the fsid we saved at mount. If they * are different, we crossed server fs boundary. * * The stub type is set (or not) at rnode * creation time and it never changes for life * of the rnode. * * The stub type is also set during RO failover, * nfs4_remap_file(). * * This stub will be for a mirror-mount. * * We don't bother with taking r_state_lock to * set the stub type because this is a new rnode * and we're holding the hash bucket r_lock RW_WRITER. * No other thread could have obtained access * to this rnode. */ is_stub = 0; if (garp->n4g_fsid_valid) { fattr4_fsid ga_fsid = garp->n4g_fsid; servinfo4_t *svp = rp->r_server; rp->r_srv_fsid = ga_fsid; (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); if (!FATTR4_FSID_EQ(&ga_fsid, &svp->sv_fsid)) is_stub = 1; nfs_rw_exit(&svp->sv_lock); } if (is_stub) r4_stub_mirrormount(rp); else r4_stub_none(rp); /* Can not cache partial attr */ if (attr->va_mask == AT_ALL) nfs4_attrcache_noinval(vp, garp, t); else PURGE_ATTRCACHE4(vp); rw_exit(&rtable4[index].r_lock); } } else { if (newnode) { PURGE_ATTRCACHE4(vp); } rw_exit(&rtable4[index].r_lock); } }