/* * Add a new multicast entry. * * Search hash table based on address. If match found then * update associated val (which is chain of ports), otherwise * create new key/val (addr/port) pair and insert into table. */ int vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) { int dup = 0; int rv = 0; mfdb_ent_t *ment = NULL; mfdb_ent_t *tmp_ent = NULL; mfdb_ent_t *new_ent = NULL; void *tgt = NULL; if (devtype == VSW_VNETPORT) { /* * Being invoked from a vnet. */ ASSERT(arg != NULL); tgt = arg; D2(NULL, "%s: port %d : address 0x%llx", __func__, ((vsw_port_t *)arg)->p_instance, addr); } else { /* * We are being invoked via the m_multicst mac entry * point. */ D2(NULL, "%s: address 0x%llx", __func__, addr); tgt = (void *)vswp; } WRITE_ENTER(&vswp->mfdbrw); if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t *)&ment) != 0) { /* address not currently in table */ ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); ment->d_addr = (void *)tgt; ment->d_type = devtype; ment->nextp = NULL; if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t)ment) != 0) { DERR(vswp, "%s: hash table insertion failed", __func__); kmem_free(ment, sizeof (mfdb_ent_t)); rv = 1; } else { D2(vswp, "%s: added initial entry for 0x%llx to " "table", __func__, addr); } } else { /* * Address in table. Check to see if specified port * is already associated with the address. If not add * it now. */ tmp_ent = ment; while (tmp_ent != NULL) { if (tmp_ent->d_addr == (void *)tgt) { if (devtype == VSW_VNETPORT) { DERR(vswp, "%s: duplicate port entry " "found for portid %ld and key " "0x%llx", __func__, ((vsw_port_t *)arg)->p_instance, addr); } else { DERR(vswp, "%s: duplicate entry found" "for key 0x%llx", __func__, addr); } rv = 1; dup = 1; break; } tmp_ent = tmp_ent->nextp; } /* * Port not on list so add it to end now. */ if (0 == dup) { D2(vswp, "%s: added entry for 0x%llx to table", __func__, addr); new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); new_ent->d_addr = (void *)tgt; new_ent->d_type = devtype; new_ent->nextp = NULL; tmp_ent = ment; while (tmp_ent->nextp != NULL) tmp_ent = tmp_ent->nextp; tmp_ent->nextp = new_ent; } } RW_EXIT(&vswp->mfdbrw); return (rv); }
/* * Mount a remote root fs via. NFS. It goes like this: * - Call nfs_boot_init() to fill in the nfs_diskless struct * - build the rootfs mount point and call mountnfs() to do the rest. */ int nfs_mountroot(void) { struct timespec ts; struct nfs_diskless *nd; struct vattr attr; struct mount *mp; struct vnode *vp; struct lwp *l; long n; int error; l = curlwp; /* XXX */ if (device_class(root_device) != DV_IFNET) return (ENODEV); /* * XXX time must be non-zero when we init the interface or else * the arp code will wedge. [Fixed now in if_ether.c] * However, the NFS attribute cache gives false "hits" when the * current time < nfs_attrtimeo(nmp, np) so keep this in for now. */ if (time_second < NFS_MAXATTRTIMO) { ts.tv_sec = NFS_MAXATTRTIMO; ts.tv_nsec = 0; tc_setclock(&ts); } /* * Call nfs_boot_init() to fill in the nfs_diskless struct. * Side effect: Finds and configures a network interface. */ nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); error = nfs_boot_init(nd, l); if (error) { kmem_free(nd, sizeof(*nd)); return (error); } /* * Create the root mount point. */ error = nfs_mount_diskless(&nd->nd_root, "/", &mp, &vp, l); if (error) goto out; printf("root on %s\n", nd->nd_root.ndm_host); /* * Link it into the mount list. */ mountlist_append(mp); rootvp = vp; mp->mnt_vnodecovered = NULLVP; vfs_unbusy(mp, false, NULL); /* Get root attributes (for the time). */ vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &attr, l->l_cred); VOP_UNLOCK(vp); if (error) panic("nfs_mountroot: getattr for root"); n = attr.va_atime.tv_sec; #ifdef DEBUG printf("root time: 0x%lx\n", n); #endif setrootfstime(n); out: if (error) nfs_boot_cleanup(nd, l); kmem_free(nd, sizeof(*nd)); return (error); }
/* * Look up a vnode/nfsnode by file handle. * Callers must check for mount points!! * In all cases, a pointer to a * nfsnode structure is returned. */ int nfs_nget1(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int lkflags) { struct nfsnode *np; struct vnode *vp; struct nfsmount *nmp = VFSTONFS(mntp); int error; struct fh_match fhm; fhm.fhm_fhp = fhp; fhm.fhm_fhsize = fhsize; loop: rw_enter(&nmp->nm_rbtlock, RW_READER); np = rb_tree_find_node(&nmp->nm_rbtree, &fhm); if (np != NULL) { vp = NFSTOV(np); mutex_enter(vp->v_interlock); rw_exit(&nmp->nm_rbtlock); error = vget(vp, LK_EXCLUSIVE | lkflags); if (error == EBUSY) return error; if (error) goto loop; *npp = np; return(0); } rw_exit(&nmp->nm_rbtlock); error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, NULL, &vp); if (error) { *npp = 0; return (error); } np = pool_get(&nfs_node_pool, PR_WAITOK); memset(np, 0, sizeof *np); np->n_vnode = vp; /* * Insert the nfsnode in the hash queue for its new file handle */ if (fhsize > NFS_SMALLFH) { np->n_fhp = kmem_alloc(fhsize, KM_SLEEP); } else np->n_fhp = &np->n_fh; memcpy(np->n_fhp, fhp, fhsize); np->n_fhsize = fhsize; np->n_accstamp = -1; np->n_vattr = pool_get(&nfs_vattr_pool, PR_WAITOK); rw_enter(&nmp->nm_rbtlock, RW_WRITER); if (NULL != rb_tree_find_node(&nmp->nm_rbtree, &fhm)) { rw_exit(&nmp->nm_rbtlock); if (fhsize > NFS_SMALLFH) { kmem_free(np->n_fhp, fhsize); } pool_put(&nfs_vattr_pool, np->n_vattr); pool_put(&nfs_node_pool, np); ungetnewvnode(vp); goto loop; } vp->v_data = np; genfs_node_init(vp, &nfs_genfsops); /* * Initalize read/write creds to useful values. VOP_OPEN will * overwrite these. */ np->n_rcred = curlwp->l_cred; kauth_cred_hold(np->n_rcred); np->n_wcred = curlwp->l_cred; kauth_cred_hold(np->n_wcred); VOP_LOCK(vp, LK_EXCLUSIVE); NFS_INVALIDATE_ATTRCACHE(np); uvm_vnp_setsize(vp, 0); (void)rb_tree_insert_node(&nmp->nm_rbtree, np); rw_exit(&nmp->nm_rbtlock); *npp = np; return (0); }
/* * smb_encode_stream_info * * This function encodes the streams information. * The following rules about how have been derived from observed NT * behaviour. * * If the target is a file: * 1. If there are no named streams, the response should still contain * an entry for the unnamed stream. * 2. If there are named streams, the response should contain an entry * for the unnamed stream followed by the entries for the named * streams. * * If the target is a directory: * 1. If there are no streams, the response is complete. Directories * do not report the unnamed stream. * 2. If there are streams, the response should contain entries for * those streams but there should not be an entry for the unnamed * stream. * * Note that the stream name lengths exclude the null terminator but * the field lengths (i.e. next offset calculations) need to include * the null terminator and be padded to a multiple of 8 bytes. The * last entry does not seem to need any padding. * * If an error is encountered when trying to read the stream entries * (smb_odir_read_streaminfo) it is treated as if there are no [more] * entries. The entries that have been read so far are returned and * no error is reported. * * Offset calculation: * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 */ static void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) { char *stream_name; uint32_t next_offset; uint32_t stream_nlen; uint32_t pad; u_offset_t datasz, allocsz; boolean_t is_dir; smb_streaminfo_t *sinfo, *sinfo_next; int rc = 0; boolean_t done = B_FALSE; boolean_t eos = B_FALSE; uint16_t odid; smb_odir_t *od = NULL; smb_node_t *fnode = qinfo->qi_node; smb_attr_t *attr = &qinfo->qi_attr; ASSERT(fnode); if (SMB_IS_STREAM(fnode)) { fnode = fnode->n_unode; ASSERT(fnode); } ASSERT(fnode->n_magic == SMB_NODE_MAGIC); ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); is_dir = (attr->sa_vattr.va_type == VDIR); datasz = attr->sa_vattr.va_size; allocsz = attr->sa_allocsz; odid = smb_odir_openat(sr, fnode); if (odid != 0) od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od != NULL) rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); if ((od == NULL) || (rc != 0) || (eos)) done = B_TRUE; /* If not a directory, encode an entry for the unnamed stream. */ if (!is_dir) { stream_name = "::$DATA"; stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); if (done) next_offset = 0; else next_offset = 24 + stream_nlen + smb_ascii_or_unicode_null_len(sr); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, next_offset, stream_nlen, datasz, allocsz, stream_name); } /* * Since last packet does not have a pad we need to check * for the next stream before we encode the current one */ while (!done) { stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); sinfo_next->si_name[0] = 0; rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); if ((rc != 0) || (eos)) { done = B_TRUE; next_offset = 0; pad = 0; } else { next_offset = 24 + stream_nlen + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(next_offset, 8); next_offset += pad; } (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", sr, next_offset, stream_nlen, sinfo->si_size, sinfo->si_alloc_size, sinfo->si_name, pad); (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); } kmem_free(sinfo, sizeof (smb_streaminfo_t)); kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); if (od) { smb_odir_close(od); smb_odir_release(od); } }
void dmu_objset_evict(objset_t *os) { dsl_dataset_t *ds = os->os_dsl_dataset; for (int t = 0; t < TXG_SIZE; t++) ASSERT(!dmu_objset_is_dirty(os, t)); if (ds) { if (!dsl_dataset_is_snapshot(ds)) { VERIFY(0 == dsl_prop_unregister(ds, "checksum", checksum_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "compression", compression_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "copies", copies_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "dedup", dedup_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "logbias", logbias_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "sync", sync_changed_cb, os)); } VERIFY(0 == dsl_prop_unregister(ds, "primarycache", primary_cache_changed_cb, os)); VERIFY(0 == dsl_prop_unregister(ds, "secondarycache", secondary_cache_changed_cb, os)); } if (os->os_sa) sa_tear_down(os); /* * We should need only a single pass over the dnode list, since * nothing can be added to the list at this point. */ (void) dmu_objset_evict_dbufs(os); dnode_special_close(&os->os_meta_dnode); if (DMU_USERUSED_DNODE(os)) { dnode_special_close(&os->os_userused_dnode); dnode_special_close(&os->os_groupused_dnode); } zil_free(os->os_zil); ASSERT3P(list_head(&os->os_dnodes), ==, NULL); VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf) == 1); /* * This is a barrier to prevent the objset from going away in * dnode_move() until we can safely ensure that the objset is still in * use. We consider the objset valid before the barrier and invalid * after the barrier. */ rw_enter(&os_lock, RW_READER); rw_exit(&os_lock); mutex_destroy(&os->os_lock); mutex_destroy(&os->os_obj_lock); mutex_destroy(&os->os_user_ptr_lock); kmem_free(os, sizeof (objset_t)); }
/* * Check if user has requested permission. If descendent is set, must have * descendent perms. */ int dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm, cred_t *cr) { dsl_dir_t *dd; dsl_pool_t *dp; void *cookie; int error; char checkflag; objset_t *mos; avl_tree_t permsets; perm_set_t *setnode; dp = ds->ds_dir->dd_pool; mos = dp->dp_meta_objset; if (dsl_delegation_on(mos) == B_FALSE) return (ECANCELED); if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < SPA_VERSION_DELEGATED_PERMS) return (EPERM); if (dsl_dataset_is_snapshot(ds) || descendent) { /* * Snapshots are treated as descendents only, * local permissions do not apply. */ checkflag = ZFS_DELEG_DESCENDENT; } else { checkflag = ZFS_DELEG_LOCAL; } avl_create(&permsets, perm_set_compare, sizeof (perm_set_t), offsetof(perm_set_t, p_node)); rw_enter(&dp->dp_config_rwlock, RW_READER); for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent, checkflag = ZFS_DELEG_DESCENDENT) { uint64_t zapobj; boolean_t expanded; /* * If not in global zone then make sure * the zoned property is set */ if (!INGLOBALZONE(curproc)) { uint64_t zoned; if (dsl_prop_get_dd(dd, zfs_prop_to_name(ZFS_PROP_ZONED), 8, 1, &zoned, NULL, B_FALSE) != 0) break; if (!zoned) break; } zapobj = dd->dd_phys->dd_deleg_zapobj; if (zapobj == 0) continue; dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr); again: expanded = B_FALSE; for (setnode = avl_first(&permsets); setnode; setnode = AVL_NEXT(&permsets, setnode)) { if (setnode->p_matched == B_TRUE) continue; /* See if this set directly grants this permission */ error = dsl_check_access(mos, zapobj, ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm); if (error == 0) goto success; if (error == EPERM) setnode->p_matched = B_TRUE; /* See if this set includes other sets */ error = dsl_load_sets(mos, zapobj, ZFS_DELEG_NAMED_SET_SETS, 0, setnode->p_setname, &permsets); if (error == 0) setnode->p_matched = expanded = B_TRUE; } /* * If we expanded any sets, that will define more sets, * which we need to check. */ if (expanded) goto again; error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr); if (error == 0) goto success; } error = EPERM; success: rw_exit(&dp->dp_config_rwlock); cookie = NULL; while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) kmem_free(setnode, sizeof (perm_set_t)); return (error); }
/** * Remove given item & update the tree * * @root radix root * @info item info * @return error code */ error_t radix_tree_remove_item(struct radix_s *root, radix_item_info_t *info) { kmem_req_t req; struct radix_node_s *current_node; struct radix_node_s *current_parent; uint_t current_height; uint_t next_child; uint_t deleted; uint_t key; uint_t i; req.type = KMEM_RADIX_NODE; current_node = info->node; current_node->children[info->index] = NULL; bitmap_clear(current_node->bitmap, info->index); current_node->count--; current_height = info->height; next_child = info->index; key = info->key; // updating local tag for (i = 0; i < NB_TAGS; ++i) TAG_CLEAR(current_node, i, next_child); if (current_node->count == 0) { req.ptr = current_node; kmem_free(&req); deleted = 1; } current_node = current_node->parent; current_height--; // going back up the tree, up till we reach the root // updating tags on the way up // deleting childless nodes on the way up while (current_node) { next_child = NEXT_CHILD(root, current_height, key); current_parent = current_node->parent; if (deleted) // child node was deleted { current_node->children[next_child] = NULL; bitmap_clear(current_node->bitmap, next_child); current_node->count--; for (i = 0; i < NB_TAGS; ++i) TAG_CLEAR(current_node, i, next_child); } else { struct radix_node_s* temp_node = current_node->children[next_child]; for (i = 0; i < NB_TAGS; ++i) { if (temp_node->tags[i]) TAG_SET(current_node, i, next_child); else TAG_CLEAR(current_node, i, next_child); } } deleted = 0; if (current_node->count == 0) { req.ptr = current_node; kmem_free(&req); deleted = 1; } current_node = current_parent; current_height--; } // check if we can shrink the tree shrink_tree(root); return 0; }
void crgrprele(credgrp_t *grps) { if (atomic_add_32_nv(&grps->crg_ref, -1) == 0) kmem_free(grps, CREDGRPSZ(grps->crg_ngroups)); }
/* * removes pci_ispec_t from the ino's link list. * uses hardware mutex to lock out interrupt threads. * Side effects: interrupt belongs to that ino is turned off on return. * if we are sharing PCI slot with other inos, the caller needs * to turn it back on. */ void ib_ino_rem_intr(pci_t *pci_p, ib_ino_pil_t *ipil_p, ih_t *ih_p) { ib_ino_info_t *ino_p = ipil_p->ipil_ino_p; int i; ib_ino_t ino = ino_p->ino_ino; ih_t *ih_lst = ipil_p->ipil_ih_head; volatile uint64_t *state_reg = IB_INO_INTR_STATE_REG(ino_p->ino_ib_p, ino); hrtime_t start_time; ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); /* disable interrupt, this could disrupt devices sharing our slot */ IB_INO_INTR_OFF(ino_p->ino_map_reg); *ino_p->ino_map_reg; /* do NOT modify the link list until after the busy wait */ /* * busy wait if there is interrupt being processed. * either the pending state will be cleared by the interrupt wrapper * or the interrupt will be marked as blocked indicating that it was * jabbering. */ start_time = gethrtime(); while ((ino_p->ino_unclaimed_intrs <= pci_unclaimed_intr_max) && IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) { if (gethrtime() - start_time > pci_intrpend_timeout) { pbm_t *pbm_p = pci_p->pci_pbm_p; cmn_err(CE_WARN, "%s:%s: ib_ino_rem_intr %x timeout", pbm_p->pbm_nameinst_str, pbm_p->pbm_nameaddr_str, ino); break; } } if (ipil_p->ipil_ih_size == 1) { if (ih_lst != ih_p) goto not_found; /* no need to set head/tail as ino_p will be freed */ goto reset; } /* * if the interrupt was previously blocked (left in pending state) * because of jabber we need to clear the pending state in case the * jabber has gone away. */ if (ino_p->ino_unclaimed_intrs > pci_unclaimed_intr_max) { cmn_err(CE_WARN, "%s%d: ib_ino_rem_intr: ino 0x%x has been unblocked", ddi_driver_name(pci_p->pci_dip), ddi_get_instance(pci_p->pci_dip), ino_p->ino_ino); ino_p->ino_unclaimed_intrs = 0; IB_INO_INTR_CLEAR(ino_p->ino_clr_reg); } /* search the link list for ih_p */ for (i = 0; (i < ipil_p->ipil_ih_size) && (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next) ; if (ih_lst->ih_next != ih_p) goto not_found; /* remove ih_p from the link list and maintain the head/tail */ ih_lst->ih_next = ih_p->ih_next; if (ipil_p->ipil_ih_head == ih_p) ipil_p->ipil_ih_head = ih_p->ih_next; if (ipil_p->ipil_ih_tail == ih_p) ipil_p->ipil_ih_tail = ih_lst; ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; reset: if (ih_p->ih_config_handle) pci_config_teardown(&ih_p->ih_config_handle); if (ih_p->ih_ksp != NULL) kstat_delete(ih_p->ih_ksp); kmem_free(ih_p, sizeof (ih_t)); ipil_p->ipil_ih_size--; return; not_found: DEBUG2(DBG_R_INTX, ino_p->ino_ib_p->ib_pci_p->pci_dip, "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); }
/* register callback to mdeg */ static int i_vldc_mdeg_register(vldc_t *vldcp) { mdeg_prop_spec_t *pspecp; mdeg_node_spec_t *inst_specp; mdeg_handle_t mdeg_hdl; size_t templatesz; int inst; char *name; size_t namesz; char *nameprop; int rv; /* get the unique vldc instance assigned by the LDom manager */ inst = ddi_prop_get_int(DDI_DEV_T_ANY, vldcp->dip, DDI_PROP_DONTPASS, "reg", -1); if (inst == -1) { cmn_err(CE_NOTE, "?vldc%d has no 'reg' property", ddi_get_instance(vldcp->dip)); return (DDI_FAILURE); } /* get the name of the vldc instance */ rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip, DDI_PROP_DONTPASS, "name", &nameprop); if (rv != DDI_PROP_SUCCESS) { cmn_err(CE_NOTE, "?vldc%d has no 'name' property", ddi_get_instance(vldcp->dip)); return (DDI_FAILURE); } D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst); /* * Allocate and initialize a per-instance copy * of the global property spec array that will * uniquely identify this vldc instance. */ templatesz = sizeof (vldc_prop_template); pspecp = kmem_alloc(templatesz, KM_SLEEP); bcopy(vldc_prop_template, pspecp, templatesz); /* copy in the name property */ namesz = strlen(nameprop) + 1; name = kmem_alloc(namesz, KM_SLEEP); bcopy(nameprop, name, namesz); VLDC_SET_MDEG_PROP_NAME(pspecp, name); ddi_prop_free(nameprop); /* copy in the instance property */ VLDC_SET_MDEG_PROP_INST(pspecp, inst); /* initialize the complete prop spec structure */ inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP); inst_specp->namep = "virtual-device"; inst_specp->specp = pspecp; /* perform the registration */ rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb, vldcp, &mdeg_hdl); if (rv != MDEG_SUCCESS) { cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register " "failed, err = %d", rv); kmem_free(name, namesz); kmem_free(pspecp, templatesz); kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); return (DDI_FAILURE); } /* save off data that will be needed later */ vldcp->inst_spec = inst_specp; vldcp->mdeg_hdl = mdeg_hdl; return (DDI_SUCCESS); }
/* close a vldc port */ static int i_vldc_close_port(vldc_t *vldcp, uint_t portno) { vldc_port_t *vport; vldc_minor_t *vminor; int rv = DDI_SUCCESS; vport = &(vldcp->port[portno]); ASSERT(MUTEX_HELD(&vport->minorp->lock)); D1("i_vldc_close_port: vldc@%d:%d: closing port\n", vport->inst, vport->minorp->portno); vminor = vport->minorp; switch (vport->status) { case VLDC_PORT_CLOSED: /* nothing to do */ DWARN("i_vldc_close_port: port %d in an unexpected " "state (%d)\n", portno, vport->status); return (DDI_SUCCESS); case VLDC_PORT_READY: case VLDC_PORT_RESET: do { rv = i_vldc_ldc_close(vport); if (rv != EAGAIN) break; /* * EAGAIN indicates that ldc_close() failed because * ldc callback thread is active for the channel. * cv_timedwait() is used to release vminor->lock and * allow ldc callback thread to complete. * after waking up, check if the port has been closed * by another thread in the meantime. */ (void) cv_reltimedwait(&vminor->cv, &vminor->lock, drv_usectohz(vldc_close_delay), TR_CLOCK_TICK); rv = 0; } while (vport->status != VLDC_PORT_CLOSED); if ((rv != 0) || (vport->status == VLDC_PORT_CLOSED)) return (rv); break; case VLDC_PORT_OPEN: break; default: DWARN("i_vldc_close_port: port %d in an unexpected " "state (%d)\n", portno, vport->status); ASSERT(0); /* fail quickly to help diagnosis */ return (EINVAL); } ASSERT(vport->status == VLDC_PORT_OPEN); /* free memory */ kmem_free(vport->send_buf, vport->mtu); kmem_free(vport->recv_buf, vport->mtu); if (strcmp(vminor->sname, VLDC_HVCTL_SVCNAME) == 0) kmem_free(vport->cookie_buf, vldc_max_cookie); vport->status = VLDC_PORT_CLOSED; return (rv); }
void __dprintf(const char *file, const char *func, int line, const char *fmt, ...) { const char *newfile; va_list adx; size_t size; char *buf; char *nl; if (!zfs_dbgmsg_enable && !(zfs_flags & ZFS_DEBUG_DPRINTF)) return; size = 1024; buf = kmem_alloc(size, KM_SLEEP); /* * Get rid of annoying prefix to filename. */ newfile = strrchr(file, '/'); if (newfile != NULL) { newfile = newfile + 1; /* Get rid of leading / */ } else { newfile = file; } va_start(adx, fmt); (void) vsnprintf(buf, size, fmt, adx); va_end(adx); /* * Get rid of trailing newline. */ nl = strrchr(buf, '\n'); if (nl != NULL) *nl = '\0'; /* * To get this data enable the zfs__dprintf trace point as shown: * * # Enable zfs__dprintf tracepoint, clear the tracepoint ring buffer * $ echo 1 > /sys/module/zfs/parameters/zfs_flags * $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable * $ echo 0 > /sys/kernel/debug/tracing/trace * * # Dump the ring buffer. * $ cat /sys/kernel/debug/tracing/trace */ if (zfs_flags & ZFS_DEBUG_DPRINTF) DTRACE_PROBE4(zfs__dprintf, char *, newfile, char *, func, int, line, char *, buf); /* * To get this data enable the zfs debug log as shown: * * # Set zfs_dbgmsg enable, clear the log buffer * $ echo 1 > /sys/module/zfs/parameters/zfs_dbgmsg_enable * $ echo 0 > /proc/spl/kstat/zfs/dbgmsg * * # Dump the log buffer. * $ cat /proc/spl/kstat/zfs/dbgmsg */ if (zfs_dbgmsg_enable) __zfs_dbgmsg(buf); kmem_free(buf, size); }
void kmem_freepages(void *addr, pgcnt_t npages) { kmem_free(addr, ptob(npages)); }
/* * Remove a multicast entry from the hashtable. * * Search hash table based on address. If match found, scan * list of ports associated with address. If specified port * found remove it from list. */ int vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) { mfdb_ent_t *ment = NULL; mfdb_ent_t *curr_p, *prev_p; void *tgt = NULL; D1(vswp, "%s: enter", __func__); if (devtype == VSW_VNETPORT) { tgt = (vsw_port_t *)arg; D2(vswp, "%s: removing port %d from mFDB for address" " 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance, addr); } else { D2(vswp, "%s: removing entry", __func__); tgt = (void *)vswp; } WRITE_ENTER(&vswp->mfdbrw); if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t *)&ment) != 0) { D2(vswp, "%s: address 0x%llx not in table", __func__, addr); RW_EXIT(&vswp->mfdbrw); return (1); } prev_p = curr_p = ment; while (curr_p != NULL) { if (curr_p->d_addr == (void *)tgt) { if (devtype == VSW_VNETPORT) { D2(vswp, "%s: port %d found", __func__, ((vsw_port_t *)tgt)->p_instance); } else { D2(vswp, "%s: instance found", __func__); } if (prev_p == curr_p) { /* * head of list, if no other element is in * list then destroy this entry, otherwise * just replace it with updated value. */ ment = curr_p->nextp; if (ment == NULL) { (void) mod_hash_destroy(vswp->mfdb, (mod_hash_val_t)addr); } else { (void) mod_hash_replace(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t)ment); } } else { /* * Not head of list, no need to do * replacement, just adjust list pointers. */ prev_p->nextp = curr_p->nextp; } break; } prev_p = curr_p; curr_p = curr_p->nextp; } RW_EXIT(&vswp->mfdbrw); D1(vswp, "%s: exit", __func__); if (curr_p == NULL) return (1); kmem_free(curr_p, sizeof (mfdb_ent_t)); return (0); }
/*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)); }
void * pxa2x0_i2s_allocm(void *hdl, int direction, size_t size) { struct pxa2x0_i2s_softc *sc = hdl; struct pxa2x0_i2s_dma *p; struct dmac_xfer *dx; int error; p = kmem_alloc(sizeof(*p), KM_SLEEP); if (p == NULL) return NULL; dx = pxa2x0_dmac_allocate_xfer(); if (dx == NULL) { goto fail_alloc; } p->dx = dx; p->size = size; if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, p->segs, I2S_N_SEGS, &p->nsegs, BUS_DMA_WAITOK)) != 0) { goto fail_xfer; } if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, size, &p->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) { goto fail_map; } if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK, &p->map)) != 0) { goto fail_create; } if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL, BUS_DMA_WAITOK)) != 0) { goto fail_load; } dx->dx_cookie = sc; dx->dx_priority = DMAC_PRIORITY_NORMAL; dx->dx_dev_width = DMAC_DEV_WIDTH_4; dx->dx_burst_size = DMAC_BURST_SIZE_32; p->next = sc->sc_dmas; sc->sc_dmas = p; return p->addr; fail_load: bus_dmamap_destroy(sc->sc_dmat, p->map); fail_create: bus_dmamem_unmap(sc->sc_dmat, p->addr, size); fail_map: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); fail_xfer: pxa2x0_dmac_free_xfer(dx); fail_alloc: kmem_free(p, sizeof(*p)); return NULL; }
/* * Find all 'allow' permissions from a given point and then continue * traversing up to the root. * * This function constructs an nvlist of nvlists. * each setpoint is an nvlist composed of an nvlist of an nvlist * of the individual * users/groups/everyone/create * permissions. * * The nvlist will look like this. * * { source fsname -> { whokeys { permissions,...}, ...}} * * The fsname nvpairs will be arranged in a bottom up order. For example, * if we have the following structure a/b/c then the nvpairs for the fsnames * will be ordered a/b/c, a/b, a. */ int dsl_deleg_get(const char *ddname, nvlist_t **nvp) { dsl_dir_t *dd, *startdd; dsl_pool_t *dp; int error; objset_t *mos; zap_cursor_t *basezc, *zc; zap_attribute_t *baseza, *za; char *source; error = dsl_dir_open(ddname, FTAG, &startdd, NULL); if (error) return (error); dp = startdd->dd_pool; mos = dp->dp_meta_objset; zc = kmem_alloc(sizeof(zap_cursor_t), KM_SLEEP); za = kmem_alloc(sizeof(zap_attribute_t), KM_SLEEP); basezc = kmem_alloc(sizeof(zap_cursor_t), KM_SLEEP); baseza = kmem_alloc(sizeof(zap_attribute_t), KM_SLEEP); source = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, KM_SLEEP); VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); rw_enter(&dp->dp_config_rwlock, RW_READER); for (dd = startdd; dd != NULL; dd = dd->dd_parent) { nvlist_t *sp_nvp; uint64_t n; if (dd->dd_phys->dd_deleg_zapobj && (zap_count(mos, dd->dd_phys->dd_deleg_zapobj, &n) == 0) && n) { VERIFY(nvlist_alloc(&sp_nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); } else { continue; } for (zap_cursor_init(basezc, mos, dd->dd_phys->dd_deleg_zapobj); zap_cursor_retrieve(basezc, baseza) == 0; zap_cursor_advance(basezc)) { nvlist_t *perms_nvp; ASSERT(baseza->za_integer_length == 8); ASSERT(baseza->za_num_integers == 1); VERIFY(nvlist_alloc(&perms_nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); for (zap_cursor_init(zc, mos, baseza->za_first_integer); zap_cursor_retrieve(zc, za) == 0; zap_cursor_advance(zc)) { VERIFY(nvlist_add_boolean(perms_nvp, za->za_name) == 0); } zap_cursor_fini(zc); VERIFY(nvlist_add_nvlist(sp_nvp, baseza->za_name, perms_nvp) == 0); nvlist_free(perms_nvp); } zap_cursor_fini(basezc); dsl_dir_name(dd, source); VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0); nvlist_free(sp_nvp); } rw_exit(&dp->dp_config_rwlock); kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1); kmem_free(baseza, sizeof(zap_attribute_t)); kmem_free(basezc, sizeof(zap_cursor_t)); kmem_free(za, sizeof(zap_attribute_t)); kmem_free(zc, sizeof(zap_cursor_t)); dsl_dir_close(startdd, FTAG); return (0); }
static void usb_vprintf(dev_info_t *dip, int level, char *label, char *fmt, va_list ap) { size_t len; int instance; char driver_name[USBA_DRVNAME_LEN]; char *msg_ptr; if (usba_suppress_dprintf) { return; } *driver_name = '\0'; mutex_enter(&usba_print_mutex); /* * Check if we have a valid buf size? * Suppress logging to usb_buffer if so. */ if (usba_debug_buf_size <= 0) { usba_buffer_dprintf = 0; } /* * if there is label and dip, use <driver name><instance>: * otherwise just use the label */ if (dip) { instance = ddi_get_instance(dip); (void) snprintf(driver_name, USBA_DRVNAME_LEN, "%s%d", ddi_driver_name(dip), instance); } if (label == (char *)NULL) { len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "\t"); } else if (usba_timestamp_dprintf) { hrtime_t t = gethrtime(); hrtime_t elapsed = (t - usba_last_timestamp)/1000; usba_last_timestamp = t; if (dip) { len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "+%lld->%p: %s%d: ", elapsed, (void *)curthread, label, instance); } else { len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "+%lld->%p: %s: ", elapsed, (void *)curthread, label); } } else { if (dip) { len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "%s%d:\t", label, instance); } else { len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "%s:\t", label); } } msg_ptr = usba_print_buf + len; (void) vsnprintf(msg_ptr, USBA_PRINT_BUF_LEN - len - 2, fmt, ap); len = min(strlen(usba_print_buf), USBA_PRINT_BUF_LEN - 2); usba_print_buf[len++] = '\n'; usba_print_buf[len] = '\0'; /* * stuff the message in the debug buf */ if (usba_buffer_dprintf) { if (usba_debug_buf == NULL) { usba_debug_buf = kmem_alloc( usba_debug_buf_size + USBA_DEBUG_SIZE_EXTRA_ALLOC, KM_SLEEP); usba_clear_dprint_buf(); } else if (usba_clear_debug_buf_flag) { usba_clear_dprint_buf(); usba_clear_debug_buf_flag = 0; } /* * overwrite >>>> that might be over the end of the * the buffer */ *(usba_debug_buf + usba_debug_buf_size) = '\0'; if ((usba_buf_sptr + len) > usba_buf_eptr) { size_t left = _PTRDIFF(usba_buf_eptr, usba_buf_sptr); bcopy(usba_print_buf, usba_buf_sptr, left); bcopy((caddr_t)usba_print_buf + left, usba_debug_buf, len - left); usba_buf_sptr = usba_debug_buf + len - left; } else { bcopy(usba_print_buf, usba_buf_sptr, len); usba_buf_sptr += len; } /* add marker */ (void) sprintf(usba_buf_sptr, ">>>>"); } /* * L4-L2 message may go to the log buf if not logged in usba_debug_buf * L1 messages will go to the log buf in non-debug kernels and * to console and log buf in debug kernels if usba_debug_chatty * has been set * L0 messages are warnings and will go to console and log buf and * include the pathname, if available */ switch (level) { case USB_LOG_L4: case USB_LOG_L3: case USB_LOG_L2: if (!usba_buffer_dprintf) { cmn_err(CE_CONT, "^%s", usba_print_buf); } break; case USB_LOG_L1: if (dip) { char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); if (pathname) { cmn_err(CE_CONT, usba_debug_chatty ? "%s (%s): %s" : "?%s (%s): %s", ddi_pathname(dip, pathname), driver_name, msg_ptr); kmem_free(pathname, MAXPATHLEN); } else { cmn_err(CE_CONT, usba_debug_chatty ? "%s" : "?%s", usba_print_buf); } } else { cmn_err(CE_CONT, usba_debug_chatty ? "%s" : "?%s", usba_print_buf); } break; case USB_LOG_L0: /* Strip the "\n" added earlier */ if (usba_print_buf[len - 1] == '\n') { usba_print_buf[len - 1] = '\0'; } if (msg_ptr[len - 1] == '\n') { msg_ptr[len - 1] = '\0'; } if (dip) { char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); if (pathname) { cmn_err(CE_WARN, "%s (%s): %s", ddi_pathname(dip, pathname), driver_name, msg_ptr); kmem_free(pathname, MAXPATHLEN); } else { cmn_err(CE_WARN, usba_print_buf); } } else { cmn_err(CE_WARN, usba_print_buf); } break; } mutex_exit(&usba_print_mutex); }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp) { struct lwp *l = curlwp; struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; kauth_cred_t cred; dev = devvp->v_rdev; cred = l->l_cred; /* Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; ump = NULL; /* Read the superblock from disk, and swap it directly. */ error = bread(devvp, SBLOCK, SBSIZE, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; m_fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP); e2fs_sbload(fs, &m_fs->e2fs); brelse(bp, 0); bp = NULL; /* Once swapped, validate and fill in the superblock. */ error = ext2fs_sbfill(m_fs, ronly); if (error) { kmem_free(m_fs, sizeof(struct m_ext2fs)); goto out; } m_fs->e2fs_ronly = ronly; ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); ump->um_fstype = UFS1; ump->um_ops = &ext2fs_ufsops; ump->um_e2fs = m_fs; if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* XXX: should be added in ext2fs_sbfill()? */ m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp, EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, 0, &bp); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; } mp->mnt_data = ump; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ mp->mnt_fs_bshift = m_fs->e2fs_bshift; mp->mnt_iflag |= IMNT_DTYPE; ump->um_flags = 0; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = EXT2_NINDIR(m_fs); ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1; ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; ump->um_dirblksiz = m_fs->e2fs_bsize; ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); spec_node_setmountedfs(devvp, mp); return (0); out: if (bp != NULL) brelse(bp, 0); if (ump) { kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs)); kmem_free(ump, sizeof(*ump)); mp->mnt_data = NULL; } return (error); }
/* * usb_create_pm_components: * map descriptor into pm properties */ int usb_create_pm_components(dev_info_t *dip, uint_t *pwr_states) { uchar_t *usb_cfg; /* buf for config descriptor */ usb_cfg_descr_t cfg_descr; size_t cfg_length; usba_cfg_pwr_descr_t confpwr_descr; usba_if_pwr_descr_t ifpwr_descr; uint8_t cfg_attrib; int i, lvl, rval; int n_prop = 0; uint8_t *ptr; char *drvname; char str[USBA_POWER_STR_SIZE]; char *pm_comp[USBA_N_PMCOMP]; USBA_CHECK_CONTEXT(); if (usb_is_pm_enabled(dip) != USB_SUCCESS) { return (USB_FAILURE); } /* Obtain the raw configuration descriptor */ usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); /* get configuration descriptor, must succceed */ rval = usb_parse_cfg_descr(usb_cfg, cfg_length, &cfg_descr, USB_CFG_DESCR_SIZE); ASSERT(rval == USB_CFG_DESCR_SIZE); cfg_attrib = cfg_descr.bmAttributes; *pwr_states = 0; /* * Now start creating the pm-components strings */ drvname = (char *)ddi_driver_name(dip); (void) snprintf(str, USBA_POWER_STR_SIZE, "NAME= %s%d Power", drvname, ddi_get_instance(dip)); pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1, KM_SLEEP); (void) strcpy(pm_comp[n_prop++], str); /* * if the device is bus powered we look at the bBusPowerSavingDx * fields else we look at bSelfPowerSavingDx fields. * OS and USB power states are numerically reversed, * * Here is the mapping :- * OS State USB State * 0 D3 (minimal or no power) * 1 D2 * 2 D1 * 3 D0 (Full power) * * if we own the whole device, we look at the config pwr descr * else at the interface pwr descr. */ if (usb_owns_device(dip)) { /* Parse the configuration power descriptor */ rval = usba_parse_cfg_pwr_descr(usb_cfg, cfg_length, &confpwr_descr, USBA_CFG_PWR_DESCR_SIZE); if (rval != USBA_CFG_PWR_DESCR_SIZE) { USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, "usb_create_pm_components: " "usb_parse_cfg_pwr_descr returns length of %d, " "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE); return (USB_FAILURE); } if (cfg_attrib & USB_CFG_ATTR_SELFPWR) { ptr = &confpwr_descr.bSelfPowerSavingD3; } else { ptr = &confpwr_descr.bBusPowerSavingD3; } } else { /* Parse the interface power descriptor */ rval = usba_parse_if_pwr_descr(usb_cfg, cfg_length, usba_get_ifno(dip), /* interface index */ 0, /* XXXX alt interface index */ &ifpwr_descr, USBA_IF_PWR_DESCR_SIZE); if (rval != USBA_IF_PWR_DESCR_SIZE) { USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, "usb_create_pm_components: " "usb_parse_if_pwr_descr " "returns length of %d, " "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE); return (USB_FAILURE); } if (cfg_attrib & USB_CFG_ATTR_SELFPWR) { ptr = &ifpwr_descr.bSelfPowerSavingD3; } else { ptr = &ifpwr_descr.bBusPowerSavingD3; } } /* walk thru levels and create prop level=name strings */ for (lvl = USB_DEV_OS_PWR_0; lvl <= USB_DEV_OS_PWR_3; lvl++) { if (*ptr || (lvl == USB_DEV_OS_PWR_3)) { (void) snprintf(str, USBA_POWER_STR_SIZE, "%d=USB D%d State", lvl, USB_DEV_OS_PWR2USB_PWR(lvl)); pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1, KM_SLEEP); (void) strcpy(pm_comp[n_prop++], str); *pwr_states |= USB_DEV_PWRMASK(lvl); } ptr -= 2; /* skip to the next power state */ } USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, "usb_create_pm_components: pwr_states: %x", *pwr_states); /* now create the actual components */ rval = ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, "pm-components", pm_comp, n_prop); if (rval == DDI_PROP_SUCCESS) { rval = USB_SUCCESS; } else { rval = USB_FAILURE; } /* display & delete properties */ USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, "usb_create_pm_components: The properties are:"); for (i = 0; i < n_prop; i++) { USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, "\t%s", pm_comp[i]); kmem_free(pm_comp[i], strlen(pm_comp[i]) + 1); } return (rval); }
/* * smb_query_by_path * * Common code for querying file information by file name. * Use the file name to identify the node object and request the * smb_queryinfo_t data for that node. * * Querying attributes on a named pipe by name is an error and * is handled in the calling functions so that they can return * the appropriate error status code (which differs by caller). */ static int smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev, char *path) { smb_queryinfo_t *qinfo; smb_node_t *node, *dnode; int rc; int len; /* VALID, but not yet supported */ if (infolev == SMB_FILE_ACCESS_INFORMATION) { smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); return (-1); } /* * Some MS clients pass NULL file names. NT interprets this as "\". * Otherwise, if path is not "\\", remove the terminating slash. */ if ((len = strlen(path)) == 0) path = "\\"; else { if ((len > 1) && (path[len - 1] == '\\')) { path[len - 1] = 0; } } qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); rc = smb_pathname_reduce(sr, sr->user_cr, path, sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, qinfo->qi_name); if (rc == 0) { rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node); smb_node_release(dnode); } if (rc != 0) { if (rc == ENOENT) smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERROR_FILE_NOT_FOUND); else smbsr_errno(sr, rc); kmem_free(qinfo, sizeof (smb_queryinfo_t)); return (-1); } rc = smb_query_fileinfo(sr, node, infolev, qinfo); if (rc != 0) { kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (rc); } /* If delete_on_close - NT_STATUS_DELETE_PENDING */ if (qinfo->qi_delete_on_close) { smbsr_error(sr, NT_STATUS_DELETE_PENDING, ERRDOS, ERROR_ACCESS_DENIED); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (-1); } rc = smb_query_encode_response(sr, xa, infolev, qinfo); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (rc); }
/* * port_associate_fd() * This function associates new file descriptors with a port or * reactivate already associated file descriptors. * The reactivation also updates the events types to be checked and the * attached user pointer. * Per port a cache is used to store associated file descriptors. * Internally the VOP_POLL interface is used to poll for existing events. * The VOP_POLL interface can also deliver a pointer to a pollhead_t structure * which is used to enqueue polldat_t structures with pending events. * If VOP_POLL immediately returns valid events (revents) then those events * will be submitted to the event port with port_send_event(). * Otherwise VOP_POLL does not return events but it delivers a pointer to a * pollhead_t structure. In such a case the corresponding file system behind * VOP_POLL will use the pollwakeup() function to notify about exisiting * events. */ int port_associate_fd(port_t *pp, int source, uintptr_t object, int events, void *user) { port_fdcache_t *pcp; int fd; struct pollhead *php = NULL; portfd_t *pfd; polldat_t *pdp; file_t *fp; port_kevent_t *pkevp; short revents; int error = 0; pcp = pp->port_queue.portq_pcp; if (object > (uintptr_t)INT_MAX) return (EBADFD); fd = object; if ((fp = getf(fd)) == NULL) return (EBADFD); mutex_enter(&pcp->pc_lock); if (pcp->pc_hash == NULL) { /* * This is the first time that a fd is being associated with * the current port: * - create PORT_SOURCE_FD cache * - associate PORT_SOURCE_FD source with the port */ error = port_associate_ksource(pp->port_fd, PORT_SOURCE_FD, NULL, port_close_sourcefd, pp, NULL); if (error) { mutex_exit(&pcp->pc_lock); releasef(fd); return (error); } /* create polldat cache */ pcp->pc_hashsize = PORTHASH_START; pcp->pc_hash = kmem_zalloc(pcp->pc_hashsize * sizeof (portfd_t *), KM_SLEEP); pfd = NULL; } else { /* Check if the fd/fp is already associated with the port */ pfd = port_cache_lookup_fp(pcp, fd, fp); } if (pfd == NULL) { /* * new entry * Allocate a polldat_t structure per fd * The use of the polldat_t structure to cache file descriptors * is required to be able to share the pollwakeup() function * with poll(2) and devpoll(7d). */ pfd = kmem_zalloc(sizeof (portfd_t), KM_SLEEP); pdp = PFTOD(pfd); pdp->pd_fd = fd; pdp->pd_fp = fp; pdp->pd_pcache = (void *)pcp; /* Allocate a port event structure per fd */ error = port_alloc_event_local(pp, source, PORT_ALLOC_CACHED, &pdp->pd_portev); if (error) { kmem_free(pfd, sizeof (portfd_t)); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } pkevp = pdp->pd_portev; pkevp->portkev_callback = port_fd_callback; pkevp->portkev_arg = pfd; /* add portfd_t entry to the cache */ port_cache_insert_fd(pcp, pdp); pkevp->portkev_object = fd; pkevp->portkev_user = user; /* * Add current port to the file descriptor interested list * The members of the list are notified when the file descriptor * is closed. */ addfd_port(fd, pfd); } else { /* * The file descriptor is already associated with the port */ pdp = PFTOD(pfd); pkevp = pdp->pd_portev; /* * Check if the re-association happens before the last * submitted event of the file descriptor was retrieved. * Clear the PORT_KEV_VALID flag if set. No new events * should get submitted after this flag is cleared. */ mutex_enter(&pkevp->portkev_lock); if (pkevp->portkev_flags & PORT_KEV_VALID) { pkevp->portkev_flags &= ~PORT_KEV_VALID; } if (pkevp->portkev_flags & PORT_KEV_DONEQ) { mutex_exit(&pkevp->portkev_lock); /* * Remove any events that where already fired * for this fd and are still in the port queue. */ port_remove_done_event(pkevp); } else { mutex_exit(&pkevp->portkev_lock); } pkevp->portkev_user = user; } mutex_enter(&pkevp->portkev_lock); pkevp->portkev_events = 0; /* no fired events */ pdp->pd_events = events; /* events associated */ /* * allow new events. */ pkevp->portkev_flags |= PORT_KEV_VALID; mutex_exit(&pkevp->portkev_lock); /* * do VOP_POLL and cache this poll fd. * * XXX - pollrelock() logic needs to know * which pollcache lock to grab. It'd be a * cleaner solution if we could pass pcp as * an arguement in VOP_POLL interface instead * of implicitly passing it using thread_t * struct. On the other hand, changing VOP_POLL * interface will require all driver/file system * poll routine to change. */ curthread->t_pollcache = (pollcache_t *)pcp; error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php); curthread->t_pollcache = NULL; /* * To keep synchronization between VOP_POLL above and * pollhead_insert below, it is necessary to * call VOP_POLL() again (see port_bind_pollhead()). */ if (error) { /* dissociate the fd from the port */ delfd_port(fd, pfd); port_remove_fd_local(pfd, pcp); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } if (php != NULL) { /* * No events delivered yet. * Bind pollhead pointer with current polldat_t structure. * Sub-system will call pollwakeup() later with php as * argument. */ error = port_bind_pollhead(&php, pdp, &revents); if (error) { delfd_port(fd, pfd); port_remove_fd_local(pfd, pcp); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } } /* * Check if new events where detected and no events have been * delivered. The revents was already set after the VOP_POLL * above or it was updated in port_bind_pollhead(). */ mutex_enter(&pkevp->portkev_lock); if (revents && (pkevp->portkev_flags & PORT_KEV_VALID)) { ASSERT((pkevp->portkev_flags & PORT_KEV_DONEQ) == 0); pkevp->portkev_flags &= ~PORT_KEV_VALID; revents = revents & (pdp->pd_events | POLLHUP | POLLERR); /* send events to the event port */ pkevp->portkev_events = revents; /* * port_send_event will release the portkev_lock mutex. */ port_send_event(pkevp); } else { mutex_exit(&pkevp->portkev_lock); } releasef(fd); mutex_exit(&pcp->pc_lock); return (error); }
int dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, objset_t **osp) { objset_t *os; int i, err; ASSERT(ds == NULL || MUTEX_HELD(&ds->ds_opening_lock)); os = kmem_zalloc(sizeof (objset_t), KM_SLEEP); os->os_dsl_dataset = ds; os->os_spa = spa; os->os_rootbp = bp; if (!BP_IS_HOLE(os->os_rootbp)) { uint32_t aflags = ARC_WAIT; zbookmark_t zb; SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET, ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID); if (DMU_OS_IS_L2CACHEABLE(os)) aflags |= ARC_L2CACHE; dprintf_bp(os->os_rootbp, "reading %s", ""); /* * XXX when bprewrite scrub can change the bp, * and this is called from dmu_objset_open_ds_os, the bp * could change, and we'll need a lock. */ err = dsl_read_nolock(NULL, spa, os->os_rootbp, arc_getbuf_func, &os->os_phys_buf, ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb); if (err) { kmem_free(os, sizeof (objset_t)); /* convert checksum errors into IO errors */ if (err == ECKSUM) err = EIO; return (err); } /* Increase the blocksize if we are permitted. */ if (spa_version(spa) >= SPA_VERSION_USERSPACE && arc_buf_size(os->os_phys_buf) < sizeof (objset_phys_t)) { arc_buf_t *buf = arc_buf_alloc(spa, sizeof (objset_phys_t), &os->os_phys_buf, ARC_BUFC_METADATA); bzero(buf->b_data, sizeof (objset_phys_t)); bcopy(os->os_phys_buf->b_data, buf->b_data, arc_buf_size(os->os_phys_buf)); (void) arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf); os->os_phys_buf = buf; } os->os_phys = os->os_phys_buf->b_data; os->os_flags = os->os_phys->os_flags; } else { int size = spa_version(spa) >= SPA_VERSION_USERSPACE ? sizeof (objset_phys_t) : OBJSET_OLD_PHYS_SIZE; os->os_phys_buf = arc_buf_alloc(spa, size, &os->os_phys_buf, ARC_BUFC_METADATA); os->os_phys = os->os_phys_buf->b_data; bzero(os->os_phys, size); } /* * Note: the changed_cb will be called once before the register * func returns, thus changing the checksum/compression from the * default (fletcher2/off). Snapshots don't need to know about * checksum/compression/copies. */ if (ds) { err = dsl_prop_register(ds, "primarycache", primary_cache_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "secondarycache", secondary_cache_changed_cb, os); if (!dsl_dataset_is_snapshot(ds)) { if (err == 0) err = dsl_prop_register(ds, "checksum", checksum_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "compression", compression_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "copies", copies_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "dedup", dedup_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "logbias", logbias_changed_cb, os); if (err == 0) err = dsl_prop_register(ds, "sync", sync_changed_cb, os); } if (err) { VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf) == 1); kmem_free(os, sizeof (objset_t)); return (err); } } else if (ds == NULL) { /* It's the meta-objset. */ os->os_checksum = ZIO_CHECKSUM_FLETCHER_4; os->os_compress = ZIO_COMPRESS_LZJB; os->os_copies = spa_max_replication(spa); os->os_dedup_checksum = ZIO_CHECKSUM_OFF; os->os_dedup_verify = 0; os->os_logbias = 0; os->os_sync = 0; os->os_primary_cache = ZFS_CACHE_ALL; os->os_secondary_cache = ZFS_CACHE_ALL; } if (ds == NULL || !dsl_dataset_is_snapshot(ds)) os->os_zil_header = os->os_phys->os_zil_header; os->os_zil = zil_alloc(os, &os->os_zil_header); for (i = 0; i < TXG_SIZE; i++) { list_create(&os->os_dirty_dnodes[i], sizeof (dnode_t), offsetof(dnode_t, dn_dirty_link[i])); list_create(&os->os_free_dnodes[i], sizeof (dnode_t), offsetof(dnode_t, dn_dirty_link[i])); } list_create(&os->os_dnodes, sizeof (dnode_t), offsetof(dnode_t, dn_link)); list_create(&os->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), offsetof(dmu_buf_impl_t, db_link)); mutex_init(&os->os_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&os->os_obj_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&os->os_user_ptr_lock, NULL, MUTEX_DEFAULT, NULL); DMU_META_DNODE(os) = dnode_special_open(os, &os->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT, &os->os_meta_dnode); if (arc_buf_size(os->os_phys_buf) >= sizeof (objset_phys_t)) { DMU_USERUSED_DNODE(os) = dnode_special_open(os, &os->os_phys->os_userused_dnode, DMU_USERUSED_OBJECT, &os->os_userused_dnode); DMU_GROUPUSED_DNODE(os) = dnode_special_open(os, &os->os_phys->os_groupused_dnode, DMU_GROUPUSED_OBJECT, &os->os_groupused_dnode); } /* * We should be the only thread trying to do this because we * have ds_opening_lock */ if (ds) { mutex_enter(&ds->ds_lock); ASSERT(ds->ds_objset == NULL); ds->ds_objset = os; mutex_exit(&ds->ds_lock); } *osp = os; return (0); }
/*ARGSUSED*/ int dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) { uint64_t size; uint64_t dumpsize_in_pages; int error = 0; char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); vnode_t *vp; switch (cmd) { case DIOCGETDUMPSIZE: if (dump_conflags & DUMP_ALL) size = ptob((uint64_t)physmem) / DUMP_COMPRESS_RATIO; else { /* * We can't give a good answer for the DUMP_CURPROC * because we won't know which process to use until it * causes a panic. We'll therefore punt and give the * caller the size for the kernel. * * This kernel size equation takes care of the * boot time kernel footprint and also accounts * for availrmem changes due to user explicit locking. * Refer to common/vm/vm_page.c for an explanation * of these counters. */ dumpsize_in_pages = (physinstalled - obp_pages - availrmem - anon_segkp_pages_locked - k_anoninfo.ani_mem_resv - pages_locked - pages_claimed - pages_useclaim); /* * Protect against vm vagaries. */ if (dumpsize_in_pages > (uint64_t)physmem) dumpsize_in_pages = (uint64_t)physmem; size = ptob(dumpsize_in_pages) / DUMP_COMPRESS_RATIO; } if (copyout(&size, (void *)arg, sizeof (size)) < 0) error = EFAULT; break; case DIOCGETCONF: mutex_enter(&dump_lock); *rvalp = dump_conflags; if (dumpvp && !(dumpvp->v_flag & VISSWAP)) *rvalp |= DUMP_EXCL; mutex_exit(&dump_lock); break; case DIOCSETCONF: mutex_enter(&dump_lock); if (arg == DUMP_KERNEL || arg == DUMP_ALL || arg == DUMP_CURPROC) dump_conflags = arg; else error = EINVAL; mutex_exit(&dump_lock); break; case DIOCGETDEV: mutex_enter(&dump_lock); if (dumppath == NULL) { mutex_exit(&dump_lock); error = ENODEV; break; } (void) strcpy(pathbuf, dumppath); mutex_exit(&dump_lock); error = copyoutstr(pathbuf, (void *)arg, MAXPATHLEN, NULL); break; case DIOCSETDEV: case DIOCTRYDEV: if ((error = copyinstr((char *)arg, pathbuf, MAXPATHLEN, NULL)) != 0 || (error = lookupname(pathbuf, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) break; mutex_enter(&dump_lock); if (vp->v_type == VBLK) error = dumpinit(vp, pathbuf, cmd == DIOCTRYDEV); else error = ENOTBLK; mutex_exit(&dump_lock); VN_RELE(vp); break; case DIOCDUMP: mutex_enter(&dump_lock); if (dumpvp == NULL) error = ENODEV; else if (dumpvp->v_flag & VISSWAP) error = EBUSY; else dumpsys(); mutex_exit(&dump_lock); break; default: error = ENXIO; } kmem_free(pathbuf, MAXPATHLEN); return (error); }
STATIC int linvfs_fill_super( struct super_block *sb, void *data, int silent) { vnode_t *rootvp; struct vfs *vfsp = vfs_allocate(); struct xfs_mount_args *args = xfs_args_allocate(sb); struct kstatfs statvfs; int error; vfsp->vfs_super = sb; LINVFS_SET_VFS(sb, vfsp); if (sb->s_flags & MS_RDONLY) vfsp->vfs_flag |= VFS_RDONLY; bhv_insert_all_vfsops(vfsp); VFS_PARSEARGS(vfsp, (char *)data, args, 0, error); if (error) { bhv_remove_all_vfsops(vfsp, 1); goto fail_vfsop; } sb_min_blocksize(sb, BBSIZE); sb->s_export_op = &linvfs_export_ops; sb->s_qcop = &linvfs_qops; sb->s_op = &linvfs_sops; VFS_MOUNT(vfsp, args, NULL, error); if (error) { bhv_remove_all_vfsops(vfsp, 1); goto fail_vfsop; } VFS_STATVFS(vfsp, &statvfs, NULL, error); if (error) goto fail_unmount; sb->s_dirt = 1; sb->s_magic = statvfs.f_type; sb->s_blocksize = statvfs.f_bsize; sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); set_posix_acl_flag(sb); VFS_ROOT(vfsp, &rootvp, error); if (error) goto fail_unmount; sb->s_root = d_alloc_root(LINVFS_GET_IP(rootvp)); if (!sb->s_root) goto fail_vnrele; if (is_bad_inode(sb->s_root->d_inode)) goto fail_vnrele; if (linvfs_start_syncd(vfsp)) goto fail_vnrele; vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address); kmem_free(args, sizeof(*args)); return 0; fail_vnrele: if (sb->s_root) { dput(sb->s_root); sb->s_root = NULL; } else { VN_RELE(rootvp); } fail_unmount: VFS_UNMOUNT(vfsp, 0, NULL, error); fail_vfsop: vfs_deallocate(vfsp); kmem_free(args, sizeof(*args)); return -error; }
/* * Synchronize pool configuration to disk. This must be called with the * namespace lock held. */ void spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent) { spa_config_dirent_t *dp, *tdp; nvlist_t *nvl; ASSERT(MUTEX_HELD(&spa_namespace_lock)); if (rootdir == NULL || !(spa_mode_global & FWRITE)) return; /* * Iterate over all cachefiles for the pool, past or present. When the * cachefile is changed, the new one is pushed onto this list, allowing * us to update previous cachefiles that no longer contain this pool. */ for (dp = list_head(&target->spa_config_list); dp != NULL; dp = list_next(&target->spa_config_list, dp)) { spa_t *spa = NULL; if (dp->scd_path == NULL) continue; /* * Iterate over all pools, adding any matching pools to 'nvl'. */ nvl = NULL; while ((spa = spa_next(spa)) != NULL) { if (spa == target && removing) continue; mutex_enter(&spa->spa_props_lock); tdp = list_head(&spa->spa_config_list); if (spa->spa_config == NULL || tdp->scd_path == NULL || strcmp(tdp->scd_path, dp->scd_path) != 0) { mutex_exit(&spa->spa_props_lock); continue; } if (nvl == NULL) VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); VERIFY(nvlist_add_nvlist(nvl, spa->spa_name, spa->spa_config) == 0); mutex_exit(&spa->spa_props_lock); } spa_config_write(dp, nvl); nvlist_free(nvl); } /* * Remove any config entries older than the current one. */ dp = list_head(&target->spa_config_list); while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) { list_remove(&target->spa_config_list, tdp); if (tdp->scd_path != NULL) spa_strfree(tdp->scd_path); kmem_free(tdp, sizeof (spa_config_dirent_t)); } spa_config_generation++; if (postsysevent) spa_event_notify(target, NULL, ESC_ZFS_CONFIG_SYNC); }
int prusrio(proc_t *p, enum uio_rw rw, struct uio *uiop, int old) { /* longlong-aligned short buffer */ longlong_t buffer[STACK_BUF_SIZE / sizeof (longlong_t)]; int error = 0; void *bp; int allocated; ssize_t total = uiop->uio_resid; uintptr_t addr; size_t len; /* for short reads/writes, use the on-stack buffer */ if (uiop->uio_resid <= STACK_BUF_SIZE) { bp = buffer; allocated = 0; } else { bp = kmem_alloc(PAGESIZE, KM_SLEEP); allocated = 1; } #if defined(__sparc) if (p == curproc) (void) flush_user_windows_to_stack(NULL); #endif switch (rw) { case UIO_READ: while (uiop->uio_resid != 0) { addr = uiop->uio_offset; len = MIN(uiop->uio_resid, PAGESIZE - (addr & PAGEOFFSET)); if ((error = uread(p, bp, len, addr)) != 0 || (error = uiomove(bp, len, UIO_READ, uiop)) != 0) break; } /* * ENXIO indicates that a page didn't exist. If the I/O was * truncated, return success; otherwise convert the error into * EIO. When obeying new /proc semantics, we don't return an * error for a read that begins at an invalid address. */ if (error == ENXIO) { if (total != uiop->uio_resid || !old) error = 0; else error = EIO; } break; case UIO_WRITE: while (uiop->uio_resid != 0) { addr = uiop->uio_offset; len = MIN(uiop->uio_resid, PAGESIZE - (addr & PAGEOFFSET)); if ((error = uiomove(bp, len, UIO_WRITE, uiop)) != 0) break; if ((error = uwrite(p, bp, len, addr)) != 0) { uiop->uio_resid += len; uiop->uio_loffset -= len; break; } } /* * ENXIO indicates that a page didn't exist. If the I/O was * truncated, return success; otherwise convert the error * into EIO. */ if (error == ENXIO) { if (total != uiop->uio_resid) error = 0; else error = EIO; } break; default: panic("prusrio: rw=%d neither UIO_READ not UIO_WRITE", rw); /*NOTREACHED*/ } if (allocated) kmem_free(bp, PAGESIZE); return (error); }
/* * Called when the module is first loaded, this routine loads the configuration * file into the SPA namespace. It does not actually open or load the pools; it * only populates the namespace. */ void spa_config_load(void) { void *buf = NULL; nvlist_t *nvlist, *child; nvpair_t *nvpair; spa_t *spa; char *pathname; struct _buf *file; uint64_t fsize; /* * Open the configuration file. */ pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); (void) snprintf(pathname, MAXPATHLEN, "%s%s", (rootdir != NULL) ? "./" : "", spa_config_path); file = kobj_open_file(pathname); kmem_free(pathname, MAXPATHLEN); if (file == (struct _buf *)-1) return; if (kobj_get_filesize(file, &fsize) != 0) goto out; buf = kmem_alloc(fsize, KM_SLEEP); /* * Read the nvlist from the file. */ if (kobj_read_file(file, buf, fsize, 0) < 0) goto out; /* * Unpack the nvlist. */ if (nvlist_unpack(buf, fsize, &nvlist, KM_SLEEP) != 0) goto out; /* * Iterate over all elements in the nvlist, creating a new spa_t for * each one with the specified configuration. */ mutex_enter(&spa_namespace_lock); nvpair = NULL; while ((nvpair = nvlist_next_nvpair(nvlist, nvpair)) != NULL) { if (nvpair_type(nvpair) != DATA_TYPE_NVLIST) continue; VERIFY(nvpair_value_nvlist(nvpair, &child) == 0); if (spa_lookup(nvpair_name(nvpair)) != NULL) continue; spa = spa_add(nvpair_name(nvpair), NULL); /* * We blindly duplicate the configuration here. If it's * invalid, we will catch it when the pool is first opened. */ VERIFY(nvlist_dup(child, &spa->spa_config, 0) == 0); } mutex_exit(&spa_namespace_lock); nvlist_free(nvlist); out: if (buf != NULL) kmem_free(buf, fsize); kobj_close_file(file); }
/* * Syssgi interface for swapext */ int xfs_swapext( xfs_swapext_t __user *sxu) { xfs_swapext_t *sxp; xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; xfs_trans_t *tp; xfs_mount_t *mp; xfs_bstat_t *sbp; struct file *fp = NULL, *tfp = NULL; vnode_t *vp, *tvp; static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; int ilf_fields, tilf_fields; int error = 0; xfs_ifork_t *tempifp, *ifp, *tifp; __uint64_t tmp; int aforkblks = 0; int taforkblks = 0; char locked = 0; sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); if (!sxp || !tempifp) { error = XFS_ERROR(ENOMEM); goto error0; } if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) { error = XFS_ERROR(EFAULT); goto error0; } /* Pull information for the target fd */ if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) || ((vp = vn_from_inode(fp->f_dentry->d_inode)) == NULL)) { error = XFS_ERROR(EINVAL); goto error0; } ip = xfs_vtoi(vp); if (ip == NULL) { error = XFS_ERROR(EBADF); goto error0; } if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) || ((tvp = vn_from_inode(tfp->f_dentry->d_inode)) == NULL)) { error = XFS_ERROR(EINVAL); goto error0; } tip = xfs_vtoi(tvp); if (tip == NULL) { error = XFS_ERROR(EBADF); goto error0; } if (ip->i_mount != tip->i_mount) { error = XFS_ERROR(EINVAL); goto error0; } if (ip->i_ino == tip->i_ino) { error = XFS_ERROR(EINVAL); goto error0; } mp = ip->i_mount; sbp = &sxp->sx_stat; if (XFS_FORCED_SHUTDOWN(mp)) { error = XFS_ERROR(EIO); goto error0; } locked = 1; /* Lock in i_ino order */ if (ip->i_ino < tip->i_ino) { ips[0] = ip; ips[1] = tip; } else { ips[0] = tip; ips[1] = ip; } xfs_lock_inodes(ips, 2, 0, lock_flags); /* Check permissions */ error = xfs_iaccess(ip, S_IWUSR, NULL); if (error) goto error0; error = xfs_iaccess(tip, S_IWUSR, NULL); if (error) goto error0; /* Verify that both files have the same format */ if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { error = XFS_ERROR(EINVAL); goto error0; } /* Verify both files are either real-time or non-realtime */ if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { error = XFS_ERROR(EINVAL); goto error0; } /* Should never get a local format */ if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL || tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) { error = XFS_ERROR(EINVAL); goto error0; } if (VN_CACHED(tvp) != 0) { xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED); } /* Verify O_DIRECT for ftmp */ if (VN_CACHED(tvp) != 0) { error = XFS_ERROR(EINVAL); goto error0; } /* Verify all data are being swapped */ if (sxp->sx_offset != 0 || sxp->sx_length != ip->i_d.di_size || sxp->sx_length != tip->i_d.di_size) { error = XFS_ERROR(EFAULT); goto error0; } /* * If the target has extended attributes, the tmp file * must also in order to ensure the correct data fork * format. */ if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) { error = XFS_ERROR(EINVAL); goto error0; } /* * Compare the current change & modify times with that * passed in. If they differ, we abort this swap. * This is the mechanism used to ensure the calling * process that the file was not changed out from * under it. */ if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) || (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) || (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) || (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) { error = XFS_ERROR(EBUSY); goto error0; } /* We need to fail if the file is memory mapped. Once we have tossed * all existing pages, the page fault will have no option * but to go to the filesystem for pages. By making the page fault call * VOP_READ (or write in the case of autogrow) they block on the iolock * until we have switched the extents. */ if (VN_MAPPED(vp)) { error = XFS_ERROR(EBUSY); goto error0; } xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(tip, XFS_ILOCK_EXCL); /* * There is a race condition here since we gave up the * ilock. However, the data fork will not change since * we have the iolock (locked for truncation too) so we * are safe. We don't really care if non-io related * fields change. */ VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); if ((error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0))) { xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(tip, XFS_IOLOCK_EXCL); xfs_trans_cancel(tp, 0); locked = 0; goto error0; } xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); /* * Count the number of extended attribute blocks */ if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) && (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks); if (error) { xfs_trans_cancel(tp, 0); goto error0; } } if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, &taforkblks); if (error) { xfs_trans_cancel(tp, 0); goto error0; } } /* * Swap the data forks of the inodes */ ifp = &ip->i_df; tifp = &tip->i_df; *tempifp = *ifp; /* struct copy */ *ifp = *tifp; /* struct copy */ *tifp = *tempifp; /* struct copy */ /* * Fix the on-disk inode values */ tmp = (__uint64_t)ip->i_d.di_nblocks; ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks; tip->i_d.di_nblocks = tmp + taforkblks - aforkblks; tmp = (__uint64_t) ip->i_d.di_nextents; ip->i_d.di_nextents = tip->i_d.di_nextents; tip->i_d.di_nextents = tmp; tmp = (__uint64_t) ip->i_d.di_format; ip->i_d.di_format = tip->i_d.di_format; tip->i_d.di_format = tmp; ilf_fields = XFS_ILOG_CORE; switch(ip->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: /* If the extents fit in the inode, fix the * pointer. Otherwise it's already NULL or * pointing to the extent. */ if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) { ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; } ilf_fields |= XFS_ILOG_DEXT; break; case XFS_DINODE_FMT_BTREE: ilf_fields |= XFS_ILOG_DBROOT; break; } tilf_fields = XFS_ILOG_CORE; switch(tip->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: /* If the extents fit in the inode, fix the * pointer. Otherwise it's already NULL or * pointing to the extent. */ if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) { tifp->if_u1.if_extents = tifp->if_u2.if_inline_ext; } tilf_fields |= XFS_ILOG_DEXT; break; case XFS_DINODE_FMT_BTREE: tilf_fields |= XFS_ILOG_DBROOT; break; } /* * Increment vnode ref counts since xfs_trans_commit & * xfs_trans_cancel will both unlock the inodes and * decrement the associated ref counts. */ VN_HOLD(vp); VN_HOLD(tvp); xfs_trans_ijoin(tp, ip, lock_flags); xfs_trans_ijoin(tp, tip, lock_flags); xfs_trans_log_inode(tp, ip, ilf_fields); xfs_trans_log_inode(tp, tip, tilf_fields); /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) { xfs_trans_set_sync(tp); } error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL); locked = 0; error0: if (locked) { xfs_iunlock(ip, lock_flags); xfs_iunlock(tip, lock_flags); } if (fp != NULL) fput(fp); if (tfp != NULL) fput(tfp); if (sxp != NULL) kmem_free(sxp, sizeof(xfs_swapext_t)); if (tempifp != NULL) kmem_free(tempifp, sizeof(xfs_ifork_t)); return error; }
/* * Add or remove multicast address(es). * * Returns 0 on success, 1 on failure. */ int vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port) { mcst_addr_t *mcst_p = NULL; vsw_t *vswp = port->p_vswp; uint64_t addr = 0x0; int i; D1(vswp, "%s: enter", __func__); D2(vswp, "%s: %d addresses", __func__, mcst_pkt->count); for (i = 0; i < mcst_pkt->count; i++) { /* * Convert address into form that can be used * as hash table key. */ KEY_HASH(addr, &(mcst_pkt->mca[i])); /* * Add or delete the specified address/port combination. */ if (mcst_pkt->set == 0x1) { D3(vswp, "%s: adding multicast address 0x%llx for " "port %ld", __func__, addr, port->p_instance); if (vsw_add_mcst(vswp, VSW_VNETPORT, addr, port) == 0) { /* * Update the list of multicast * addresses contained within the * port structure to include this new * one. */ mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); if (mcst_p == NULL) { DERR(vswp, "%s: unable to alloc mem", __func__); (void) vsw_del_mcst(vswp, VSW_VNETPORT, addr, port); return (1); } mcst_p->nextp = NULL; mcst_p->addr = addr; ether_copy(&mcst_pkt->mca[i], &mcst_p->mca); /* * Program the address into HW. If the addr * has already been programmed then the MAC * just increments a ref counter (which is * used when the address is being deleted) */ if (vsw_mac_multicast_add(vswp, port, mcst_p, VSW_VNETPORT)) { (void) vsw_del_mcst(vswp, VSW_VNETPORT, addr, port); kmem_free(mcst_p, sizeof (*mcst_p)); return (1); } mutex_enter(&port->mca_lock); mcst_p->nextp = port->mcap; port->mcap = mcst_p; mutex_exit(&port->mca_lock); } else { DERR(vswp, "%s: error adding multicast " "address 0x%llx for port %ld", __func__, addr, port->p_instance); return (1); } } else { /* * Delete an entry from the multicast hash * table and update the address list * appropriately. */ if (vsw_del_mcst(vswp, VSW_VNETPORT, addr, port) == 0) { D3(vswp, "%s: deleting multicast address " "0x%llx for port %ld", __func__, addr, port->p_instance); mcst_p = vsw_del_addr(VSW_VNETPORT, port, addr); ASSERT(mcst_p != NULL); /* * Remove the address from HW. The address * will actually only be removed once the ref * count within the MAC layer has dropped to * zero. I.e. we can safely call this fn even * if other ports are interested in this * address. */ vsw_mac_multicast_remove(vswp, port, mcst_p, VSW_VNETPORT); kmem_free(mcst_p, sizeof (*mcst_p)); } else { DERR(vswp, "%s: error deleting multicast " "addr 0x%llx for port %ld", __func__, addr, port->p_instance); return (1); } } } D1(vswp, "%s: exit", __func__); return (0); }