/*
 * 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);
}
Exemplo n.º 2
0
/*
 * 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);
}
Exemplo n.º 3
0
/*
 * 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);
	}
}
Exemplo n.º 5
0
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));
}
Exemplo n.º 6
0
/*
 * 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);
}
Exemplo n.º 7
0
/**
 * 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;
}
Exemplo n.º 8
0
void
crgrprele(credgrp_t *grps)
{
	if (atomic_add_32_nv(&grps->crg_ref, -1) == 0)
		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
}
Exemplo n.º 9
0
/*
 * 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);
}
Exemplo n.º 10
0
/* 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);
}
Exemplo n.º 11
0
/* 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);
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
void
kmem_freepages(void *addr, pgcnt_t npages)
{
	kmem_free(addr, ptob(npages));
}
Exemplo n.º 14
0
/*
 * 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);
}
Exemplo n.º 15
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));
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
/*
 * 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);
}
Exemplo n.º 18
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);
}
Exemplo n.º 20
0
/*
 * 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);
}
Exemplo n.º 22
0
/*
 * 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);
}
Exemplo n.º 23
0
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);
}
Exemplo n.º 24
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);
}
Exemplo n.º 25
0
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;
}
Exemplo n.º 26
0
/*
 * 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);
}
Exemplo n.º 27
0
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);
}
Exemplo n.º 28
0
/*
 * 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);
}
Exemplo n.º 29
0
/*
 * 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;
}
Exemplo n.º 30
0
/*
 * 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);
}