/* * Move console messages from src to dst. The time of day isn't known * early in boot, so fix up the message timestamps if necessary. */ static void log_conswitch(log_t *src, log_t *dst) { mblk_t *mp; mblk_t *hmp = NULL; mblk_t *tmp = NULL; log_ctl_t *hlc; while ((mp = getq_noenab(src->log_q, 0)) != NULL) { log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; lc->flags |= SL_LOGONLY; /* * The ttime is written with 0 in log_sensmsg() only when * good gethrestime_sec() data is not available to store in * the log_ctl_t in the early boot phase. */ if (lc->ttime == 0) { /* * Look ahead to first early boot message with time. */ if (hmp) { tmp->b_next = mp; tmp = mp; } else hmp = tmp = mp; continue; } while (hmp) { tmp = hmp->b_next; hmp->b_next = NULL; hlc = (log_ctl_t *)hmp->b_rptr; /* * Calculate hrestime for an early log message with * an invalid time stamp. We know: * - the lbolt of the invalid time stamp. * - the hrestime and lbolt of the first valid * time stamp. */ hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz; (void) putq(dst->log_q, hmp); hmp = tmp; } (void) putq(dst->log_q, mp); } while (hmp) { tmp = hmp->b_next; hmp->b_next = NULL; hlc = (log_ctl_t *)hmp->b_rptr; hlc->ttime = gethrestime_sec() - (ddi_get_lbolt() - hlc->ltime) / hz; (void) putq(dst->log_q, hmp); hmp = tmp; } dst->log_overflow = src->log_overflow; src->log_flags = 0; dst->log_flags = SL_CONSOLE; log_consq = dst->log_q; }
/* ARGSUSED */ int socket_vop_setattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr, caller_context_t *ct) { struct sonode *so = VTOSO(vp); /* * If times were changed, and we have a STREAMS socket, then update * the sonode. */ if (!SOCK_IS_NONSTR(so)) { sotpi_info_t *sti = SOTOTPI(so); mutex_enter(&so->so_lock); if (vap->va_mask & AT_ATIME) sti->sti_atime = vap->va_atime.tv_sec; if (vap->va_mask & AT_MTIME) { sti->sti_mtime = vap->va_mtime.tv_sec; sti->sti_ctime = gethrestime_sec(); } mutex_exit(&so->so_lock); } return (0); }
uint64_t dsl_dir_create_sync(dsl_pool_t *dp, dsl_dir_t *pds, const char *name, dmu_tx_t *tx) { objset_t *mos = dp->dp_meta_objset; uint64_t ddobj; dsl_dir_phys_t *dsphys; dmu_buf_t *dbuf; ddobj = dmu_object_alloc(mos, DMU_OT_DSL_DIR, 0, DMU_OT_DSL_DIR, sizeof (dsl_dir_phys_t), tx); if (pds) { VERIFY(0 == zap_add(mos, pds->dd_phys->dd_child_dir_zapobj, name, sizeof (uint64_t), 1, &ddobj, tx)); } else { /* it's the root dir */ VERIFY(0 == zap_add(mos, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_ROOT_DATASET, sizeof (uint64_t), 1, &ddobj, tx)); } VERIFY(0 == dmu_bonus_hold(mos, ddobj, FTAG, &dbuf)); dmu_buf_will_dirty(dbuf, tx); dsphys = dbuf->db_data; dsphys->dd_creation_time = gethrestime_sec(); if (pds) dsphys->dd_parent_obj = pds->dd_object; dsphys->dd_props_zapobj = zap_create(mos, DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); dsphys->dd_child_dir_zapobj = zap_create(mos, DMU_OT_DSL_DIR_CHILD_MAP, DMU_OT_NONE, 0, tx); dmu_buf_rele(dbuf, FTAG); return (ddobj); }
/* * XDR loopback unix auth parameters. * NOTE: this is an XDR_ENCODE only routine. */ bool_t xdr_authloopback(XDR *xdrs) { uid_t uid; gid_t gid; int len; caddr_t groups; char *name = uts_nodename(); struct cred *cr; time_t now; if (xdrs->x_op != XDR_ENCODE) return (FALSE); cr = CRED(); uid = crgetuid(cr); gid = crgetgid(cr); len = crgetngroups(cr); groups = (caddr_t)crgetgroups(cr); now = gethrestime_sec(); if (xdr_uint32(xdrs, (uint32_t *)&now) && xdr_string(xdrs, &name, MAX_MACHINE_NAME) && xdr_uid_t(xdrs, &uid) && xdr_gid_t(xdrs, &gid) && xdr_array(xdrs, &groups, (uint_t *)&len, NGRPS_LOOPBACK, sizeof (int), (xdrproc_t)xdr_int)) return (TRUE); return (FALSE); }
static void dsl_dataset_user_hold_sync(void *arg, dmu_tx_t *tx) { dsl_dataset_user_hold_arg_t *dduha = arg; dsl_pool_t *dp = dmu_tx_pool(tx); nvlist_t *tmpholds; nvpair_t *pair; uint64_t now = gethrestime_sec(); if (dduha->dduha_minor != 0) tmpholds = fnvlist_alloc(); else tmpholds = NULL; for (pair = nvlist_next_nvpair(dduha->dduha_chkholds, NULL); pair != NULL; pair = nvlist_next_nvpair(dduha->dduha_chkholds, pair)) { dsl_dataset_t *ds; VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds)); dsl_dataset_user_hold_sync_one_impl(tmpholds, ds, fnvpair_value_string(pair), dduha->dduha_minor, now, tx); dsl_dataset_rele(ds, FTAG); } dsl_onexit_hold_cleanup(dp->dp_spa, tmpholds, dduha->dduha_minor); }
static int nd_auth_marshall(XDR *xdrp) { int credsize; int32_t *ptr; int hostnamelen; hostnamelen = (int)strlen(utsname.nodename); credsize = 4 + 4 + roundup(hostnamelen, 4) + 4 + 4 + 4; ptr = XDR_INLINE(xdrp, 4 + 4 + credsize + 4 + 4); if (!ptr) { cmn_err(CE_WARN, "\tnfs_dump: auth_marshall failed"); return (0); } /* * We can do the fast path. */ IXDR_PUT_INT32(ptr, AUTH_UNIX); /* cred flavor */ IXDR_PUT_INT32(ptr, credsize); /* cred len */ IXDR_PUT_INT32(ptr, gethrestime_sec()); IXDR_PUT_INT32(ptr, hostnamelen); bcopy(utsname.nodename, ptr, hostnamelen); ptr += roundup(hostnamelen, 4) / 4; IXDR_PUT_INT32(ptr, 0); /* uid */ IXDR_PUT_INT32(ptr, 0); /* gid */ IXDR_PUT_INT32(ptr, 0); /* gid list length (empty) */ IXDR_PUT_INT32(ptr, AUTH_NULL); /* verf flavor */ IXDR_PUT_INT32(ptr, 0); /* verf len */ return (1); }
/* * msgget system call. */ static int msgget(key_t key, int msgflg) { kmsqid_t *qp; kmutex_t *lock; int id, error; int ii; proc_t *pp = curproc; top: if (error = ipc_get(msq_svc, key, msgflg, (kipc_perm_t **)&qp, &lock)) return (set_errno(error)); if (IPC_FREE(&qp->msg_perm)) { mutex_exit(lock); mutex_exit(&pp->p_lock); list_create(&qp->msg_list, sizeof (struct msg), offsetof(struct msg, msg_node)); qp->msg_qnum = 0; qp->msg_lspid = qp->msg_lrpid = 0; qp->msg_stime = qp->msg_rtime = 0; qp->msg_ctime = gethrestime_sec(); qp->msg_ngt_cnt = 0; qp->msg_neg_copy = 0; for (ii = 0; ii <= MSG_MAX_QNUM; ii++) { list_create(&qp->msg_wait_snd[ii], sizeof (msgq_wakeup_t), offsetof(msgq_wakeup_t, msgw_list)); list_create(&qp->msg_wait_snd_ngt[ii], sizeof (msgq_wakeup_t), offsetof(msgq_wakeup_t, msgw_list)); } /* * The proper initialization of msg_lowest_type is to the * highest possible value. By doing this we guarantee that * when the first send happens, the lowest type will be set * properly. */ qp->msg_lowest_type = -1; list_create(&qp->msg_cpy_block, sizeof (msgq_wakeup_t), offsetof(msgq_wakeup_t, msgw_list)); qp->msg_fnd_sndr = &msg_fnd_sndr[0]; qp->msg_fnd_rdr = &msg_fnd_rdr[0]; qp->msg_rcv_cnt = 0; qp->msg_snd_cnt = 0; if (error = ipc_commit_begin(msq_svc, key, msgflg, (kipc_perm_t *)qp)) { if (error == EAGAIN) goto top; return (set_errno(error)); } qp->msg_qbytes = rctl_enforced_value(rc_process_msgmnb, pp->p_rctls, pp); qp->msg_qmax = rctl_enforced_value(rc_process_msgtql, pp->p_rctls, pp); lock = ipc_commit_end(msq_svc, &qp->msg_perm); }
/* * Print these messages by running: * echo ::zfs_dbgmsg | mdb -k * * Monitor these messages by running: * dtrace -q -n 'zfs-dbgmsg{printf("%s\n", stringof(arg0))}' */ void zfs_dbgmsg(const char *fmt, ...) { int size; va_list adx; zfs_dbgmsg_t *zdm; va_start(adx, fmt); size = vsnprintf(NULL, 0, fmt, adx); va_end(adx); /* * There is one byte of string in sizeof (zfs_dbgmsg_t), used * for the terminating null. */ zdm = kmem_alloc(sizeof (zfs_dbgmsg_t) + size, KM_SLEEP); zdm->zdm_timestamp = gethrestime_sec(); va_start(adx, fmt); (void) vsnprintf(zdm->zdm_msg, size + 1, fmt, adx); va_end(adx); DTRACE_PROBE1(zfs__dbgmsg, char *, zdm->zdm_msg); mutex_enter(&zfs_dbgmsgs_lock); list_insert_tail(&zfs_dbgmsgs, zdm); zfs_dbgmsg_size += sizeof (zfs_dbgmsg_t) + size; while (zfs_dbgmsg_size > zfs_dbgmsg_maxsize) { zdm = list_remove_head(&zfs_dbgmsgs); size = sizeof (zfs_dbgmsg_t) + strlen(zdm->zdm_msg); kmem_free(zdm, size); zfs_dbgmsg_size -= size; } mutex_exit(&zfs_dbgmsgs_lock); }
/* * When the uberblock on-disk is updated by a spa_sync, * creating a new "best" uberblock, update the one stored * in the mmp thread state, used for mmp writes. */ void mmp_update_uberblock(spa_t *spa, uberblock_t *ub) { mmp_thread_t *mmp = &spa->spa_mmp; mutex_enter(&mmp->mmp_io_lock); mmp->mmp_ub = *ub; mmp->mmp_ub.ub_timestamp = gethrestime_sec(); mutex_exit(&mmp->mmp_io_lock); }
static void vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state) { ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock)); spa_t *spa = vd->vdev_spa; if (new_state == vd->vdev_initialize_state) return; /* * Copy the vd's guid, this will be freed by the sync task. */ uint64_t *guid = kmem_zalloc(sizeof (uint64_t), KM_SLEEP); *guid = vd->vdev_guid; /* * If we're suspending, then preserving the original start time. */ if (vd->vdev_initialize_state != VDEV_INITIALIZE_SUSPENDED) { vd->vdev_initialize_action_time = gethrestime_sec(); } vd->vdev_initialize_state = new_state; dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir); VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); dsl_sync_task_nowait(spa_get_dsl(spa), vdev_initialize_zap_update_sync, guid, 2, ZFS_SPACE_CHECK_RESERVED, tx); switch (new_state) { case VDEV_INITIALIZE_ACTIVE: spa_history_log_internal(spa, "initialize", tx, "vdev=%s activated", vd->vdev_path); break; case VDEV_INITIALIZE_SUSPENDED: spa_history_log_internal(spa, "initialize", tx, "vdev=%s suspended", vd->vdev_path); break; case VDEV_INITIALIZE_CANCELED: spa_history_log_internal(spa, "initialize", tx, "vdev=%s canceled", vd->vdev_path); break; case VDEV_INITIALIZE_COMPLETE: spa_history_log_internal(spa, "initialize", tx, "vdev=%s complete", vd->vdev_path); break; default: panic("invalid state %llu", (unsigned long long)new_state); } dmu_tx_commit(tx); }
void rfs4_recall_deleg(rfs4_file_t *fp, bool_t trunc, rfs4_client_t *cp) { time_t elapsed1, elapsed2; if (fp->rf_dinfo.rd_time_recalled != 0) { elapsed1 = gethrestime_sec() - fp->rf_dinfo.rd_time_recalled; elapsed2 = gethrestime_sec() - fp->rf_dinfo.rd_time_lastwrite; /* First check to see if a revocation should occur */ if (elapsed1 > rfs4_lease_time && elapsed2 > rfs4_lease_time) { rfs4_revoke_file(fp); return; } /* * Next check to see if a recall should be done again * so quickly. */ if (elapsed1 <= ((rfs4_lease_time * 20) / 100)) return; } rfs4_recall_file(fp, rfs4_do_cb_recall, trunc, cp); }
/* * Choose a random vdev, label, and MMP block, and write over it * with a copy of the last-synced uberblock, whose timestamp * has been updated to reflect that the pool is in use. */ static void mmp_write_uberblock(spa_t *spa) { int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL; mmp_thread_t *mmp = &spa->spa_mmp; uberblock_t *ub; vdev_t *vd; int label; uint64_t offset; spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); vd = mmp_random_leaf(spa->spa_root_vdev); if (vd == NULL) { spa_config_exit(spa, SCL_STATE, FTAG); return; } mutex_enter(&mmp->mmp_io_lock); if (mmp->mmp_zio_root == NULL) mmp->mmp_zio_root = zio_root(spa, NULL, NULL, flags | ZIO_FLAG_GODFATHER); ub = &mmp->mmp_ub; ub->ub_timestamp = gethrestime_sec(); ub->ub_mmp_magic = MMP_MAGIC; ub->ub_mmp_delay = mmp->mmp_delay; vd->vdev_mmp_pending = gethrtime(); zio_t *zio = zio_null(mmp->mmp_zio_root, spa, NULL, NULL, NULL, flags); abd_t *ub_abd = abd_alloc_for_io(VDEV_UBERBLOCK_SIZE(vd), B_TRUE); abd_zero(ub_abd, VDEV_UBERBLOCK_SIZE(vd)); abd_copy_from_buf(ub_abd, ub, sizeof (uberblock_t)); mutex_exit(&mmp->mmp_io_lock); offset = VDEV_UBERBLOCK_OFFSET(vd, VDEV_UBERBLOCK_COUNT(vd) - MMP_BLOCKS_PER_LABEL + spa_get_random(MMP_BLOCKS_PER_LABEL)); label = spa_get_random(VDEV_LABELS); vdev_label_write(zio, vd, label, ub_abd, offset, VDEV_UBERBLOCK_SIZE(vd), mmp_write_done, mmp, flags | ZIO_FLAG_DONT_PROPAGATE); spa_mmp_history_add(ub->ub_txg, ub->ub_timestamp, ub->ub_mmp_delay, vd, label); zio_nowait(zio); }
static void sys_log(const char *msg) { static time_t tstamp = 0; time_t now; /* * msg is shown (at most) once per minute */ now = gethrestime_sec(); if ((tstamp + 60) < now) { tstamp = now; cmn_err(CE_WARN, msg); } }
static void dsl_dataset_user_hold_sync(void *arg, dmu_tx_t *tx) { dsl_dataset_user_hold_arg_t *dduha = arg; dsl_pool_t *dp = dmu_tx_pool(tx); nvpair_t *pair; uint64_t now = gethrestime_sec(); for (pair = nvlist_next_nvpair(dduha->dduha_holds, NULL); pair != NULL; pair = nvlist_next_nvpair(dduha->dduha_holds, pair)) { dsl_dataset_t *ds; VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds)); dsl_dataset_user_hold_sync_one(ds, fnvpair_value_string(pair), dduha->dduha_minor, now, tx); dsl_dataset_rele(ds, FTAG); } }
/* * Allocate zeroed memory if tmpfs_maxkmem has not been exceeded * or the 'musthave' flag is set. 'musthave' allocations should * always be subordinate to normal allocations so that tmpfs_maxkmem * can't be exceeded by more than a few KB. Example: when creating * a new directory, the tmpnode is a normal allocation; if that * succeeds, the dirents for "." and ".." are 'musthave' allocations. */ void * tmp_memalloc(size_t size, int musthave) { static time_t last_warning; time_t now; if (atomic_add_long_nv(&tmp_kmemspace, size) < tmpfs_maxkmem || musthave) return (kmem_zalloc(size, KM_SLEEP)); atomic_add_long(&tmp_kmemspace, -size); now = gethrestime_sec(); if (last_warning != now) { last_warning = now; cmn_err(CE_WARN, "tmp_memalloc: tmpfs over memory limit"); } return (NULL); }
void __zfs_dbgmsg(char *buf) { zfs_dbgmsg_t *zdm; int size; size = sizeof (zfs_dbgmsg_t) + strlen(buf); zdm = kmem_zalloc(size, KM_SLEEP); zdm->zdm_size = size; zdm->zdm_timestamp = gethrestime_sec(); strcpy(zdm->zdm_msg, buf); mutex_enter(&zfs_dbgmsgs_lock); list_insert_tail(&zfs_dbgmsgs, zdm); zfs_dbgmsg_size += size; zfs_dbgmsg_purge(MAX(zfs_dbgmsg_maxsize, 0)); mutex_exit(&zfs_dbgmsgs_lock); }
static void dsl_crypto_key_new_sync(void *arg1, dmu_tx_t *tx) { struct knarg *kn = arg1; dsl_dataset_t *ds = kn->kn_ds; /* * Generate a new key and add it to the keychain to be valid from * this txg onwards. */ dsl_keychain_set_key(ds->ds_dir, tx, kn->kn_wkeybuf, kn->kn_wkeylen, gethrestime_sec()); zcrypt_keychain_insert(&kn->kn_skn->skn_keychain, tx->tx_txg, kn->kn_txgkey); spa_history_log_internal( dsl_dataset_get_spa(ds), "key create", tx, "rekey succeeded dataset = %llu", ds->ds_object); }
/* * Update the uberblock and return TRUE if anything changed in this * transaction group. */ boolean_t uberblock_update(uberblock_t *ub, vdev_t *rvd, uint64_t txg, uint64_t mmp_delay) { ASSERT(ub->ub_txg < txg); /* * We explicitly do not set ub_version here, so that older versions * continue to be written with the previous uberblock version. */ ub->ub_magic = UBERBLOCK_MAGIC; ub->ub_txg = txg; ub->ub_guid_sum = rvd->vdev_guid_sum; ub->ub_timestamp = gethrestime_sec(); ub->ub_software_version = SPA_VERSION; ub->ub_mmp_magic = MMP_MAGIC; ub->ub_mmp_delay = spa_multihost(rvd->vdev_spa) ? mmp_delay : 0; ub->ub_mmp_seq = 0; return (ub->ub_rootbp.blk_birth == txg); }
/* * Create a pipe end by... * allocating a vnode-fifonode pair and initializing the fifonode. */ void makepipe(vnode_t **vpp1, vnode_t **vpp2) { fifonode_t *fnp1; fifonode_t *fnp2; vnode_t *nvp1; vnode_t *nvp2; fifodata_t *fdp; time_t now; fdp = kmem_cache_alloc(pipe_cache, KM_SLEEP); fdp->fifo_lock.flk_ref = 2; fnp1 = &fdp->fifo_fnode[0]; fnp2 = &fdp->fifo_fnode[1]; fnp1->fn_wcnt = fnp2->fn_wcnt = 1; fnp1->fn_rcnt = fnp2->fn_rcnt = 1; #if FIFODEBUG if (! Fifo_fastmode) { fnp1->fn_flag = fnp2->fn_flag = ISPIPE; } else { fnp1->fn_flag = fnp2->fn_flag = ISPIPE | FIFOFAST; } #else /* FIFODEBUG */ fnp1->fn_flag = fnp2->fn_flag = ISPIPE | FIFOFAST; #endif /* FIFODEBUG */ now = gethrestime_sec(); fnp1->fn_atime = fnp2->fn_atime = now; fnp1->fn_mtime = fnp2->fn_mtime = now; fnp1->fn_ctime = fnp2->fn_ctime = now; *vpp1 = nvp1 = FTOV(fnp1); *vpp2 = nvp2 = FTOV(fnp2); fifo_reinit_vp(nvp1); /* Reinitialize vnodes for reuse... */ fifo_reinit_vp(nvp2); nvp1->v_vfsp = fifovfsp; /* Need to re-establish VFS & device */ nvp2->v_vfsp = fifovfsp; /* before we can reuse this vnode. */ nvp1->v_rdev = fifodev; nvp2->v_rdev = fifodev; }
/* * The caller is done with the callback info. It may be that the * caller's RPC failed and the NFSv4 client has actually provided new * callback information. If so, let the caller know so they can * advantage of this and maybe retry the RPC that originally failed. */ static int rfs4_cbinfo_rele(rfs4_cbinfo_t *cbp, rfs4_cbstate_t newstate) { int cb_new = FALSE; mutex_enter(cbp->cb_lock); /* The caller gets a chance to mark the callback info as bad */ if (newstate != CB_NOCHANGE) cbp->cb_state = newstate; if (newstate == CB_FAILED) { cbp->cb_timefailed = gethrestime_sec(); /* observability */ cbp->cb_notified_of_cb_path_down = FALSE; } cbp->cb_refcnt--; /* no longer using the information */ /* * A thread may be waiting on this one to finish and if so, * let it know that it is okay to do the CB_NULL to the * client's callback server. */ if (cbp->cb_refcnt == 0 && cbp->cb_nullcaller) cv_broadcast(cbp->cb_cv_nullcaller); /* * If this is the last thread to use the callback info and * there is new callback information to try and no thread is * there ready to do the CB_NULL, then return true to teh * caller so they can do the CB_NULL */ if (cbp->cb_refcnt == 0 && cbp->cb_nullcaller == FALSE && cbp->cb_newer.cb_new == TRUE && cbp->cb_newer.cb_confirmed == TRUE) cb_new = TRUE; mutex_exit(cbp->cb_lock); return (cb_new); }
/* * Given the desired delegation type and the "history" of the file * determine the actual delegation type to return. */ static open_delegation_type4 rfs4_delegation_policy(open_delegation_type4 dtype, rfs4_dinfo_t *dinfo, clientid4 cid) { time_t elapsed; if (rfs4_deleg_policy != SRV_NORMAL_DELEGATE) return (OPEN_DELEGATE_NONE); /* * Has this file/delegation ever been recalled? If not then * no further checks for a delegation race need to be done. * However if a recall has occurred, then check to see if a * client has caused its own delegation recall to occur. If * not, then has a delegation for this file been returned * recently? If so, then do not assign a new delegation to * avoid a "delegation race" between the original client and * the new/conflicting client. */ if (dinfo->rd_ever_recalled == TRUE) { if (dinfo->rd_conflicted_client != cid) { elapsed = gethrestime_sec() - dinfo->rd_time_returned; if (elapsed < rfs4_lease_time) return (OPEN_DELEGATE_NONE); } } /* Limit the number of read grants */ if (dtype == OPEN_DELEGATE_READ && dinfo->rd_rdgrants > MAX_READ_DELEGATIONS) return (OPEN_DELEGATE_NONE); /* * Should consider limiting total number of read/write * delegations the server will permit. */ return (dtype); }
/* * Note: ci_numusers should be the number of users connected to * the share rather than the number of references on the tree but * we don't have a mechanism to track users/share in smbsrv yet. */ static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) { smb_user_t *user; ASSERT(tree); info->ci_id = tree->t_tid; info->ci_type = tree->t_res_type; info->ci_numopens = tree->t_open_files; info->ci_numusers = tree->t_refcnt; info->ci_time = gethrestime_sec() - tree->t_connect_time; info->ci_sharelen = strlen(tree->t_sharename) + 1; info->ci_share = smb_strdup(tree->t_sharename); user = tree->t_user; ASSERT(user); info->ci_namelen = user->u_domain_len + user->u_name_len + 2; info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP); (void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s", user->u_domain, user->u_name); }
static void rfs4_recall_file(rfs4_file_t *fp, void (*recall)(rfs4_deleg_state_t *, bool_t trunc), bool_t trunc, rfs4_client_t *cp) { struct master_recall_args *args; rfs4_dbe_lock(fp->rf_dbe); if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) { rfs4_dbe_unlock(fp->rf_dbe); return; } rfs4_dbe_hold(fp->rf_dbe); /* hold for new thread */ /* * Mark the time we started the recall processing. * If it has been previously recalled, do not reset the * timer since this is used for the revocation decision. */ if (fp->rf_dinfo.rd_time_recalled == 0) fp->rf_dinfo.rd_time_recalled = gethrestime_sec(); fp->rf_dinfo.rd_ever_recalled = TRUE; /* used for policy decision */ /* Client causing recall not always available */ if (cp) fp->rf_dinfo.rd_conflicted_client = cp->rc_clientid; rfs4_dbe_unlock(fp->rf_dbe); args = kmem_alloc(sizeof (struct master_recall_args), KM_SLEEP); args->fp = fp; args->recall = recall; args->trunc = trunc; (void) thread_create(NULL, 0, do_recall_file, args, 0, &p0, TS_RUN, minclsyspri); }
/*ARGSUSED*/ static void spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx) { spa_t *spa = arg1; history_arg_t *hap = arg2; const char *history_str = hap->ha_history_str; objset_t *mos = spa->spa_meta_objset; dmu_buf_t *dbp; spa_history_phys_t *shpp; size_t reclen; uint64_t le_len; nvlist_t *nvrecord; char *record_packed = NULL; int ret; /* * If we have an older pool that doesn't have a command * history object, create it now. */ mutex_enter(&spa->spa_history_lock); if (!spa->spa_history) spa_history_create_obj(spa, tx); mutex_exit(&spa->spa_history_lock); /* * Get the offset of where we need to write via the bonus buffer. * Update the offset when the write completes. */ VERIFY(0 == dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp)); shpp = dbp->db_data; dmu_buf_will_dirty(dbp, tx); #ifdef ZFS_DEBUG { dmu_object_info_t doi; dmu_object_info_from_db(dbp, &doi); ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS); } #endif VERIFY(nvlist_alloc(&nvrecord, NV_UNIQUE_NAME, KM_SLEEP) == 0); VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TIME, gethrestime_sec()) == 0); VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_WHO, hap->ha_uid) == 0); if (hap->ha_zone != NULL) VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_ZONE, hap->ha_zone) == 0); #ifdef _KERNEL VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_HOST, utsname.nodename) == 0); #endif if (hap->ha_log_type == LOG_CMD_POOL_CREATE || hap->ha_log_type == LOG_CMD_NORMAL) { VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_CMD, history_str) == 0); zfs_dbgmsg("command: %s", history_str); } else { VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_INT_EVENT, hap->ha_event) == 0); VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TXG, tx->tx_txg) == 0); VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_INT_STR, history_str) == 0); zfs_dbgmsg("internal %s pool:%s txg:%llu %s", zfs_history_event_names[hap->ha_event], spa_name(spa), (longlong_t)tx->tx_txg, history_str); } VERIFY(nvlist_size(nvrecord, &reclen, NV_ENCODE_XDR) == 0); record_packed = kmem_alloc(reclen, KM_SLEEP); VERIFY(nvlist_pack(nvrecord, &record_packed, &reclen, NV_ENCODE_XDR, KM_SLEEP) == 0); mutex_enter(&spa->spa_history_lock); if (hap->ha_log_type == LOG_CMD_POOL_CREATE) VERIFY(shpp->sh_eof == shpp->sh_pool_create_len); /* write out the packed length as little endian */ le_len = LE_64((uint64_t)reclen); ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx); if (!ret) ret = spa_history_write(spa, record_packed, reclen, shpp, tx); if (!ret && hap->ha_log_type == LOG_CMD_POOL_CREATE) { shpp->sh_pool_create_len += sizeof (le_len) + reclen; shpp->sh_bof = shpp->sh_pool_create_len; } mutex_exit(&spa->spa_history_lock); nvlist_free(nvrecord); kmem_free(record_packed, reclen); dmu_buf_rele(dbp, FTAG); strfree(hap->ha_history_str); if (hap->ha_zone != NULL) strfree(hap->ha_zone); kmem_free(hap, sizeof (history_arg_t)); }
/*ARGSUSED*/ static void spa_history_log_sync(void *arg, dmu_tx_t *tx) { nvlist_t *nvl = arg; spa_t *spa = dmu_tx_pool(tx)->dp_spa; objset_t *mos = spa->spa_meta_objset; dmu_buf_t *dbp; spa_history_phys_t *shpp; size_t reclen; uint64_t le_len; char *record_packed = NULL; int ret; /* * If we have an older pool that doesn't have a command * history object, create it now. */ mutex_enter(&spa->spa_history_lock); if (!spa->spa_history) spa_history_create_obj(spa, tx); mutex_exit(&spa->spa_history_lock); /* * Get the offset of where we need to write via the bonus buffer. * Update the offset when the write completes. */ VERIFY0(dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp)); shpp = dbp->db_data; dmu_buf_will_dirty(dbp, tx); #ifdef ZFS_DEBUG { dmu_object_info_t doi; dmu_object_info_from_db(dbp, &doi); ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS); } #endif fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec()); #ifdef _KERNEL fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname.nodename); #endif if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) { zfs_dbgmsg("command: %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD)); } else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) { if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) { zfs_dbgmsg("txg %lld %s %s (id %llu) %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME), fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } else { zfs_dbgmsg("txg %lld %s %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) { zfs_dbgmsg("ioctl %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL)); } record_packed = fnvlist_pack(nvl, &reclen); mutex_enter(&spa->spa_history_lock); /* write out the packed length as little endian */ le_len = LE_64((uint64_t)reclen); ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx); if (!ret) ret = spa_history_write(spa, record_packed, reclen, shpp, tx); /* The first command is the create, which we keep forever */ if (ret == 0 && shpp->sh_pool_create_len == 0 && nvlist_exists(nvl, ZPOOL_HIST_CMD)) { shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof; } mutex_exit(&spa->spa_history_lock); fnvlist_pack_free(record_packed, reclen); dmu_buf_rele(dbp, FTAG); fnvlist_free(nvl); }
/* ARGSUSED */ static void dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx) { static const char *old_names[] = { "scrub_bookmark", "scrub_ddt_bookmark", "scrub_ddt_class_max", "scrub_queue", "scrub_min_txg", "scrub_max_txg", "scrub_func", "scrub_errors", NULL }; dsl_pool_t *dp = scn->scn_dp; spa_t *spa = dp->dp_spa; int i; /* Remove any remnants of an old-style scrub. */ for (i = 0; old_names[i]; i++) { (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, old_names[i], tx); } if (scn->scn_phys.scn_queue_obj != 0) { VERIFY(0 == dmu_object_free(dp->dp_meta_objset, scn->scn_phys.scn_queue_obj, tx)); scn->scn_phys.scn_queue_obj = 0; } /* * If we were "restarted" from a stopped state, don't bother * with anything else. */ if (scn->scn_phys.scn_state != DSS_SCANNING) return; if (complete) scn->scn_phys.scn_state = DSS_FINISHED; else scn->scn_phys.scn_state = DSS_CANCELED; spa_history_log_internal(spa, "scan done", tx, "complete=%u", complete); if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) { mutex_enter(&spa->spa_scrub_lock); while (spa->spa_scrub_inflight > 0) { cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock); } mutex_exit(&spa->spa_scrub_lock); spa->spa_scrub_started = B_FALSE; spa->spa_scrub_active = B_FALSE; /* * If the scrub/resilver completed, update all DTLs to * reflect this. Whether it succeeded or not, vacate * all temporary scrub DTLs. */ vdev_dtl_reassess(spa->spa_root_vdev, tx->tx_txg, complete ? scn->scn_phys.scn_max_txg : 0, B_TRUE); if (complete) { spa_event_notify(spa, NULL, scn->scn_phys.scn_min_txg ? ESC_ZFS_RESILVER_FINISH : ESC_ZFS_SCRUB_FINISH); } spa_errlog_rotate(spa); /* * We may have finished replacing a device. * Let the async thread assess this and handle the detach. */ spa_async_request(spa, SPA_ASYNC_RESILVER_DONE); } scn->scn_phys.scn_end_time = gethrestime_sec(); }
static void dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) { dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan; pool_scan_func_t *funcp = arg; dmu_object_type_t ot = 0; dsl_pool_t *dp = scn->scn_dp; spa_t *spa = dp->dp_spa; ASSERT(scn->scn_phys.scn_state != DSS_SCANNING); ASSERT(*funcp > POOL_SCAN_NONE && *funcp < POOL_SCAN_FUNCS); bzero(&scn->scn_phys, sizeof (scn->scn_phys)); scn->scn_phys.scn_func = *funcp; scn->scn_phys.scn_state = DSS_SCANNING; scn->scn_phys.scn_min_txg = 0; scn->scn_phys.scn_max_txg = tx->tx_txg; scn->scn_phys.scn_ddt_class_max = DDT_CLASSES - 1; /* the entire DDT */ scn->scn_phys.scn_start_time = gethrestime_sec(); scn->scn_phys.scn_errors = 0; scn->scn_phys.scn_to_examine = spa->spa_root_vdev->vdev_stat.vs_alloc; scn->scn_restart_txg = 0; spa_scan_stat_init(spa); if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) { scn->scn_phys.scn_ddt_class_max = zfs_scrub_ddt_class_max; /* rewrite all disk labels */ vdev_config_dirty(spa->spa_root_vdev); if (vdev_resilver_needed(spa->spa_root_vdev, &scn->scn_phys.scn_min_txg, &scn->scn_phys.scn_max_txg)) { spa_event_notify(spa, NULL, ESC_ZFS_RESILVER_START); } else { spa_event_notify(spa, NULL, ESC_ZFS_SCRUB_START); } spa->spa_scrub_started = B_TRUE; /* * If this is an incremental scrub, limit the DDT scrub phase * to just the auto-ditto class (for correctness); the rest * of the scrub should go faster using top-down pruning. */ if (scn->scn_phys.scn_min_txg > TXG_INITIAL) scn->scn_phys.scn_ddt_class_max = DDT_CLASS_DITTO; } /* back to the generic stuff */ if (dp->dp_blkstats == NULL) { dp->dp_blkstats = kmem_alloc(sizeof (zfs_all_blkstats_t), KM_SLEEP); } bzero(dp->dp_blkstats, sizeof (zfs_all_blkstats_t)); if (spa_version(spa) < SPA_VERSION_DSL_SCRUB) ot = DMU_OT_ZAP_OTHER; scn->scn_phys.scn_queue_obj = zap_create(dp->dp_meta_objset, ot ? ot : DMU_OT_SCAN_QUEUE, DMU_OT_NONE, 0, tx); dsl_scan_sync_state(scn, tx); spa_history_log_internal(spa, "scan setup", tx, "func=%u mintxg=%llu maxtxg=%llu", *funcp, scn->scn_phys.scn_min_txg, scn->scn_phys.scn_max_txg); }
/* * tcp_time_wait_processing() handles processing of incoming packets when * the tcp_t is in the TIME_WAIT state. * * A TIME_WAIT tcp_t that has an associated open TCP end point (not in * detached state) is never put on the time wait list. */ void tcp_time_wait_processing(tcp_t *tcp, mblk_t *mp, uint32_t seg_seq, uint32_t seg_ack, int seg_len, tcpha_t *tcpha, ip_recv_attr_t *ira) { int32_t bytes_acked; int32_t gap; int32_t rgap; tcp_opt_t tcpopt; uint_t flags; uint32_t new_swnd = 0; conn_t *nconnp; conn_t *connp = tcp->tcp_connp; tcp_stack_t *tcps = tcp->tcp_tcps; BUMP_LOCAL(tcp->tcp_ibsegs); DTRACE_PROBE2(tcp__trace__recv, mblk_t *, mp, tcp_t *, tcp); flags = (unsigned int)tcpha->tha_flags & 0xFF; new_swnd = ntohs(tcpha->tha_win) << ((tcpha->tha_flags & TH_SYN) ? 0 : tcp->tcp_snd_ws); if (tcp->tcp_snd_ts_ok) { if (!tcp_paws_check(tcp, tcpha, &tcpopt)) { tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt, tcp->tcp_rnxt, TH_ACK); goto done; } } gap = seg_seq - tcp->tcp_rnxt; rgap = tcp->tcp_rwnd - (gap + seg_len); if (gap < 0) { TCPS_BUMP_MIB(tcps, tcpInDataDupSegs); TCPS_UPDATE_MIB(tcps, tcpInDataDupBytes, (seg_len > -gap ? -gap : seg_len)); seg_len += gap; if (seg_len < 0 || (seg_len == 0 && !(flags & TH_FIN))) { if (flags & TH_RST) { goto done; } if ((flags & TH_FIN) && seg_len == -1) { /* * When TCP receives a duplicate FIN in * TIME_WAIT state, restart the 2 MSL timer. * See page 73 in RFC 793. Make sure this TCP * is already on the TIME_WAIT list. If not, * just restart the timer. */ if (TCP_IS_DETACHED(tcp)) { if (tcp_time_wait_remove(tcp, NULL) == B_TRUE) { tcp_time_wait_append(tcp); TCP_DBGSTAT(tcps, tcp_rput_time_wait); } } else { ASSERT(tcp != NULL); TCP_TIMER_RESTART(tcp, tcps->tcps_time_wait_interval); } tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt, tcp->tcp_rnxt, TH_ACK); goto done; } flags |= TH_ACK_NEEDED; seg_len = 0; goto process_ack; } /* Fix seg_seq, and chew the gap off the front. */ seg_seq = tcp->tcp_rnxt; } if ((flags & TH_SYN) && gap > 0 && rgap < 0) { /* * Make sure that when we accept the connection, pick * an ISS greater than (tcp_snxt + ISS_INCR/2) for the * old connection. * * The next ISS generated is equal to tcp_iss_incr_extra * + ISS_INCR/2 + other components depending on the * value of tcp_strong_iss. We pre-calculate the new * ISS here and compare with tcp_snxt to determine if * we need to make adjustment to tcp_iss_incr_extra. * * The above calculation is ugly and is a * waste of CPU cycles... */ uint32_t new_iss = tcps->tcps_iss_incr_extra; int32_t adj; ip_stack_t *ipst = tcps->tcps_netstack->netstack_ip; switch (tcps->tcps_strong_iss) { case 2: { /* Add time and MD5 components. */ uint32_t answer[4]; struct { uint32_t ports; in6_addr_t src; in6_addr_t dst; } arg; MD5_CTX context; mutex_enter(&tcps->tcps_iss_key_lock); context = tcps->tcps_iss_key; mutex_exit(&tcps->tcps_iss_key_lock); arg.ports = connp->conn_ports; /* We use MAPPED addresses in tcp_iss_init */ arg.src = connp->conn_laddr_v6; arg.dst = connp->conn_faddr_v6; MD5Update(&context, (uchar_t *)&arg, sizeof (arg)); MD5Final((uchar_t *)answer, &context); answer[0] ^= answer[1] ^ answer[2] ^ answer[3]; new_iss += (gethrtime() >> ISS_NSEC_SHT) + answer[0]; break; } case 1: /* Add time component and min random (i.e. 1). */ new_iss += (gethrtime() >> ISS_NSEC_SHT) + 1; break; default: /* Add only time component. */ new_iss += (uint32_t)gethrestime_sec() * ISS_INCR; break; } if ((adj = (int32_t)(tcp->tcp_snxt - new_iss)) > 0) { /* * New ISS not guaranteed to be ISS_INCR/2 * ahead of the current tcp_snxt, so add the * difference to tcp_iss_incr_extra. */ tcps->tcps_iss_incr_extra += adj; } /* * If tcp_clean_death() can not perform the task now, * drop the SYN packet and let the other side re-xmit. * Otherwise pass the SYN packet back in, since the * old tcp state has been cleaned up or freed. */ if (tcp_clean_death(tcp, 0) == -1) goto done; nconnp = ipcl_classify(mp, ira, ipst); if (nconnp != NULL) { TCP_STAT(tcps, tcp_time_wait_syn_success); /* Drops ref on nconnp */ tcp_reinput(nconnp, mp, ira, ipst); return; } goto done; }
/* * msgctl system call. * * gets q lock (via ipc_lookup), releases before return. * may call users of msg_lock */ static int msgctl(int msgid, int cmd, void *arg) { STRUCT_DECL(msqid_ds, ds); /* SVR4 queue work area */ kmsqid_t *qp; /* ptr to associated q */ int error; struct cred *cr; model_t mdl = get_udatamodel(); struct msqid_ds64 ds64; kmutex_t *lock; proc_t *pp = curproc; STRUCT_INIT(ds, mdl); cr = CRED(); /* * Perform pre- or non-lookup actions (e.g. copyins, RMID). */ switch (cmd) { case IPC_SET: if (copyin(arg, STRUCT_BUF(ds), STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_SET64: if (copyin(arg, &ds64, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; case IPC_RMID: if (error = ipc_rmid(msq_svc, msgid, cr)) return (set_errno(error)); return (0); } /* * get msqid_ds for this msgid */ if ((lock = ipc_lookup(msq_svc, msgid, (kipc_perm_t **)&qp)) == NULL) return (set_errno(EINVAL)); switch (cmd) { case IPC_SET: if (STRUCT_FGET(ds, msg_qbytes) > qp->msg_qbytes && secpolicy_ipc_config(cr) != 0) { mutex_exit(lock); return (set_errno(EPERM)); } if (error = ipcperm_set(msq_svc, cr, &qp->msg_perm, &STRUCT_BUF(ds)->msg_perm, mdl)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = STRUCT_FGET(ds, msg_qbytes); qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT: if (error = ipcperm_access(&qp->msg_perm, MSG_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat(&STRUCT_BUF(ds)->msg_perm, &qp->msg_perm, mdl); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); STRUCT_FSETP(ds, msg_first, NULL); /* kernel addr */ STRUCT_FSETP(ds, msg_last, NULL); STRUCT_FSET(ds, msg_cbytes, qp->msg_cbytes); STRUCT_FSET(ds, msg_qnum, qp->msg_qnum); STRUCT_FSET(ds, msg_qbytes, qp->msg_qbytes); STRUCT_FSET(ds, msg_lspid, qp->msg_lspid); STRUCT_FSET(ds, msg_lrpid, qp->msg_lrpid); STRUCT_FSET(ds, msg_stime, qp->msg_stime); STRUCT_FSET(ds, msg_rtime, qp->msg_rtime); STRUCT_FSET(ds, msg_ctime, qp->msg_ctime); break; case IPC_SET64: mutex_enter(&pp->p_lock); if ((ds64.msgx_qbytes > qp->msg_qbytes) && secpolicy_ipc_config(cr) != 0 && rctl_test(rc_process_msgmnb, pp->p_rctls, pp, ds64.msgx_qbytes, RCA_SAFE) & RCT_DENY) { mutex_exit(&pp->p_lock); mutex_exit(lock); return (set_errno(EPERM)); } mutex_exit(&pp->p_lock); if (error = ipcperm_set64(msq_svc, cr, &qp->msg_perm, &ds64.msgx_perm)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = ds64.msgx_qbytes; qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT64: if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat64(&ds64.msgx_perm, &qp->msg_perm); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); ds64.msgx_cbytes = qp->msg_cbytes; ds64.msgx_qnum = qp->msg_qnum; ds64.msgx_qbytes = qp->msg_qbytes; ds64.msgx_lspid = qp->msg_lspid; ds64.msgx_lrpid = qp->msg_lrpid; ds64.msgx_stime = qp->msg_stime; ds64.msgx_rtime = qp->msg_rtime; ds64.msgx_ctime = qp->msg_ctime; break; default: mutex_exit(lock); return (set_errno(EINVAL)); } mutex_exit(lock); /* * Do copyout last (after releasing mutex). */ switch (cmd) { case IPC_STAT: if (copyout(STRUCT_BUF(ds), arg, STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_STAT64: if (copyout(&ds64, arg, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; } return (0); }
/*ARGSUSED*/ static void spa_history_log_sync(void *arg, dmu_tx_t *tx) { nvlist_t *nvl = arg; spa_t *spa = dmu_tx_pool(tx)->dp_spa; objset_t *mos = spa->spa_meta_objset; dmu_buf_t *dbp; spa_history_phys_t *shpp; size_t reclen; uint64_t le_len; char *record_packed = NULL; int ret; /* * If we have an older pool that doesn't have a command * history object, create it now. */ mutex_enter(&spa->spa_history_lock); if (!spa->spa_history) spa_history_create_obj(spa, tx); mutex_exit(&spa->spa_history_lock); /* * Get the offset of where we need to write via the bonus buffer. * Update the offset when the write completes. */ VERIFY0(dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp)); shpp = dbp->db_data; dmu_buf_will_dirty(dbp, tx); #ifdef ZFS_DEBUG { dmu_object_info_t doi; dmu_object_info_from_db(dbp, &doi); ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS); } #endif fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec()); fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname()->nodename); if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) { zfs_dbgmsg("command: %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD)); } else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) { if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) { zfs_dbgmsg("txg %lld %s %s (id %llu) %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME), fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } else { zfs_dbgmsg("txg %lld %s %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } /* * The history sysevent is posted only for internal history * messages to show what has happened, not how it happened. For * example, the following command: * * # zfs destroy -r tank/foo * * will result in one sysevent posted per dataset that is * destroyed as a result of the command - which could be more * than one event in total. By contrast, if the sysevent was * posted as a result of the ZPOOL_HIST_CMD key being present * it would result in only one sysevent being posted with the * full command line arguments, requiring the consumer to know * how to parse and understand zfs(1M) command invocations. */ spa_history_log_notify(spa, nvl); } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) { zfs_dbgmsg("ioctl %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL)); } VERIFY3U(nvlist_pack(nvl, &record_packed, &reclen, NV_ENCODE_NATIVE, KM_SLEEP), ==, 0); mutex_enter(&spa->spa_history_lock); /* write out the packed length as little endian */ le_len = LE_64((uint64_t)reclen); ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx); if (!ret) ret = spa_history_write(spa, record_packed, reclen, shpp, tx); /* The first command is the create, which we keep forever */ if (ret == 0 && shpp->sh_pool_create_len == 0 && nvlist_exists(nvl, ZPOOL_HIST_CMD)) { shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof; } mutex_exit(&spa->spa_history_lock); fnvlist_pack_free(record_packed, reclen); dmu_buf_rele(dbp, FTAG); fnvlist_free(nvl); }