Beispiel #1
0
static int
topo_add_disk(topo_hdl_t *thp, tnode_t *node, diskmon_t *target_diskp)
{
	nvlist_t	*fmri = NULL;
	nvlist_t	*asru_fmri;
	nvlist_t	*fru_fmri;
	char		*devpath = NULL;
	char		*capacity = NULL;
	char		*firmrev = NULL;
	char		*serial = NULL;
	char		*manuf = NULL;
	char		*model = NULL;
	char		*cstr = NULL;
	char		*buf;
	char		*label;
	char		*p;
	uint64_t	ptr = 0;
	int		buflen;
	int		err;
	int		orig_cstr_len;
	dm_fru_t	*frup;
	diskmon_t	*diskp;

	/*
	 * Match this node to a disk in the configuration by looking at
	 * our parent's fmri (and do that by getting our FMRI and chopping
	 * off the last part).
	 */
	if (topo_node_resource(node, &fmri, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not generate FMRI for "
		    "node %p!\n", (void *)node);
		return (-1);
	}

	if (topo_fmri_nvl2str(thp, fmri, &cstr, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not create string for "
		    "node %p's FMRI!\n", (void *)node);
		nvlist_free(fmri);
		return (-1);
	}

	nvlist_free(fmri);

	/*
	 * Chop off all but last path (since there's no way to get
	 * the node's parent in the libtopo API).
	 */
	orig_cstr_len = strlen(cstr) + 1;
	p = strrchr(cstr, '/');
	dm_assert(p != NULL);
	*p = 0;
	if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &ptr) != 0) {
		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
		topo_hdl_free(thp, cstr, orig_cstr_len);
		/* Skip this disk: */
		return (0);
	}

	topo_hdl_free(thp, cstr, orig_cstr_len);

	diskp = (diskmon_t *)(uintptr_t)ptr;

	/* If we were called upon to update a particular disk, do it */
	if (target_diskp != NULL && diskp != target_diskp) {
		return (0);
	}

	/*
	 * Update the diskmon's ASRU and FRU with our information (this
	 * information is cached in the diskmon so we don't have to do a
	 * time-consuming topo traversal when we get an ereport).
	 */
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
	    &asru_fmri, &err) == 0) {
		diskmon_add_asru(diskp, asru_fmri);
		nvlist_free(asru_fmri);
	}
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
	    &fru_fmri, &err) == 0) {
		diskmon_add_fru(diskp, fru_fmri);
		nvlist_free(fru_fmri);
	}
	if (topo_node_resource(node, &fmri, &err) == 0) {
		diskmon_add_disk_fmri(diskp, fmri);
		nvlist_free(fmri);
	}

	/*
	 * Update the diskmon's location field with the disk's label
	 */
	if (diskp->location)
		dstrfree(diskp->location);
	if (topo_node_label(node, &label, &err) == 0) {
		diskp->location = dstrdup(label);
		topo_hdl_strfree(thp, label);
	} else
		diskp->location = dstrdup("unknown location");

	/*
	 * Check for a device path property (if the disk is configured,
	 * it will be present) and add it to the diskmon's properties)
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
	    &devpath, &err) == 0) {
		char devp[PATH_MAX];
		/*
		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
		 * minor device node
		 */
		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
		    devp);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the logical disk node, if it exists
	 */
	if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
		    devpath);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the FRU information (if present in the node) to the diskmon's
	 * fru data structure:
	 */
	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MODEL, &model, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_CAPACITY, &capacity, &err);

	frup = new_dmfru(manuf, model, firmrev, serial,
	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));

	/*
	 * Update the disk's resource FMRI with the
	 * SunService-required members:
	 * FM_FMRI_HC_SERIAL_ID, FM_FMRI_HC_PART, and
	 * FM_FMRI_HC_REVISION
	 */
	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	transform_model_string(manuf, model, &buf, &buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_PART, buf);

	/*
	 * Add the serial number to the ASRU so that when the resource
	 * is marked faulty in the fmd resource cache, the hc scheme
	 * plugin can detect when the disk is no longer installed (and so,
	 * can clear the faulty state automatically across fmd restarts).
	 *
	 * The serial number is only updated when a disk comes online
	 * because that's when the disk node exists in the topo tree.
	 * It's ok to keep a stale value in the ASRU when the disk is removed
	 * because it's only used as part of fault creation when the disk
	 * is configured (online), at which point it will be updated with
	 * the (current) serial number of the disk inserted.
	 */
	(void) nvlist_add_string(diskp->asru_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	dfree(buf, buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_REVISION, firmrev);

	if (model) {
		topo_hdl_strfree(thp, model);
	}

	if (manuf) {
		topo_hdl_strfree(thp, manuf);
	}

	if (serial) {
		topo_hdl_strfree(thp, serial);
	}

	if (firmrev) {
		topo_hdl_strfree(thp, firmrev);
	}

	if (capacity) {
		topo_hdl_strfree(thp, capacity);
	}

	/* Add the fru information to the diskmon: */
	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
	dm_assert(diskp->frup == NULL);
	diskp->frup = frup;
	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);

	return (0);
}
Beispiel #2
0
/*
 * Synchronize pool configuration to disk.  This must be called with the
 * namespace lock held. Synchronizing the pool cache is typically done after
 * the configuration has been synced to the MOS. This exposes a window where
 * the MOS config will have been updated but the cache file has not. If
 * the system were to crash at that instant then the cached config may not
 * contain the correct information to open the pool and an explicity import
 * would be required.
 */
void
spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
{
	spa_config_dirent_t *dp, *tdp;
	nvlist_t *nvl;
	char *pool_name;

	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) {
			/*
			 * Skip over our own pool if we're about to remove
			 * ourselves from the spa namespace or any pool that
			 * is readonly. Since we cannot guarantee that a
			 * readonly pool would successfully import upon reboot,
			 * we don't allow them to be written to the cache file.
			 */
			if ((spa == target && removing) ||
			    !spa_writeable(spa))
				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);

			if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
				VERIFY0(nvlist_lookup_string(spa->spa_config,
					ZPOOL_CONFIG_POOL_NAME, &pool_name));
			} else
				pool_name = spa_name(spa);

			VERIFY(nvlist_add_nvlist(nvl, pool_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, FM_EREPORT_ZFS_CONFIG_SYNC);
}
Beispiel #3
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;
	char *pathname;
	struct _buf *file;
	uint64_t fsize;

#ifdef _KERNEL
	if (zfs_autoimport_disable)
		return;
#endif

	/*
	 * 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;
		(void) spa_add(nvpair_name(nvpair), child, NULL);
	}
	mutex_exit(&spa_namespace_lock);

	nvlist_free(nvlist);

out:
	if (buf != NULL)
		kmem_free(buf, fsize);

	kobj_close_file(file);
}
Beispiel #4
0
/*
 * sync out AVL trees to persistent storage.
 */
void
zfs_fuid_sync(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
{
#ifdef HAVE_ZPL
	nvlist_t *nvp;
	nvlist_t **fuids;
	size_t nvsize = 0;
	char *packed;
	dmu_buf_t *db;
	fuid_domain_t *domnode;
	int numnodes;
	int i;

	if (!zfsvfs->z_fuid_dirty) {
		return;
	}

	rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);

	/*
	 * First see if table needs to be created?
	 */
	if (zfsvfs->z_fuid_obj == 0) {
		zfsvfs->z_fuid_obj = dmu_object_alloc(zfsvfs->z_os,
		    DMU_OT_FUID, 1 << 14, DMU_OT_FUID_SIZE,
		    sizeof (uint64_t), tx);
		VERIFY(zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
		    ZFS_FUID_TABLES, sizeof (uint64_t), 1,
		    &zfsvfs->z_fuid_obj, tx) == 0);
	}

	VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);

	numnodes = avl_numnodes(&zfsvfs->z_fuid_idx);
	fuids = kmem_alloc(numnodes * sizeof (void *), KM_SLEEP);
	for (i = 0, domnode = avl_first(&zfsvfs->z_fuid_domain); domnode; i++,
	    domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode)) {
		VERIFY(nvlist_alloc(&fuids[i], NV_UNIQUE_NAME, KM_SLEEP) == 0);
		VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX,
		    domnode->f_idx) == 0);
		VERIFY(nvlist_add_uint64(fuids[i], FUID_OFFSET, 0) == 0);
		VERIFY(nvlist_add_string(fuids[i], FUID_DOMAIN,
		    domnode->f_ksid->kd_name) == 0);
	}
	VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY,
	    fuids, numnodes) == 0);
	for (i = 0; i != numnodes; i++)
		nvlist_free(fuids[i]);
	kmem_free(fuids, numnodes * sizeof (void *));
	VERIFY(nvlist_size(nvp, &nvsize, NV_ENCODE_XDR) == 0);
	packed = kmem_alloc(nvsize, KM_SLEEP);
	VERIFY(nvlist_pack(nvp, &packed, &nvsize,
	    NV_ENCODE_XDR, KM_SLEEP) == 0);
	nvlist_free(nvp);
	zfsvfs->z_fuid_size = nvsize;
	dmu_write(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0,
	    zfsvfs->z_fuid_size, packed, tx);
	kmem_free(packed, zfsvfs->z_fuid_size);
	VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
	    FTAG, &db));
	dmu_buf_will_dirty(db, tx);
	*(uint64_t *)db->db_data = zfsvfs->z_fuid_size;
	dmu_buf_rele(db, FTAG);

	zfsvfs->z_fuid_dirty = B_FALSE;
	rw_exit(&zfsvfs->z_fuid_lock);
#endif /* HAVE_ZPL */
}
Beispiel #5
0
/*
 * Copy in a packed nvlist from the user and create a request set out of it.
 * If successful, return 0 and store a pointer to the set we've created. Returns
 * error code on error.
 */
int
kcpc_copyin_set(kcpc_set_t **inset, void *ubuf, size_t len)
{
	kcpc_set_t	*set;
	int		i;
	int		j;
	char		*packbuf;

	nvlist_t	*nvl;
	nvpair_t	*nvp = NULL;

	nvlist_t	*attrs;
	nvpair_t	*nvp_attr;
	kcpc_attr_t	*attrp;

	nvlist_t	**reqlist;
	uint_t		nreqs;
	uint64_t	uint64;
	uint32_t	uint32;
	uint32_t	setflags = (uint32_t)-1;
	char		*string;
	char		*name;

	if (len < CPC_MIN_PACKSIZE || len > CPC_MAX_PACKSIZE)
		return (EINVAL);

	packbuf = kmem_alloc(len, KM_SLEEP);

	if (copyin(ubuf, packbuf, len) == -1) {
		kmem_free(packbuf, len);
		return (EFAULT);
	}

	if (nvlist_unpack(packbuf, len, &nvl, KM_SLEEP) != 0) {
		kmem_free(packbuf, len);
		return (EINVAL);
	}

	/*
	 * The nvlist has been unpacked so there is no need for the packed
	 * representation from this point on.
	 */
	kmem_free(packbuf, len);

	i = 0;
	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
		switch (nvpair_type(nvp)) {
		case DATA_TYPE_UINT32:
			if (strcmp(nvpair_name(nvp), "flags") != 0 ||
			    nvpair_value_uint32(nvp, &setflags) != 0) {
				nvlist_free(nvl);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_NVLIST_ARRAY:
			if (strcmp(nvpair_name(nvp), "reqs") != 0 ||
			    nvpair_value_nvlist_array(nvp, &reqlist,
			    &nreqs) != 0) {
				nvlist_free(nvl);
				return (EINVAL);
			}
			break;
		default:
			nvlist_free(nvl);
			return (EINVAL);
		}
		i++;
	}

	/*
	 * There should be two members in the top-level nvlist:
	 * an array of nvlists consisting of the requests, and flags.
	 * Anything else is an invalid set.
	 */
	if (i != 2) {
		nvlist_free(nvl);
		return (EINVAL);
	}

	if (nreqs > CPC_MAX_NREQS) {
		nvlist_free(nvl);
		return (EINVAL);
	}

	/*
	 * The requests are now stored in the nvlist array at reqlist.
	 * Note that the use of kmem_zalloc() to alloc the kcpc_set_t means
	 * we don't need to call the init routines for ks_lock and ks_condv.
	 */
	set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP);
	set->ks_req = (kcpc_request_t *)kmem_zalloc(sizeof (kcpc_request_t) *
	    nreqs, KM_SLEEP);
	set->ks_nreqs = nreqs;
	/*
	 * If the nvlist didn't contain a flags member, setflags was initialized
	 * with an illegal value and this set will fail sanity checks later on.
	 */
	set->ks_flags = setflags;
	/*
	 * Initialize bind/unbind set synchronization.
	 */
	set->ks_state &= ~KCPC_SET_BOUND;

	/*
	 * Build the set up one request at a time, always keeping it self-
	 * consistent so we can give it to kcpc_free_set() if we need to back
	 * out and return and error.
	 */
	for (i = 0; i < nreqs; i++) {
		nvp = NULL;
		set->ks_req[i].kr_picnum = -1;
		while ((nvp = nvlist_next_nvpair(reqlist[i], nvp)) != NULL) {
			name = nvpair_name(nvp);
			switch (nvpair_type(nvp)) {
			case DATA_TYPE_UINT32:
				if (nvpair_value_uint32(nvp, &uint32) == EINVAL)
					goto inval;
				if (strcmp(name, "cr_flags") == 0)
					set->ks_req[i].kr_flags = uint32;
				if (strcmp(name, "cr_index") == 0)
					set->ks_req[i].kr_index = uint32;
				break;
			case DATA_TYPE_UINT64:
				if (nvpair_value_uint64(nvp, &uint64) == EINVAL)
					goto inval;
				if (strcmp(name, "cr_preset") == 0)
					set->ks_req[i].kr_preset = uint64;
				break;
			case DATA_TYPE_STRING:
				if (nvpair_value_string(nvp, &string) == EINVAL)
					goto inval;
				if (strcmp(name, "cr_event") == 0)
					(void) strncpy(set->ks_req[i].kr_event,
					    string, CPC_MAX_EVENT_LEN);
				break;
			case DATA_TYPE_NVLIST:
				if (strcmp(name, "cr_attr") != 0)
					goto inval;
				if (nvpair_value_nvlist(nvp, &attrs) == EINVAL)
					goto inval;
				nvp_attr = NULL;
				/*
				 * If the picnum has been specified as an
				 * attribute, consume that attribute here and
				 * remove it from the list of attributes.
				 */
				if (nvlist_lookup_uint64(attrs, "picnum",
				    &uint64) == 0) {
					if (nvlist_remove(attrs, "picnum",
					    DATA_TYPE_UINT64) != 0)
						panic("nvlist %p faulty",
						    (void *)attrs);
					set->ks_req[i].kr_picnum = uint64;
				}

				if ((set->ks_req[i].kr_nattrs =
				    kcpc_nvlist_npairs(attrs)) == 0)
					break;

				if (set->ks_req[i].kr_nattrs > CPC_MAX_ATTRS)
					goto inval;

				set->ks_req[i].kr_attr =
				    kmem_alloc(set->ks_req[i].kr_nattrs *
				    sizeof (kcpc_attr_t), KM_SLEEP);
				j = 0;

				while ((nvp_attr = nvlist_next_nvpair(attrs,
				    nvp_attr)) != NULL) {
					attrp = &set->ks_req[i].kr_attr[j];

					if (nvpair_type(nvp_attr) !=
					    DATA_TYPE_UINT64)
						goto inval;

					(void) strncpy(attrp->ka_name,
					    nvpair_name(nvp_attr),
					    CPC_MAX_ATTR_LEN);

					if (nvpair_value_uint64(nvp_attr,
					    &(attrp->ka_val)) == EINVAL)
						goto inval;
					j++;
				}
				ASSERT(j == set->ks_req[i].kr_nattrs);
			default:
				break;
			}
		}
	}

	nvlist_free(nvl);
	*inset = set;
	return (0);

inval:
	nvlist_free(nvl);
	kcpc_free_set(set);
	return (EINVAL);
}
Beispiel #6
0
/*
 * Generate the pool's configuration based on the current in-core state.
 * We infer whether to generate a complete config or just one top-level config
 * based on whether vd is the root vdev.
 */
nvlist_t *
spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
{
	nvlist_t *config, *nvroot;
	vdev_t *rvd = spa->spa_root_vdev;
	unsigned long hostid = 0;
	boolean_t locked = B_FALSE;
	uint64_t split_guid;

	if (vd == NULL) {
		vd = rvd;
		locked = B_TRUE;
		spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER);
	}

	ASSERT(spa_config_held(spa, SCL_CONFIG | SCL_STATE, RW_READER) ==
	    (SCL_CONFIG | SCL_STATE));

	/*
	 * If txg is -1, report the current value of spa->spa_config_txg.
	 */
	if (txg == -1ULL)
		txg = spa->spa_config_txg;

	VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);

	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
	    spa_version(spa)) == 0);
	VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
	    spa_name(spa)) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
	    spa_state(spa)) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG,
	    txg) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
	    spa_guid(spa)) == 0);
	VERIFY(spa->spa_comment == NULL || nvlist_add_string(config,
	    ZPOOL_CONFIG_COMMENT, spa->spa_comment) == 0);


#ifdef	_KERNEL
	hostid = zone_get_hostid(NULL);
#else	/* _KERNEL */
	/*
	 * We're emulating the system's hostid in userland, so we can't use
	 * zone_get_hostid().
	 */
	(void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
#endif	/* _KERNEL */
	if (hostid != 0) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
		    hostid) == 0);
	}
	VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
	    utsname.nodename) == 0);

	if (vd != rvd) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
		    vd->vdev_top->vdev_guid) == 0);
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
		    vd->vdev_guid) == 0);
		if (vd->vdev_isspare)
			VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE,
			    1ULL) == 0);
		if (vd->vdev_islog)
			VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG,
			    1ULL) == 0);
		vd = vd->vdev_top;		/* label contains top config */
	} else {
		/*
		 * Only add the (potentially large) split information
		 * in the mos config, and not in the vdev labels
		 */
		if (spa->spa_config_splitting != NULL)
			VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
			    spa->spa_config_splitting) == 0);
	}

	/*
	 * Add the top-level config.  We even add this on pools which
	 * don't support holes in the namespace.
	 */
	vdev_top_config_generate(spa, config);

	/*
	 * If we're splitting, record the original pool's guid.
	 */
	if (spa->spa_config_splitting != NULL &&
	    nvlist_lookup_uint64(spa->spa_config_splitting,
	    ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID,
		    split_guid) == 0);
	}

	nvroot = vdev_config_generate(spa, vd, getstats, 0);
	VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
	nvlist_free(nvroot);

	if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
		ddt_histogram_t *ddh;
		ddt_stat_t *dds;
		ddt_object_t *ddo;

		ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
		ddt_get_dedup_histogram(spa, ddh);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_HISTOGRAM,
		    (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t)) == 0);
		kmem_free(ddh, sizeof (ddt_histogram_t));

		ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
		ddt_get_dedup_object_stats(spa, ddo);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_OBJ_STATS,
		    (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t)) == 0);
		kmem_free(ddo, sizeof (ddt_object_t));

		dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
		ddt_get_dedup_stats(spa, dds);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_STATS,
		    (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t)) == 0);
		kmem_free(dds, sizeof (ddt_stat_t));
	}

	if (locked)
		spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);

	return (config);
}
Beispiel #7
0
/* ARGSUSED */
static int
xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
    cred_t *cr, caller_context_t *ct)
{
	int error;
	f_attr_t attr;
	uint64_t fsid;
	xvattr_t xvattr;
	xoptattr_t *xoap;	/* Pointer to optional attributes */
	vnode_t *ppvp;
	const char *domain;
	uint32_t rid;

	xva_init(&xvattr);

	if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
		return (EINVAL);

	/*
	 * For detecting ephemeral uid/gid
	 */
	xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID);

	/*
	 * We need to access the real fs object.
	 * vp points to a GFS file; ppvp points to the real object.
	 */
	ppvp = gfs_file_parent(gfs_file_parent(vp));

	/*
	 * Iterate through the attrs associated with this view
	 */

	for (attr = 0; attr < F_ATTR_ALL; attr++) {
		if (xattr_view != attr_to_xattr_view(attr)) {
			continue;
		}

		switch (attr) {
		case F_SYSTEM:
			XVA_SET_REQ(&xvattr, XAT_SYSTEM);
			break;
		case F_READONLY:
			XVA_SET_REQ(&xvattr, XAT_READONLY);
			break;
		case F_HIDDEN:
			XVA_SET_REQ(&xvattr, XAT_HIDDEN);
			break;
		case F_ARCHIVE:
			XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
			break;
		case F_IMMUTABLE:
			XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
			break;
		case F_APPENDONLY:
			XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
			break;
		case F_NOUNLINK:
			XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
			break;
		case F_OPAQUE:
			XVA_SET_REQ(&xvattr, XAT_OPAQUE);
			break;
		case F_NODUMP:
			XVA_SET_REQ(&xvattr, XAT_NODUMP);
			break;
		case F_AV_QUARANTINED:
			XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
			break;
		case F_AV_MODIFIED:
			XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
			break;
		case F_AV_SCANSTAMP:
			if (ppvp->v_type == VREG)
				XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
			break;
		case F_CRTIME:
			XVA_SET_REQ(&xvattr, XAT_CREATETIME);
			break;
		case F_FSID:
			fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) |
			    (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] &
			    0xffffffff));
			VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
			    fsid) == 0);
			break;
		case F_REPARSE:
			XVA_SET_REQ(&xvattr, XAT_REPARSE);
			break;
		case F_GEN:
			XVA_SET_REQ(&xvattr, XAT_GEN);
			break;
		case F_OFFLINE:
			XVA_SET_REQ(&xvattr, XAT_OFFLINE);
			break;
		case F_SPARSE:
			XVA_SET_REQ(&xvattr, XAT_SPARSE);
			break;
		default:
			break;
		}
	}

	error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
	if (error)
		return (error);

	/*
	 * Process all the optional attributes together here.  Notice that
	 * xoap was set when the optional attribute bits were set above.
	 */
	if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) {
		if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_READONLY),
			    xoap->xoa_readonly) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_HIDDEN),
			    xoap->xoa_hidden) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_SYSTEM),
			    xoap->xoa_system) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_ARCHIVE),
			    xoap->xoa_archive) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_IMMUTABLE),
			    xoap->xoa_immutable) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_NOUNLINK),
			    xoap->xoa_nounlink) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_APPENDONLY),
			    xoap->xoa_appendonly) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_NODUMP),
			    xoap->xoa_nodump) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_OPAQUE),
			    xoap->xoa_opaque) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_AV_QUARANTINED),
			    xoap->xoa_av_quarantined) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_AV_MODIFIED),
			    xoap->xoa_av_modified) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) {
			VERIFY(nvlist_add_uint8_array(nvlp,
			    attr_to_name(F_AV_SCANSTAMP),
			    xoap->xoa_av_scanstamp,
			    sizeof (xoap->xoa_av_scanstamp)) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) {
			VERIFY(nvlist_add_uint64_array(nvlp,
			    attr_to_name(F_CRTIME),
			    (uint64_t *)&(xoap->xoa_createtime),
			    sizeof (xoap->xoa_createtime) /
			    sizeof (uint64_t)) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_REPARSE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_REPARSE),
			    xoap->xoa_reparse) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_GEN)) {
			VERIFY(nvlist_add_uint64(nvlp,
			    attr_to_name(F_GEN),
			    xoap->xoa_generation) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_OFFLINE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_OFFLINE),
			    xoap->xoa_offline) == 0);
		}
		if (XVA_ISSET_RTN(&xvattr, XAT_SPARSE)) {
			VERIFY(nvlist_add_boolean_value(nvlp,
			    attr_to_name(F_SPARSE),
			    xoap->xoa_sparse) == 0);
		}
	}
	/*
	 * Check for optional ownersid/groupsid
	 */

	if (xvattr.xva_vattr.va_uid > MAXUID) {
		nvlist_t *nvl_sid;

		if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
			return (ENOMEM);

		if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid,
		    &domain, &rid) == 0) {
			VERIFY(nvlist_add_string(nvl_sid,
			    SID_DOMAIN, domain) == 0);
			VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
			VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
			    nvl_sid) == 0);
		}
		nvlist_free(nvl_sid);
	}
	if (xvattr.xva_vattr.va_gid > MAXUID) {
		nvlist_t *nvl_sid;

		if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
			return (ENOMEM);

		if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid,
		    &domain, &rid) == 0) {
			VERIFY(nvlist_add_string(nvl_sid,
			    SID_DOMAIN, domain) == 0);
			VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
			VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
			    nvl_sid) == 0);
		}
		nvlist_free(nvl_sid);
	}

	return (0);
}
Beispiel #8
0
/*
 * Refresh the vdev statistics associated with the given pool.  This is used in
 * iostat to show configuration changes and determine the delta from the last
 * time the function was called.  This function can fail, in case the pool has
 * been destroyed.
 */
int
zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
{
	zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
	int error;
	nvlist_t *config;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	*missing = B_FALSE;
	(void) strcpy(zc.zc_name, zhp->zpool_name);

	if (zhp->zpool_config_size == 0)
		zhp->zpool_config_size = 1 << 16;

	if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
		return (-1);

	for (;;) {
		//if (zfs_ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
		if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_STATS,
		    &zc) == 0) {
			/*
			 * The real error is returned in the zc_cookie field.
			 */
            printf("ioctl(POOL_STATS) returned error\n");
			error = zc.zc_cookie;
			break;
		}

		if (errno == ENOMEM) {
			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
				zcmd_free_nvlists(&zc);
				return (-1);
			}
		} else {
			zcmd_free_nvlists(&zc);
			if (errno == ENOENT || errno == EINVAL)
				*missing = B_TRUE;
			zhp->zpool_state = POOL_STATE_UNAVAIL;
			return (0);
		}
	}

	if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
		zcmd_free_nvlists(&zc);
		return (-1);
	}

	zcmd_free_nvlists(&zc);

	zhp->zpool_config_size = zc.zc_nvlist_dst_size;

	if (zhp->zpool_config != NULL) {
		uint64_t oldtxg, newtxg;

		verify(nvlist_lookup_uint64(zhp->zpool_config,
		    ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
		verify(nvlist_lookup_uint64(config,
		    ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);

		if (zhp->zpool_old_config != NULL)
			nvlist_free(zhp->zpool_old_config);

		if (oldtxg != newtxg) {
			nvlist_free(zhp->zpool_config);
			zhp->zpool_old_config = NULL;
		} else {
			zhp->zpool_old_config = zhp->zpool_config;
		}
	}

	zhp->zpool_config = config;
	if (error)
		zhp->zpool_state = POOL_STATE_UNAVAIL;
	else
		zhp->zpool_state = POOL_STATE_ACTIVE;

	return (0);
}
Beispiel #9
0
/*
 * Take the deviceID property from the object path and get the raw devpath
 * of the drive that corresponds to the given device ID.
 */
static CIMBool
get_devpath(CCIMObjectPath *op, char *devpath, int len)
{
	CCIMPropertyList	*prop_list = NULL;
	CCIMProperty		*prop = NULL;
	int			error;
	dm_descriptor_t		dp;
	dm_descriptor_t		*da;
	nvlist_t		*attrs;
	char			*opath;
	char			*keyprop;
	int			type = 0;
	char			*p;

	if (strcasecmp(op->mName, "Solaris_Disk") == 0) {
	    keyprop = "Tag";
	    type = 1;
	} else if (strcasecmp(op->mName, "Solaris_DiskDrive") == 0) {
	    keyprop = "deviceid";
	    type = 2;
	} else if (strcasecmp(op->mName, "Solaris_DiskPartition") == 0) {
	    keyprop = "deviceid";
	    type = 3;
	} else {
	    return (cim_false);
	}

	if (op != NULL) {
	    prop_list = op->mKeyProperties;
	}

	for (; prop_list; prop_list = prop_list->mNext) {

	    if (((prop = prop_list->mDataObject) != NULL &&
		prop->mName != NULL && strcasecmp(prop->mName, keyprop)) == 0) {
		break;
	    }
	}

	if (prop == NULL || prop->mValue == NULL) {
	    return (cim_false);
	}

	switch (type) {
	case 1:
	    dp = dm_get_descriptor_by_name(DM_MEDIA, prop->mValue, &error);
	    if (error != 0) {
		return (cim_false);
	    }

	    da = dm_get_associated_descriptors(dp, DM_DRIVE, &error);
	    dm_free_descriptor(dp);
	    if (error != 0 || da == NULL) {
		return (cim_false);
	    }

	    if (da[0] == NULL) {
		dm_free_descriptors(da);
		return (cim_false);
	    }

	    attrs = dm_get_attributes(da[0], &error);
	    dm_free_descriptors(da);
	    if (error != 0) {
		return (cim_false);
	    }

	    if (nvlist_lookup_string(attrs, DM_OPATH, &opath) != 0) {
		nvlist_free(attrs);
		return (cim_false);
	    }
	    (void) strlcpy(devpath, opath, len);
	    nvlist_free(attrs);
	    break;

	case 2:
	    dp = dm_get_descriptor_by_name(DM_DRIVE, prop->mValue, &error);
	    if (error != 0) {
		return (cim_false);
	    }

	    attrs = dm_get_attributes(dp, &error);
	    dm_free_descriptor(dp);
	    if (error != 0) {
		return (cim_false);
	    }

	    if (nvlist_lookup_string(attrs, DM_OPATH, &opath) != 0) {
		nvlist_free(attrs);
		return (cim_false);
	    }
	    (void) strlcpy(devpath, opath, len);
	    nvlist_free(attrs);
	    break;

	case 3:
	    /* Convert the Solaris_DiskPartition value to rdsk. */
	    p = strstr(prop->mValue, "/dsk/");
	    if (p == NULL || (strlen(prop->mValue) + 2) > len) {
		(void) strlcpy(devpath, prop->mValue, len);
	    } else {
		p++;
		*p = 0;
		(void) strcpy(devpath, prop->mValue);	/* copy up to dsk/ */
		*p = 'd';
		(void) strcat(devpath, "r");		/* prefix 'r' to dsk/ */
		(void) strcat(devpath, p);		/* append the rest */
	    }
	    break;
	}

	return (cim_true);
}
Beispiel #10
0
/*
 * Create a generic topo node based on the hcfmri strcuture passed in.
 */
int
x86pi_enum_generic(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri,
    tnode_t *t_bindparent, tnode_t *t_fmriparent, tnode_t **t_node, int flag)
{
	int		rv;
	int		err;
	nvlist_t	*out;
	nvlist_t	*fmri;
	nvlist_t	*auth;

	topo_mod_dprintf(mod, "%s adding entry for type (%s)\n",
	    _ENUM_NAME, hcfmri->hc_name);

	if (t_bindparent == NULL) {
		topo_mod_dprintf(mod,
		    "%s called with NULL parent for type %s\n",
		    _ENUM_NAME, hcfmri->hc_name);
		return (-1);
	}

	/* Create the FMRI for this node */
	auth = topo_mod_auth(mod, t_bindparent);
	fmri = topo_mod_hcfmri(mod, t_fmriparent, FM_HC_SCHEME_VERSION,
	    hcfmri->hc_name, hcfmri->instance, NULL, auth,
	    hcfmri->part_number, hcfmri->version, hcfmri->serial_number);

	nvlist_free(auth);

	if (fmri == NULL) {
		topo_mod_dprintf(mod,
		    "%s failed to create %s fmri : %s\n", _ENUM_NAME,
		    hcfmri->hc_name, topo_strerror(topo_mod_errno(mod)));
		return (-1);
	}

	rv = topo_node_range_create(mod, t_bindparent, hcfmri->hc_name, 0, 4);
	if (rv != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
		topo_mod_dprintf(mod, "%s range create failed for node %s\n",
		    _ENUM_NAME, hcfmri->hc_name);
	}

	/* Bind this node to the parent */
	*t_node = x86pi_node_bind(mod, t_bindparent, hcfmri, fmri, flag);
	nvlist_free(fmri);
	if (*t_node == NULL) {
		topo_mod_dprintf(mod,
		    "%s failed to bind %s node instance %d: %s\n",
		    _ENUM_NAME, hcfmri->hc_name, hcfmri->instance,
		    topo_strerror(topo_mod_errno(mod)));
		return (-1);
	}

	/* call IPMI facility provider to register fac methods */
	if (topo_mod_load(mod, _FAC_PROV, TOPO_VERSION) == NULL) {
		topo_mod_dprintf(mod,
		    "%s: Failed to load %s module: %s\n", _ENUM_NAME, _FAC_PROV,
		    topo_mod_errmsg(mod));
		return (-1);
	}

	rv = topo_mod_enumerate(mod, *t_node, _FAC_PROV, _FAC_PROV, 0, 0, NULL);
	if (rv != 0) {
		topo_mod_dprintf(mod,
		    "%s: %s failed: %s\n", _ENUM_NAME, _FAC_PROV,
		    topo_mod_errmsg(mod));
		return (-1);
	}

	/* invoke fac_prov_ipmi_enum method */
	if (topo_method_supported(*t_node, TOPO_METH_FAC_ENUM, 0)) {
		if (topo_method_invoke(*t_node, TOPO_METH_FAC_ENUM, 0, NULL,
		    &out, &err) != 0) {
			/* log the error and drive on */
			topo_mod_dprintf(mod,
			    "%s: TOPO_METH_FAC_ENUM failed\n", _ENUM_NAME);
		} else {
			fac_done = 1;
		}
	}

	topo_mod_dprintf(mod, "%s added (%s) node\n", _ENUM_NAME,
	    topo_node_name(*t_node));

	return (0);
}
Beispiel #11
0
/*
 * Loads the pool namespace, or re-loads it if the cache has changed.
 */
static int
namespace_reload(libzfs_handle_t *hdl)
{
	nvlist_t *config;
	config_node_t *cn;
	nvpair_t *elem;
	zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
	void *cookie;

	if (hdl->libzfs_ns_gen == 0) {
		/*
		 * This is the first time we've accessed the configuration
		 * cache.  Initialize the AVL tree and then fall through to the
		 * common code.
		 */
		if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
		    sizeof (config_node_t),
		    offsetof(config_node_t, cn_avl),
		    config_node_compare, UU_DEFAULT)) == NULL)
			return (no_memory(hdl));

		if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
		    NULL, UU_DEFAULT)) == NULL)
			return (no_memory(hdl));
	}

	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
		return (-1);

	for (;;) {
		zc.zc_cookie = hdl->libzfs_ns_gen;
		//if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
		if (zfs_ioctl(hdl, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
			switch (errno) {
			case EEXIST:
				/*
				 * The namespace hasn't changed.
				 */
				zcmd_free_nvlists(&zc);
				return (0);

			case ENOMEM:
				if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
					zcmd_free_nvlists(&zc);
					return (-1);
				}
				break;

			default:
				zcmd_free_nvlists(&zc);
				return (zfs_standard_error(hdl, errno,
				    dgettext(TEXT_DOMAIN, "failed to read "
				    "pool configuration")));
			}
		} else {
			hdl->libzfs_ns_gen = zc.zc_cookie;
			break;
		}
	}

	if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
		zcmd_free_nvlists(&zc);
		return (-1);
	}

	zcmd_free_nvlists(&zc);

	/*
	 * Clear out any existing configuration information.
	 */
	cookie = NULL;
	while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
		nvlist_free(cn->cn_config);
		free(cn->cn_name);
		free(cn);
	}

	elem = NULL;
	while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
		nvlist_t *child;
		uu_avl_index_t where;

		if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
			nvlist_free(config);
			return (-1);
		}

		if ((cn->cn_name = zfs_strdup(hdl,
		    nvpair_name(elem))) == NULL) {
			free(cn);
			nvlist_free(config);
			return (-1);
		}

		verify(nvpair_value_nvlist(elem, &child) == 0);
		if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
			free(cn->cn_name);
			free(cn);
			nvlist_free(config);
			return (no_memory(hdl));
		}
		verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
		    == NULL);

		uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
	}

	nvlist_free(config);
	return (0);
}
Beispiel #12
0
int
main(int argc, char *argv[])
{
    char *buf = malloc(INITIAL_BUFLEN);
    dmu_replay_record_t thedrr;
    dmu_replay_record_t *drr = &thedrr;
    struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
    struct drr_end *drre = &thedrr.drr_u.drr_end;
    struct drr_object *drro = &thedrr.drr_u.drr_object;
    struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
    struct drr_write *drrw = &thedrr.drr_u.drr_write;
    struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
    struct drr_free *drrf = &thedrr.drr_u.drr_free;
    struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
    char c;
    boolean_t verbose = B_FALSE;
    boolean_t first = B_TRUE;
    int err;
    zio_cksum_t zc = { 0 };
    zio_cksum_t pcksum = { 0 };

    while ((c = getopt(argc, argv, ":vC")) != -1) {
        switch (c) {
        case 'C':
            do_cksum = B_FALSE;
            break;
        case 'v':
            verbose = B_TRUE;
            break;
        case ':':
            (void) fprintf(stderr,
                           "missing argument for '%c' option\n", optopt);
            usage();
            break;
        case '?':
            (void) fprintf(stderr, "invalid option '%c'\n",
                           optopt);
            usage();
        }
    }

    if (isatty(STDIN_FILENO)) {
        (void) fprintf(stderr,
                       "Error: Backup stream can not be read "
                       "from a terminal.\n"
                       "You must redirect standard input.\n");
        exit(1);
    }

    send_stream = stdin;
    pcksum = zc;
    while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) {

        if (first) {
            if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
                do_byteswap = B_TRUE;
                if (do_cksum) {
                    ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
                    /*
                     * recalculate header checksum now
                     * that we know it needs to be
                     * byteswapped.
                     */
                    fletcher_4_incremental_byteswap(drr,
                                                    sizeof (dmu_replay_record_t), &zc);
                }
            } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
                (void) fprintf(stderr, "Invalid stream "
                               "(bad magic number)\n");
                exit(1);
            }
            first = B_FALSE;
        }
        if (do_byteswap) {
            drr->drr_type = BSWAP_32(drr->drr_type);
            drr->drr_payloadlen =
                BSWAP_32(drr->drr_payloadlen);
        }

        /*
         * At this point, the leading fields of the replay record
         * (drr_type and drr_payloadlen) have been byte-swapped if
         * necessary, but the rest of the data structure (the
         * union of type-specific structures) is still in its
         * original state.
         */
        if (drr->drr_type >= DRR_NUMTYPES) {
            (void) printf("INVALID record found: type 0x%x\n",
                          drr->drr_type);
            (void) printf("Aborting.\n");
            exit(1);
        }

        drr_record_count[drr->drr_type]++;

        switch (drr->drr_type) {
        case DRR_BEGIN:
            if (do_byteswap) {
                drrb->drr_magic = BSWAP_64(drrb->drr_magic);
                drrb->drr_versioninfo =
                    BSWAP_64(drrb->drr_versioninfo);
                drrb->drr_creation_time =
                    BSWAP_64(drrb->drr_creation_time);
                drrb->drr_type = BSWAP_32(drrb->drr_type);
                drrb->drr_flags = BSWAP_32(drrb->drr_flags);
                drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
                drrb->drr_fromguid =
                    BSWAP_64(drrb->drr_fromguid);
            }

            (void) printf("BEGIN record\n");
            (void) printf("\thdrtype = %lld\n",
                          DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
            (void) printf("\tfeatures = %llx\n",
                          DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
            (void) printf("\tmagic = %llx\n",
                          (u_longlong_t)drrb->drr_magic);
            (void) printf("\tcreation_time = %llx\n",
                          (u_longlong_t)drrb->drr_creation_time);
            (void) printf("\ttype = %u\n", drrb->drr_type);
            (void) printf("\tflags = 0x%x\n", drrb->drr_flags);
            (void) printf("\ttoguid = %llx\n",
                          (u_longlong_t)drrb->drr_toguid);
            (void) printf("\tfromguid = %llx\n",
                          (u_longlong_t)drrb->drr_fromguid);
            (void) printf("\ttoname = %s\n", drrb->drr_toname);
            if (verbose)
                (void) printf("\n");

            if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
                    DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
                nvlist_t *nv;
                int sz = drr->drr_payloadlen;

                if (sz > 1<<20) {
                    free(buf);
                    buf = malloc(sz);
                }
                (void) ssread(buf, sz, &zc);
                if (ferror(send_stream))
                    perror("fread");
                err = nvlist_unpack(buf, sz, &nv, 0);
                if (err)
                    perror(strerror(err));
                nvlist_print(stdout, nv);
                nvlist_free(nv);
            }
            break;

        case DRR_END:
            if (do_byteswap) {
                drre->drr_checksum.zc_word[0] =
                    BSWAP_64(drre->drr_checksum.zc_word[0]);
                drre->drr_checksum.zc_word[1] =
                    BSWAP_64(drre->drr_checksum.zc_word[1]);
                drre->drr_checksum.zc_word[2] =
                    BSWAP_64(drre->drr_checksum.zc_word[2]);
                drre->drr_checksum.zc_word[3] =
                    BSWAP_64(drre->drr_checksum.zc_word[3]);
            }
            /*
             * We compare against the *previous* checksum
             * value, because the stored checksum is of
             * everything before the DRR_END record.
             */
            if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
                                                pcksum)) {
                (void) printf("Expected checksum differs from "
                              "checksum in stream.\n");
                (void) printf("Expected checksum = %"
                              FX64 "/%" FX64 "/%" FX64 "/%" FX64 "\n",
                              pcksum.zc_word[0],
                              pcksum.zc_word[1],
                              pcksum.zc_word[2],
                              pcksum.zc_word[3]);
            }
            (void) printf("END checksum = %" FX64 "/%" FX64 "/%" FX64 "/%" FX64 "\n",
                          drre->drr_checksum.zc_word[0],
                          drre->drr_checksum.zc_word[1],
                          drre->drr_checksum.zc_word[2],
                          drre->drr_checksum.zc_word[3]);

            ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
            break;

        case DRR_OBJECT:
            if (do_byteswap) {
                drro->drr_object = BSWAP_64(drro->drr_object);
                drro->drr_type = BSWAP_32(drro->drr_type);
                drro->drr_bonustype =
                    BSWAP_32(drro->drr_bonustype);
                drro->drr_blksz = BSWAP_32(drro->drr_blksz);
                drro->drr_bonuslen =
                    BSWAP_32(drro->drr_bonuslen);
                drro->drr_toguid = BSWAP_64(drro->drr_toguid);
            }
            if (verbose) {
                (void) printf("OBJECT object = %llu type = %u "
                              "bonustype = %u blksz = %u bonuslen = %u\n",
                              (u_longlong_t)drro->drr_object,
                              drro->drr_type,
                              drro->drr_bonustype,
                              drro->drr_blksz,
                              drro->drr_bonuslen);
            }
            if (drro->drr_bonuslen > 0) {
                (void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen,
                                             8), &zc);
            }
            break;

        case DRR_FREEOBJECTS:
            if (do_byteswap) {
                drrfo->drr_firstobj =
                    BSWAP_64(drrfo->drr_firstobj);
                drrfo->drr_numobjs =
                    BSWAP_64(drrfo->drr_numobjs);
                drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
            }
            if (verbose) {
                (void) printf("FREEOBJECTS firstobj = %llu "
                              "numobjs = %llu\n",
                              (u_longlong_t)drrfo->drr_firstobj,
                              (u_longlong_t)drrfo->drr_numobjs);
            }
            break;

        case DRR_WRITE:
            if (do_byteswap) {
                drrw->drr_object = BSWAP_64(drrw->drr_object);
                drrw->drr_type = BSWAP_32(drrw->drr_type);
                drrw->drr_offset = BSWAP_64(drrw->drr_offset);
                drrw->drr_length = BSWAP_64(drrw->drr_length);
                drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
                drrw->drr_key.ddk_prop =
                    BSWAP_64(drrw->drr_key.ddk_prop);
            }
            if (verbose) {
                (void) printf("WRITE object = %llu type = %u "
                              "checksum type = %u\n"
                              "offset = %llu length = %llu "
                              "props = %llx\n",
                              (u_longlong_t)drrw->drr_object,
                              drrw->drr_type,
                              drrw->drr_checksumtype,
                              (u_longlong_t)drrw->drr_offset,
                              (u_longlong_t)drrw->drr_length,
                              (u_longlong_t)drrw->drr_key.ddk_prop);
            }
            (void) ssread(buf, drrw->drr_length, &zc);
            total_write_size += drrw->drr_length;
            break;

        case DRR_WRITE_BYREF:
            if (do_byteswap) {
                drrwbr->drr_object =
                    BSWAP_64(drrwbr->drr_object);
                drrwbr->drr_offset =
                    BSWAP_64(drrwbr->drr_offset);
                drrwbr->drr_length =
                    BSWAP_64(drrwbr->drr_length);
                drrwbr->drr_toguid =
                    BSWAP_64(drrwbr->drr_toguid);
                drrwbr->drr_refguid =
                    BSWAP_64(drrwbr->drr_refguid);
                drrwbr->drr_refobject =
                    BSWAP_64(drrwbr->drr_refobject);
                drrwbr->drr_refoffset =
                    BSWAP_64(drrwbr->drr_refoffset);
                drrwbr->drr_key.ddk_prop =
                    BSWAP_64(drrwbr->drr_key.ddk_prop);
            }
            if (verbose) {
                (void) printf("WRITE_BYREF object = %llu "
                              "checksum type = %u props = %llx\n"
                              "offset = %llu length = %llu\n"
                              "toguid = %llx refguid = %llx\n"
                              "refobject = %llu refoffset = %llu\n",
                              (u_longlong_t)drrwbr->drr_object,
                              drrwbr->drr_checksumtype,
                              (u_longlong_t)drrwbr->drr_key.ddk_prop,
                              (u_longlong_t)drrwbr->drr_offset,
                              (u_longlong_t)drrwbr->drr_length,
                              (u_longlong_t)drrwbr->drr_toguid,
                              (u_longlong_t)drrwbr->drr_refguid,
                              (u_longlong_t)drrwbr->drr_refobject,
                              (u_longlong_t)drrwbr->drr_refoffset);
            }
            break;

        case DRR_FREE:
            if (do_byteswap) {
                drrf->drr_object = BSWAP_64(drrf->drr_object);
                drrf->drr_offset = BSWAP_64(drrf->drr_offset);
                drrf->drr_length = BSWAP_64(drrf->drr_length);
            }
            if (verbose) {
                (void) printf("FREE object = %llu "
                              "offset = %llu length = %lld\n",
                              (u_longlong_t)drrf->drr_object,
                              (u_longlong_t)drrf->drr_offset,
                              (longlong_t)drrf->drr_length);
            }
            break;
        case DRR_SPILL:
            if (do_byteswap) {
                drrs->drr_object = BSWAP_64(drrs->drr_object);
                drrs->drr_length = BSWAP_64(drrs->drr_length);
            }
            if (verbose) {
                (void) printf("SPILL block for object = %" FU64
                              "length = %" FU64 "\n", drrs->drr_object,
                              drrs->drr_length);
            }
            (void) ssread(buf, drrs->drr_length, &zc);
            break;
        }
        pcksum = zc;
    }
    free(buf);

    /* Print final summary */

    (void) printf("SUMMARY:\n");
    (void) printf("\tTotal DRR_BEGIN records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_BEGIN]);
    (void) printf("\tTotal DRR_END records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_END]);
    (void) printf("\tTotal DRR_OBJECT records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_OBJECT]);
    (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
    (void) printf("\tTotal DRR_WRITE records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_WRITE]);
    (void) printf("\tTotal DRR_FREE records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_FREE]);
    (void) printf("\tTotal DRR_SPILL records = %lld\n",
                  (u_longlong_t)drr_record_count[DRR_SPILL]);
    (void) printf("\tTotal records = %lld\n",
                  (u_longlong_t)(drr_record_count[DRR_BEGIN] +
                                 drr_record_count[DRR_OBJECT] +
                                 drr_record_count[DRR_FREEOBJECTS] +
                                 drr_record_count[DRR_WRITE] +
                                 drr_record_count[DRR_FREE] +
                                 drr_record_count[DRR_SPILL] +
                                 drr_record_count[DRR_END]));
    (void) printf("\tTotal write size = %lld (0x%llx)\n",
                  (u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
    (void) printf("\tTotal stream length = %lld (0x%llx)\n",
                  (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
    return (0);
}
Beispiel #13
0
/*
 * reparse_free()
 *
 * Function to free memory of a nvlist allocated previously
 * by reparse_init().
 */
void
reparse_free(nvlist_t *nvl)
{
	if (nvl)
		nvlist_free(nvl);
}
Beispiel #14
0
static int
topo_add_sata_port(topo_hdl_t *thp, tnode_t *node, diskmon_t *target_diskp)
{
	nvlist_t	*nvlp = find_sfx4500_private_pgroup(thp, node);
	nvlist_t	*prop_nvlp;
	nvpair_t	*nvp = NULL;
	char		*prop_name, *prop_value;
#define	PNAME_MAX 128
	char		pname[PNAME_MAX];
	char		msgbuf[MAX_CONF_MSG_LEN];
	char		*indicator_name, *indicator_action;
	char		*indrule_states, *indrule_actions;
	int		err = 0, i;
	conf_err_t	conferr;
	boolean_t	conf_failure = B_FALSE;
	char		*physid = NULL;
	char		*label;
	nvlist_t	*diskprops = NULL;
	char		*cstr = NULL;
	indicator_t	*indp = NULL;
	indrule_t	*indrp = NULL;
	void		*p;
	diskmon_t	*diskp;
	void		*ptr;

	/* No private properties -- just ignore the port */
	if (nvlp == NULL)
		return (0);

	/*
	 * Look for a diskmon based on this node's FMRI string.
	 * Once a diskmon has been created, it's not re-created.  This is
	 * essential for the times when the tree-walk is called after a
	 * disk is inserted (or removed) -- in that case, the disk node
	 * handler simply updates the FRU information in the diskmon.
	 */
	if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {

		diskp = (diskmon_t *)p;

		/*
		 * Delete the FRU information from the diskmon.  If a disk
		 * is connected, its FRU information will be refreshed by
		 * the disk node code.
		 */
		if (diskp->frup && (target_diskp == NULL ||
		    diskp == target_diskp)) {
			dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
			dmfru_free(diskp->frup);
			diskp->frup = NULL;
			dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
		}

		dstrfree(cstr);
		nvlist_free(nvlp);
		return (0);
	}

	/*
	 * Determine the physical path to the attachment point
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO,
	    TOPO_IO_AP_PATH, &physid, &err) != 0) {

		/* physid cannot have been allocated */
		if (cstr)
			dstrfree(cstr);
		nvlist_free(nvlp);
		return (-1);
	}

	/*
	 * Process the properties.  If we encounter a property that
	 * is not an indicator name, action, or rule, add it to the
	 * disk's props list.
	 */

	/* Process indicators */
	i = 0;
	indicator_name = NULL;
	indicator_action = NULL;
	do {
		if (indicator_name != NULL && indicator_action != NULL) {

			if (topoprop_indicator_add(&indp, indicator_name,
			    indicator_action) != 0) {

				conf_failure = B_TRUE;
			}

			topo_hdl_strfree(thp, indicator_name);
			topo_hdl_strfree(thp, indicator_action);
		}

		(void) snprintf(pname, PNAME_MAX, SATA_IND_NAME "-%d", i);
		if (topo_prop_get_string(node, SUN_FIRE_X4500_PROPERTIES,
		    pname, &indicator_name, &err) != 0)
			break;

		(void) snprintf(pname, PNAME_MAX, SATA_IND_ACTION "-%d", i);
		if (topo_prop_get_string(node, SUN_FIRE_X4500_PROPERTIES,
		    pname, &indicator_action, &err) != 0)
			break;

		i++;
	} while (!conf_failure && indicator_name != NULL &&
	    indicator_action != NULL);

	if (!conf_failure && indp != NULL &&
	    (conferr = check_inds(indp)) != E_NO_ERROR) {
		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
		conf_failure = B_TRUE;
	}

	/* Process state rules and indicator actions */
	i = 0;
	indrule_states = NULL;
	indrule_actions = NULL;
	do {
		if (indrule_states != NULL && indrule_actions != NULL) {

			if (topoprop_indrule_add(&indrp, indrule_states,
			    indrule_actions) != 0) {

				conf_failure = B_TRUE;
			}

			topo_hdl_strfree(thp, indrule_states);
			topo_hdl_strfree(thp, indrule_actions);
		}

		(void) snprintf(pname, PNAME_MAX, SATA_INDRULE_STATES "-%d", i);
		if (topo_prop_get_string(node, SUN_FIRE_X4500_PROPERTIES,
		    pname, &indrule_states, &err) != 0)
			break;

		(void) snprintf(pname, PNAME_MAX, SATA_INDRULE_ACTIONS "-%d",
		    i);
		if (topo_prop_get_string(node, SUN_FIRE_X4500_PROPERTIES,
		    pname, &indrule_actions, &err) != 0)
			break;

		i++;
	} while (!conf_failure && indrule_states != NULL &&
	    indrule_actions != NULL);

	if (!conf_failure && indrp != NULL && indp != NULL &&
	    ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
	    != E_NO_ERROR ||
	    (conferr = check_consistent_ind_indrules(indp, indrp,
	    (ind_action_t **)&ptr)) != E_NO_ERROR)) {

		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
		conf_failure = B_TRUE;

	}

	/*
	 * Now collect miscellaneous properties.
	 * Each property is stored as an embedded nvlist named
	 * TOPO_PROP_VAL.  The property name is stored in the value for
	 * key=TOPO_PROP_VAL_NAME and the property's value is
	 * stored in the value for key=TOPO_PROP_VAL_VAL.  This is all
	 * necessary so we can subtractively decode the properties that
	 * we do not directly handle (so that these properties are added to
	 * the per-disk properties nvlist), increasing flexibility.
	 */
	(void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
		/* Only care about embedded nvlists named TOPO_PROP_VAL */
		if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
		    strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
		    nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
			continue;

		if (nonunique_nvlist_lookup_string(prop_nvlp,
		    TOPO_PROP_VAL_NAME, &prop_name) != 0)
			continue;

		/* Filter out indicator properties */
		if (strstr(prop_name, SATA_IND_NAME) != NULL ||
		    strstr(prop_name, SATA_IND_ACTION) != NULL ||
		    strstr(prop_name, SATA_INDRULE_STATES) != NULL ||
		    strstr(prop_name, SATA_INDRULE_ACTIONS) != NULL)
			continue;

		if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
		    &prop_value) != 0)
			continue;

		/* Add the property to the disk's prop list: */
		if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
			log_msg(MM_TOPO,
			    "Could not add disk property `%s' with "
			    "value `%s'\n", prop_name, prop_value);
	}

	nvlist_free(nvlp);

	if (cstr != NULL) {
		namevalpr_t nvpr;
		nvlist_t *dmap_nvl;

		nvpr.name = DISK_AP_PROP_APID;
		nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
		    (physid + 8) : physid;

		/*
		 * Set the diskmon's location to the value in this port's label.
		 * If there's a disk plugged in, the location will be updated
		 * to be the disk label (e.g. HD_ID_00).  Until a disk is
		 * inserted, though, there won't be a disk libtopo node
		 * created.
		 */

		/* Pass physid without the leading "/devices": */
		dmap_nvl = namevalpr_to_nvlist(&nvpr);

		diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);

		if (topo_node_label(node, &label, &err) == 0) {
			diskp->location = dstrdup(label);
			topo_hdl_strfree(thp, label);
		} else
			diskp->location = dstrdup("unknown location");

		if (!conf_failure && diskp != NULL) {
			/* Add this diskmon to the disk list */
			cfgdata_add_diskmon(config_data, diskp);
			if (nvlist_add_uint64(g_topo2diskmon, cstr,
			    (uint64_t)(uintptr_t)diskp) != 0) {
				log_msg(MM_TOPO,
				    "Could not add pointer to nvlist "
				    "for `%s'!\n", cstr);
			}
		} else if (diskp != NULL) {
			diskmon_free(diskp);
		} else {
			if (dmap_nvl)
				nvlist_free(dmap_nvl);
			if (indp)
				ind_free(indp);
			if (indrp)
				indrule_free(indrp);
			if (diskprops)
				nvlist_free(diskprops);
		}

		dstrfree(cstr);
	}


	topo_hdl_strfree(thp, physid);
	return (0);
}
Beispiel #15
0
/*ARGSUSED*/
static int
FRU_set(tnode_t *tn, did_t *pd,
    const char *dpnm, const char *tpgrp, const char *tpnm)
{
	topo_mod_t *mp;
	char *nm;
	int e = 0, err = 0;

	nm = topo_node_name(tn);
	mp = did_mod(pd);

	/*
	 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT,
	 * check for a CPUBOARD predecessor.  If found, inherit its
	 * parent's FRU.  Otherwise, continue with FRU set.
	 */
	if ((strcmp(nm, PCIEX_BUS) == 0) &&
	    (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {

		if (use_predecessor_fru(tn, CPUBOARD) == 0)
			return (0);
	}
	/*
	 * If this topology node represents something other than an
	 * ioboard or a device that implements a slot, inherit the
	 * parent's FRU value.  If there is no label, inherit our
	 * parent's FRU value.  Otherwise, munge up an fmri based on
	 * the label.
	 */
	if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 &&
	    strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) {
		(void) topo_node_fru_set(tn, NULL, 0, &e);
		return (0);
	}

	/*
	 * If ioboard, set fru fmri to hc fmri
	 */
	if (strcmp(nm, IOBOARD) == 0) {
		e = FRU_fmri_set(mp, tn);
		return (e);
	} else if (strcmp(nm, PCI_DEVICE) == 0 ||
	    strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) {
		nvlist_t *in, *out;

		mp = did_mod(pd);
		if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
			return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
		if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) {
			nvlist_free(in);
			return (topo_mod_seterrno(mp, EMOD_NOMEM));
		}
		if (topo_method_invoke(tn,
		    TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION,
		    in, &out, &err) != 0) {
			nvlist_free(in);
			return (topo_mod_seterrno(mp, err));
		}
		nvlist_free(in);
		(void) topo_node_fru_set(tn, out, 0, &err);
		if (out != NULL)
			nvlist_free(out);
	} else
		(void) topo_node_fru_set(tn, NULL, 0, &err);

	return (0);
}
Beispiel #16
0
static int
be_do_mount(int argc, char **argv)
{
	nvlist_t	*be_attrs;
	boolean_t	shared_fs = B_FALSE;
	int		err = 1;
	int		c;
	int		mount_flags = 0;
	char		*obe_name;
	char		*mountpoint;
	char		*tmp_mp = NULL;

	while ((c = getopt(argc, argv, "s:")) != -1) {
		switch (c) {
		case 's':
			shared_fs = B_TRUE;

			mount_flags |= BE_MOUNT_FLAG_SHARED_FS;

			if (strcmp(optarg, "rw") == 0) {
				mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
			} else if (strcmp(optarg, "ro") != 0) {
				(void) fprintf(stderr, _("The -s flag "
				    "requires an argument [ rw | ro ]\n"));
				usage();
				return (1);
			}

			break;
		default:
			usage();
			return (1);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 1 || argc > 2) {
		usage();
		return (1);
	}

	obe_name = argv[0];

	if (argc == 2) {
		mountpoint = argv[1];
		if (mountpoint[0] != '/') {
			(void) fprintf(stderr, _("Invalid mount point %s. "
			    "Mount point must start with a /.\n"), mountpoint);
			return (1);
		}
	} else {
		const char *tmpdir = getenv("TMPDIR");
		const char *tmpname = "tmp.XXXXXX";
		int sz;

		if (tmpdir == NULL)
			tmpdir = "/tmp";

		sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
		if (sz < 0) {
			(void) fprintf(stderr, _("internal error: "
			    "out of memory\n"));
			return (1);
		}

		mountpoint = mkdtemp(tmp_mp);
	}

	if (be_nvl_alloc(&be_attrs) != 0)
		return (1);

	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
		goto out;

	if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
		goto out;

	if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
	    mount_flags) != 0)
		goto out;

	err = be_mount(be_attrs);

	switch (err) {
	case BE_SUCCESS:
		(void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
		break;
	case BE_ERR_BE_NOENT:
		err = 1;
		(void) fprintf(stderr, _("%s does not exist or appear "
		    "to be a valid BE.\nPlease check that the name of "
		    "the BE provided is correct.\n"), obe_name);
		break;
	case BE_ERR_MOUNTED:
		(void) fprintf(stderr, _("%s is already mounted.\n"
		    "Please unmount the BE before mounting it again.\n"),
		    obe_name);
		break;
	case BE_ERR_PERM:
	case BE_ERR_ACCESS:
		err = 1;
		(void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
		(void) fprintf(stderr, _("You have insufficient privileges to "
		    "execute this command.\n"));
		break;
	default:
		err = 1;
		(void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
	}

out:
	if (tmp_mp != NULL)
		free(tmp_mp);
	nvlist_free(be_attrs);
	return (err);
}
Beispiel #17
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, FM_EREPORT_ZFS_CONFIG_SYNC);
}
Beispiel #18
0
static int
be_do_unmount(int argc, char **argv)
{
	nvlist_t	*be_attrs;
	char		*obe_name;
	int		err = 1;
	int		c;
	int		unmount_flags = 0;

	while ((c = getopt(argc, argv, "f")) != -1) {
		switch (c) {
		case 'f':
			unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
			break;
		default:
			usage();
			return (1);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1) {
		usage();
		return (1);
	}

	obe_name = argv[0];

	if (be_nvl_alloc(&be_attrs) != 0)
		return (1);


	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
		goto out;

	if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
	    unmount_flags) != 0)
		goto out;

	err = be_unmount(be_attrs);

	switch (err) {
	case BE_SUCCESS:
		(void) printf(_("Unmounted successfully\n"));
		break;
	case BE_ERR_BE_NOENT:
		(void) fprintf(stderr, _("%s does not exist or appear "
		    "to be a valid BE.\nPlease check that the name of "
		    "the BE provided is correct.\n"), obe_name);
		break;
	case BE_ERR_UMOUNT_CURR_BE:
		(void) fprintf(stderr, _("%s is the currently active BE.\n"
		    "It cannot be unmounted unless another BE is the "
		    "currently active BE.\n"), obe_name);
		break;
	case BE_ERR_UMOUNT_SHARED:
		(void) fprintf(stderr, _("%s is a shared file system and it "
		    "cannot be unmounted.\n"), obe_name);
		break;
	case BE_ERR_PERM:
	case BE_ERR_ACCESS:
		(void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
		(void) fprintf(stderr, _("You have insufficient privileges to "
		    "execute this command.\n"));
		break;
	default:
		(void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
	}

out:
	nvlist_free(be_attrs);
	return (err);
}
Beispiel #19
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;

	error = dsl_dir_open(ddname, FTAG, &startdd, NULL);
	if (error)
		return (error);

	dp = startdd->dd_pool;
	mos = dp->dp_meta_objset;

	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) {
		zap_cursor_t basezc;
		zap_attribute_t baseza;
		nvlist_t *sp_nvp;
		uint64_t n;
		char source[MAXNAMELEN];

		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)) {
			zap_cursor_t zc;
			zap_attribute_t za;
			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);

	dsl_dir_close(startdd, FTAG);
	return (0);
}
Beispiel #20
0
static int
be_do_rollback(int argc, char **argv)
{
	nvlist_t	*be_attrs;
	char		*obe_name;
	char		*snap_name;
	int		err = 1;

	argc -= optind;
	argv += optind;

	if (argc < 1 || argc > 2) {
		usage();
		return (1);
	}

	obe_name = argv[0];
	if (argc == 2)
		snap_name = argv[1];
	else { /* argc == 1 */
		if ((snap_name = strrchr(obe_name, '@')) != NULL) {
			if (snap_name[1] == '\0') {
				usage();
				return (1);
			}

			snap_name[0] = '\0';
			snap_name++;
		} else {
			usage();
			return (1);
		}
	}

	if (be_nvl_alloc(&be_attrs) != 0)
		return (1);

	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
		goto out;

	if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
		goto out;

	err = be_rollback(be_attrs);

	switch (err) {
	case BE_SUCCESS:
		(void) printf(_("Rolled back successfully\n"));
		break;
	case BE_ERR_BE_NOENT:
		(void) fprintf(stderr, _("%s does not exist or appear "
		    "to be a valid BE.\nPlease check that the name of "
		    "the BE provided is correct.\n"), obe_name);
		break;
	case BE_ERR_SS_NOENT:
		(void) fprintf(stderr, _("%s does not exist or appear "
		    "to be a valid snapshot.\nPlease check that the name of "
		    "the snapshot provided is correct.\n"), snap_name);
		break;
	case BE_ERR_PERM:
	case BE_ERR_ACCESS:
		(void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
		    "failed.\n"), obe_name, snap_name);
		(void) fprintf(stderr, _("You have insufficient privileges to "
		    "execute this command.\n"));
		break;
	default:
		(void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
		    "failed.\n"), obe_name, snap_name);
		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
	}

out:
	nvlist_free(be_attrs);
	return (err);
}
Beispiel #21
0
/* ARGSUSED */
static int
xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    caller_context_t *ct)
{
	int error = 0;
	char *buf;
	char *domain;
	uint32_t rid;
	ssize_t size = uiop->uio_resid;
	nvlist_t *nvp;
	nvpair_t *pair = NULL;
	vnode_t *ppvp;
	xvattr_t xvattr;
	xoptattr_t *xoap = NULL;	/* Pointer to optional attributes */

	if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0)
		return (EINVAL);

	/*
	 * Validate file offset and size.
	 */
	if (uiop->uio_loffset < (offset_t)0)
		return (EINVAL);

	if (size == 0)
		return (EINVAL);

	xva_init(&xvattr);

	if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
		return (EINVAL);
	}

	/*
	 * Copy and unpack the nvlist
	 */
	buf = kmem_alloc(size, KM_SLEEP);
	if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
		return (EFAULT);
	}

	if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
		kmem_free(buf, size);
		uiop->uio_resid = size;
		return (EINVAL);
	}
	kmem_free(buf, size);

	/*
	 * Fasttrack empty writes (nvlist with no nvpairs)
	 */
	if (nvlist_next_nvpair(nvp, NULL) == 0)
		return (0);

	ppvp = gfs_file_parent(gfs_file_parent(vp));

	while (pair = nvlist_next_nvpair(nvp, pair)) {
		data_type_t type;
		f_attr_t attr;
		boolean_t value;
		uint64_t *time, *times;
		uint_t elem, nelems;
		nvlist_t *nvp_sid;
		uint8_t *scanstamp;

		/*
		 * Validate the name and type of each attribute.
		 * Log any unknown names and continue.  This will
		 * help if additional attributes are added later.
		 */
		type = nvpair_type(pair);
		if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
			cmn_err(CE_WARN, "Unknown attribute %s",
			    nvpair_name(pair));
			continue;
		}

		/*
		 * Verify nvlist type matches required type and view is OK
		 */

		if (type != attr_to_data_type(attr) ||
		    (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
			nvlist_free(nvp);
			return (EINVAL);
		}

		/*
		 * For OWNERSID/GROUPSID make sure the target
		 * file system support ephemeral ID's
		 */
		if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
		    (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
			nvlist_free(nvp);
			return (EINVAL);
		}

		/*
		 * Retrieve data from nvpair
		 */
		switch (type) {
		case DATA_TYPE_BOOLEAN_VALUE:
			if (nvpair_value_boolean_value(pair, &value)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_UINT64_ARRAY:
			if (nvpair_value_uint64_array(pair, &times, &nelems)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_NVLIST:
			if (nvpair_value_nvlist(pair, &nvp_sid)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_UINT8_ARRAY:
			if (nvpair_value_uint8_array(pair,
			    &scanstamp, &nelems)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		default:
			nvlist_free(nvp);
			return (EINVAL);
		}

		switch (attr) {
		/*
		 * If we have several similar optional attributes to
		 * process then we should do it all together here so that
		 * xoap and the requested bitmap can be set in one place.
		 */
		case F_READONLY:
			XVA_SET_REQ(&xvattr, XAT_READONLY);
			xoap->xoa_readonly = value;
			break;
		case F_HIDDEN:
			XVA_SET_REQ(&xvattr, XAT_HIDDEN);
			xoap->xoa_hidden = value;
			break;
		case F_SYSTEM:
			XVA_SET_REQ(&xvattr, XAT_SYSTEM);
			xoap->xoa_system = value;
			break;
		case F_ARCHIVE:
			XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
			xoap->xoa_archive = value;
			break;
		case F_IMMUTABLE:
			XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
			xoap->xoa_immutable = value;
			break;
		case F_NOUNLINK:
			XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
			xoap->xoa_nounlink = value;
			break;
		case F_APPENDONLY:
			XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
			xoap->xoa_appendonly = value;
			break;
		case F_NODUMP:
			XVA_SET_REQ(&xvattr, XAT_NODUMP);
			xoap->xoa_nodump = value;
			break;
		case F_AV_QUARANTINED:
			XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
			xoap->xoa_av_quarantined = value;
			break;
		case F_AV_MODIFIED:
			XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
			xoap->xoa_av_modified = value;
			break;
		case F_CRTIME:
			XVA_SET_REQ(&xvattr, XAT_CREATETIME);
			time = (uint64_t *)&(xoap->xoa_createtime);
			for (elem = 0; elem < nelems; elem++)
				*time++ = times[elem];
			break;
		case F_OWNERSID:
		case F_GROUPSID:
			if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
			    &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
			    &rid)) {
				nvlist_free(nvp);
				return (EINVAL);
			}

			/*
			 * Now map domain+rid to ephemeral id's
			 *
			 * If mapping fails, then the uid/gid will
			 * be set to UID_NOBODY by Winchester.
			 */

			if (attr == F_OWNERSID) {
				(void) kidmap_getuidbysid(crgetzone(cr), domain,
				    rid, &xvattr.xva_vattr.va_uid);
				xvattr.xva_vattr.va_mask |= AT_UID;
			} else {
				(void) kidmap_getgidbysid(crgetzone(cr), domain,
				    rid, &xvattr.xva_vattr.va_gid);
				xvattr.xva_vattr.va_mask |= AT_GID;
			}
			break;
		case F_AV_SCANSTAMP:
			if (ppvp->v_type == VREG) {
				XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
				(void) memcpy(xoap->xoa_av_scanstamp,
				    scanstamp, nelems);
			} else {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case F_REPARSE:
			XVA_SET_REQ(&xvattr, XAT_REPARSE);
			xoap->xoa_reparse = value;
			break;
		case F_OFFLINE:
			XVA_SET_REQ(&xvattr, XAT_OFFLINE);
			xoap->xoa_offline = value;
			break;
		case F_SPARSE:
			XVA_SET_REQ(&xvattr, XAT_SPARSE);
			xoap->xoa_sparse = value;
			break;
		default:
			break;
		}
	}

	ppvp = gfs_file_parent(gfs_file_parent(vp));
	error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
	if (error)
		uiop->uio_resid = size;

	nvlist_free(nvp);
	return (error);
}
Beispiel #22
0
static int
be_do_create(int argc, char **argv)
{
	nvlist_t	*be_attrs;
	nvlist_t	*zfs_props = NULL;
	boolean_t	activate = B_FALSE;
	boolean_t	is_snap = B_FALSE;
	int		c;
	int		err = 1;
	char		*obe_name = NULL;
	char		*snap_name = NULL;
	char		*nbe_zpool = NULL;
	char		*nbe_name = NULL;
	char		*nbe_desc = NULL;
	char		*propname = NULL;
	char		*propval = NULL;
	char		*strval = NULL;

	while ((c = getopt(argc, argv, "ad:e:io:p:")) != -1) {
		switch (c) {
		case 'a':
			activate = B_TRUE;
			break;
		case 'd':
			nbe_desc = optarg;
			break;
		case 'e':
			obe_name = optarg;
			break;
		case 'o':
			if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
				return (1);

			propname = optarg;
			if ((propval = strchr(propname, '=')) == NULL) {
				(void) fprintf(stderr, _("missing "
				    "'=' for -o option\n"));
				goto out2;
			}
			*propval = '\0';
			propval++;
			if (nvlist_lookup_string(zfs_props, propname,
			    &strval) == 0) {
				(void) fprintf(stderr, _("property '%s' "
				    "specified multiple times\n"), propname);
				goto out2;

			}
			if (be_nvl_add_string(zfs_props, propname, propval)
			    != 0)
				goto out2;

			break;
		case 'p':
			nbe_zpool = optarg;
			break;
		default:
			usage();
			goto out2;
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1) {
		usage();
		goto out2;
	}

	nbe_name = argv[0];

	if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
		if (snap_name[1] == '\0') {
			usage();
			goto out2;
		}

		snap_name[0] = '\0';
		snap_name++;
		is_snap = B_TRUE;
	}

	if (obe_name) {
		if (is_snap) {
			usage();
			goto out2;
		}

		/*
		 * Check if obe_name is really a snapshot name.
		 * If so, split it out.
		 */
		if ((snap_name = strrchr(obe_name, '@')) != NULL) {
			if (snap_name[1] == '\0') {
				usage();
				goto out2;
			}

			snap_name[0] = '\0';
			snap_name++;
		}
	} else if (is_snap) {
		obe_name = nbe_name;
		nbe_name = NULL;
	}

	if (be_nvl_alloc(&be_attrs) != 0)
		goto out2;


	if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
	    BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
		goto out;

	if (obe_name != NULL && be_nvl_add_string(be_attrs,
	    BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
		goto out;

	if (snap_name != NULL && be_nvl_add_string(be_attrs,
	    BE_ATTR_SNAP_NAME, snap_name) != 0)
		goto out;

	if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
	    BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
		goto out;

	if (nbe_name != NULL && be_nvl_add_string(be_attrs,
	    BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
		goto out;

	if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
	    BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
		goto out;

	if (is_snap)
		err = be_create_snapshot(be_attrs);
	else
		err = be_copy(be_attrs);

	switch (err) {
	case BE_SUCCESS:
		if (!is_snap && !nbe_name) {
			/*
			 * We requested an auto named BE; find out the
			 * name of the BE that was created for us and
			 * the auto snapshot created from the original BE.
			 */
			if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
			    &nbe_name) != 0) {
				(void) fprintf(stderr, _("failed to get %s "
				    "attribute\n"), BE_ATTR_NEW_BE_NAME);
				break;
			} else
				(void) printf(_("Auto named BE: %s\n"),
				    nbe_name);

			if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
			    &snap_name) != 0) {
				(void) fprintf(stderr, _("failed to get %s "
				    "attribute\n"), BE_ATTR_SNAP_NAME);
				break;
			} else
				(void) printf(_("Auto named snapshot: %s\n"),
				    snap_name);
		}

		if (!is_snap && activate) {
			char *args[] = { "activate", "", NULL };
			args[1] = nbe_name;
			optind = 1;

			err = be_do_activate(2, args);
			goto out;
		}

		(void) printf(_("Created successfully\n"));
		break;
	case BE_ERR_BE_EXISTS:
		(void) fprintf(stderr, _("BE %s already exists\n."
		    "Please choose a different BE name.\n"), nbe_name);
		break;
	case BE_ERR_SS_EXISTS:
		(void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
		    "Please choose a different snapshot name.\n"), obe_name,
		    snap_name);
		break;
	case BE_ERR_PERM:
	case BE_ERR_ACCESS:
		if (is_snap)
			(void) fprintf(stderr, _("Unable to create snapshot "
			    "%s.\n"), snap_name);
		else
			(void) fprintf(stderr, _("Unable to create %s.\n"),
			    nbe_name);
		(void) fprintf(stderr, _("You have insufficient privileges to "
		    "execute this command.\n"));
		break;
	default:
		if (is_snap)
			(void) fprintf(stderr, _("Unable to create snapshot "
			    "%s.\n"), snap_name);
		else
			(void) fprintf(stderr, _("Unable to create %s.\n"),
			    nbe_name);
		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
	}

out:
	nvlist_free(be_attrs);
out2:
	if (zfs_props != NULL)
		nvlist_free(zfs_props);

	return (err);
}
Beispiel #23
0
/*
 * Synchronize pool configuration to disk.  This must be called with the
 * namespace lock held. Synchronizing the pool cache is typically done after
 * the configuration has been synced to the MOS. This exposes a window where
 * the MOS config will have been updated but the cache file has not. If
 * the system were to crash at that instant then the cached config may not
 * contain the correct information to open the pool and an explicit import
 * would be required.
 */
void
spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
{
	spa_config_dirent_t *dp, *tdp;
	nvlist_t *nvl;
	char *pool_name;
	boolean_t ccw_failure;
	int error = 0;

	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.
	 */
	ccw_failure = B_FALSE;
	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) {
			/*
			 * Skip over our own pool if we're about to remove
			 * ourselves from the spa namespace or any pool that
			 * is readonly. Since we cannot guarantee that a
			 * readonly pool would successfully import upon reboot,
			 * we don't allow them to be written to the cache file.
			 */
			if ((spa == target && removing) ||
			    !spa_writeable(spa))
				continue;

			mutex_enter(&spa->spa_props_lock);
			tdp = list_head(&spa->spa_config_list);
			if (spa->spa_config == NULL ||
			    tdp == NULL ||
			    tdp->scd_path == NULL ||
			    strcmp(tdp->scd_path, dp->scd_path) != 0) {
				mutex_exit(&spa->spa_props_lock);
				continue;
			}

			if (nvl == NULL)
				nvl = fnvlist_alloc();

			if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME)
				pool_name = fnvlist_lookup_string(
				    spa->spa_config, ZPOOL_CONFIG_POOL_NAME);
			else
				pool_name = spa_name(spa);

			fnvlist_add_nvlist(nvl, pool_name, spa->spa_config);
			mutex_exit(&spa->spa_props_lock);
		}

		error = spa_config_write(dp, nvl);
		if (error != 0)
			ccw_failure = B_TRUE;
		nvlist_free(nvl);
	}

	if (ccw_failure) {
		/*
		 * Keep trying so that configuration data is
		 * written if/when any temporary filesystem
		 * resource issues are resolved.
		 */
		if (target->spa_ccw_fail_time == 0) {
			zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
			    target, NULL, NULL, 0, 0);
		}
		target->spa_ccw_fail_time = gethrtime();
		spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
	} else {
		/*
		 * Do not rate limit future attempts to update
		 * the config cache.
		 */
		target->spa_ccw_fail_time = 0;
	}

	/*
	 * 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);
}
Beispiel #24
0
static int
be_do_destroy(int argc, char **argv)
{
	nvlist_t	*be_attrs;
	boolean_t	is_snap = B_FALSE;
	boolean_t	suppress_prompt = B_FALSE;
	int		err = 1;
	int		c;
	int		destroy_flags = 0;
	char		*snap_name;
	char		*be_name;

	while ((c = getopt(argc, argv, "fFs")) != -1) {
		switch (c) {
		case 'f':
			destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
			break;
		case 's':
			destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
			break;
		case 'F':
			suppress_prompt = B_TRUE;
			break;
		default:
			usage();
			return (1);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1) {
		usage();
		return (1);
	}

	be_name = argv[0];
	if (!suppress_prompt && !confirm_destroy(be_name)) {
		(void) printf(_("%s has not been destroyed.\n"), be_name);
		return (0);
	}

	if ((snap_name = strrchr(be_name, '@')) != NULL) {
		if (snap_name[1] == '\0') {
			usage();
			return (1);
		}

		is_snap = B_TRUE;
		*snap_name = '\0';
		snap_name++;
	}

	if (be_nvl_alloc(&be_attrs) != 0)
		return (1);


	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
		goto out;

	if (is_snap) {
		if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
		    snap_name) != 0)
			goto out;

		err = be_destroy_snapshot(be_attrs);
	} else {
		if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
		    destroy_flags) != 0)
			goto out;

		err = be_destroy(be_attrs);
	}

	switch (err) {
	case BE_SUCCESS:
		(void) printf(_("Destroyed successfully\n"));
		break;
	case BE_ERR_MOUNTED:
		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
		(void) fprintf(stderr, _("It is currently mounted and must be "
		    "unmounted before it can be destroyed.\n" "Use 'beadm "
		    "unmount %s' to unmount the BE before destroying\nit or "
		    "'beadm destroy -f %s'.\n"), be_name, be_name);
		break;
	case BE_ERR_DESTROY_CURR_BE:
		(void) fprintf(stderr, _("%s is the currently active BE and "
		    "cannot be destroyed.\nYou must boot from another BE in "
		    "order to destroy %s.\n"), be_name, be_name);
		break;
	case BE_ERR_ZONES_UNMOUNT:
		(void) fprintf(stderr, _("Unable to destroy one of " "%s's "
		    "zone BE's.\nUse 'beadm destroy -f %s' or "
		    "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
		break;
	case BE_ERR_SS_NOENT:
		(void) fprintf(stderr, _("%s does not exist or appear "
		    "to be a valid snapshot.\nPlease check that the name of "
		    "the snapshot provided is correct.\n"), snap_name);
		break;
	case BE_ERR_PERM:
	case BE_ERR_ACCESS:
		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
		(void) fprintf(stderr, _("You have insufficient privileges to "
		    "execute this command.\n"));
		break;
	case BE_ERR_SS_EXISTS:
		(void) fprintf(stderr, _("Unable to destroy %s: "
		    "BE has snapshots.\nUse 'beadm destroy -s %s' or "
		    "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
		break;
	default:
		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
	}

out:
	nvlist_free(be_attrs);
	return (err);
}
Beispiel #25
0
/*
 * Our approach to cases is the same as for resources: we first obtain a
 * list of UUIDs, sort them, then obtain the case information for each.
 */
int
fmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func,
    void *arg)
{
	struct fmd_rpc_caselist rcl;
	struct fmd_rpc_caseinfo rci;
	fmd_adm_caseinfo_t aci;
	char **uuids, *p;
	int i, rv;
	enum clnt_stat cs;
	uint_t retries = 0;

	bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */

	do {
		cs = fmd_adm_caselist_1(&rcl, ap->adm_clnt);
	} while (fmd_adm_retry(ap, cs, &retries));

	if (cs != RPC_SUCCESS)
		return (fmd_adm_set_errno(ap, EPROTO));

	if (rcl.rcl_err != 0) {
		xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
		return (fmd_adm_set_svcerr(ap, rcl.rcl_err));
	}

	if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) {
		xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
		return (fmd_adm_set_errno(ap, EAGAIN));
	}

	p = rcl.rcl_buf.rcl_buf_val;

	for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1)
		uuids[i] = p;

	qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp);

	for (i = 0; i < rcl.rcl_cnt; i++) {
		bzero(&rci, sizeof (rci));

		retries = 0;
		do {
			cs = fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt);
		} while (fmd_adm_retry(ap, cs, &retries));

		if (cs != RPC_SUCCESS) {
			free(uuids);
			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
			return (fmd_adm_set_errno(ap, EPROTO));
		}

		if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) {
			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
			free(uuids);
			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
			return (fmd_adm_set_svcerr(ap, rci.rci_err));
		}

		if (rci.rci_err == FMD_ADM_ERR_CASESRCH) {
			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
			continue;
		}

		bzero(&aci, sizeof (aci));

		if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val,
		    rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) {
			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
			free(uuids);
			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
			return (fmd_adm_set_errno(ap, rv));
		}

		if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID,
		    (char **)&aci.aci_uuid)) != 0) {
			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
			free(uuids);
			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
			nvlist_free(aci.aci_event);
			return (fmd_adm_set_errno(ap, rv));
		}
		if ((rv = nvlist_lookup_string(aci.aci_event,
		    FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) {
			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
			free(uuids);
			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
			nvlist_free(aci.aci_event);
			return (fmd_adm_set_errno(ap, rv));
		}

		rv = fmd_adm_case_one(&aci, url_token, func, arg);

		xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
		nvlist_free(aci.aci_event);

		if (rv != 0)
			break;
	}

	free(uuids);
	xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
	return (0);
}
Beispiel #26
0
/*
 * Create the storage dirs, and pass the path list to the kernel.
 * This requires the nfssrv module to be loaded; the _nfssys() syscall
 * will fail ENOTSUP if it is not.
 * Use libnvpair(3LIB) to pass the data to the kernel.
 */
static int
dss_init(uint_t npaths, char **pathnames)
{
	int i, j, nskipped, error;
	char *bufp;
	uint32_t bufsize;
	size_t buflen;
	nvlist_t *nvl;

	if (npaths > 1) {
		/*
		 * We need to remove duplicate paths; this might be user error
		 * in the general case, but HA-NFSv4 can also cause this.
		 * Sort the pathnames array, and NULL out duplicates,
		 * then write the non-NULL entries to a new array.
		 * Sorting will also allow the kernel to optimise its searches.
		 */

		qsort(pathnames, npaths, sizeof (char *), qstrcmp);

		/* now NULL out any duplicates */
		i = 0; j = 1; nskipped = 0;
		while (j < npaths) {
			if (strcmp(pathnames[i], pathnames[j]) == NULL) {
				pathnames[j] = NULL;
				j++;
				nskipped++;
				continue;
			}

			/* skip i over any of its NULLed duplicates */
			i = j++;
		}

		/* finally, write the non-NULL entries to a new array */
		if (nskipped > 0) {
			int nreal;
			size_t sz;
			char **tmp_pathnames;

			nreal = npaths - nskipped;

			sz = nreal * sizeof (char *);
			tmp_pathnames = (char **)malloc(sz);
			if (tmp_pathnames == NULL) {
				fprintf(stderr, "tmp_pathnames malloc "
				    "failed\n");
				exit(1);
			}

			for (i = 0, j = 0; i < npaths; i++)
				if (pathnames[i] != NULL)
					tmp_pathnames[j++] = pathnames[i];
			free(pathnames);
			pathnames = tmp_pathnames;
			npaths = nreal;
		}

	}

	/* Create directories to store the distributed state files */
	dss_mkleafdirs(npaths, pathnames);

	/* Create the name-value pair list */
	error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
	if (error) {
		fprintf(stderr, "nvlist_alloc failed: %s\n", strerror(errno));
		return (1);
	}

	/* Add the pathnames array as a single name-value pair */
	error = nvlist_add_string_array(nvl, NFS4_DSS_NVPAIR_NAME,
	    pathnames, npaths);
	if (error) {
		fprintf(stderr, "nvlist_add_string_array failed: %s\n",
		    strerror(errno));
		nvlist_free(nvl);
		return (1);
	}

	/*
	 * Pack list into contiguous memory, for passing to kernel.
	 * nvlist_pack() will allocate the memory for the buffer,
	 * which we should free() when no longer needed.
	 * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary.
	 */
	bufp = NULL;
	error = nvlist_pack(nvl, &bufp, &buflen, NV_ENCODE_XDR, 0);
	if (error) {
		fprintf(stderr, "nvlist_pack failed: %s\n", strerror(errno));
		nvlist_free(nvl);
		return (1);
	}

	/* Now we have the packed buffer, we no longer need the list */
	nvlist_free(nvl);

	/*
	 * Let the kernel know in advance how big the buffer is.
	 * NOTE: we cannot just pass buflen, since size_t is a long, and
	 * thus a different size between ILP32 userland and LP64 kernel.
	 * Use an int for the transfer, since that should be big enough;
	 * this is a no-op at the moment, here, since nfsd is 32-bit, but
	 * that could change.
	 */
	bufsize = (uint32_t)buflen;
	error = _nfssys(NFS4_DSS_SETPATHS_SIZE, &bufsize);
	if (error) {
		fprintf(stderr,
		    "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s\n",
		    strerror(errno));
		free(bufp);
		return (1);
	}

	/* Pass the packed buffer to the kernel */
	error = _nfssys(NFS4_DSS_SETPATHS, bufp);
	if (error) {
		fprintf(stderr,
		    "_nfssys(NFS4_DSS_SETPATHS) failed: %s\n", strerror(errno));
		free(bufp);
		return (1);
	}

	/*
	 * The kernel has now unpacked the buffer and extracted the
	 * pathnames array, we no longer need the buffer.
	 */
	free(bufp);

	return (0);
}
Beispiel #27
0
/*
 * Generate the pool's configuration based on the current in-core state.
 *
 * We infer whether to generate a complete config or just one top-level config
 * based on whether vd is the root vdev.
 */
nvlist_t *
spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
{
	nvlist_t *config, *nvroot;
	vdev_t *rvd = spa->spa_root_vdev;
	unsigned long hostid = 0;
	boolean_t locked = B_FALSE;
	uint64_t split_guid;
	char *pool_name;

	if (vd == NULL) {
		vd = rvd;
		locked = B_TRUE;
		spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER);
	}

	ASSERT(spa_config_held(spa, SCL_CONFIG | SCL_STATE, RW_READER) ==
	    (SCL_CONFIG | SCL_STATE));

	/*
	 * If txg is -1, report the current value of spa->spa_config_txg.
	 */
	if (txg == -1ULL)
		txg = spa->spa_config_txg;

	/*
	 * Originally, users had to handle spa namespace collisions by either
	 * exporting the already imported pool or by specifying a new name for
	 * the pool with a conflicting name. In the case of root pools from
	 * virtual guests, neither approach to collision resolution is
	 * reasonable. This is addressed by extending the new name syntax with
	 * an option to specify that the new name is temporary. When specified,
	 * ZFS_IMPORT_TEMP_NAME will be set in spa->spa_import_flags to tell us
	 * to use the previous name, which we do below.
	 */
	if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
		VERIFY0(nvlist_lookup_string(spa->spa_config,
			ZPOOL_CONFIG_POOL_NAME, &pool_name));
	} else
		pool_name = spa_name(spa);

	VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);

	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
	    spa_version(spa)) == 0);
	VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
	    pool_name) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
	    spa_state(spa)) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG,
	    txg) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
	    spa_guid(spa)) == 0);
	VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA,
	    spa->spa_errata) == 0);
	VERIFY(spa->spa_comment == NULL || nvlist_add_string(config,
	    ZPOOL_CONFIG_COMMENT, spa->spa_comment) == 0);


#ifdef	_KERNEL
	hostid = zone_get_hostid(NULL);
#else	/* _KERNEL */
	/*
	 * We're emulating the system's hostid in userland, so we can't use
	 * zone_get_hostid().
	 */
	(void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
#endif	/* _KERNEL */
	if (hostid != 0) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
		    hostid) == 0);
	}
	VERIFY0(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
	    utsname()->nodename));

	if (vd != rvd) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
		    vd->vdev_top->vdev_guid) == 0);
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
		    vd->vdev_guid) == 0);
		if (vd->vdev_isspare)
			VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE,
			    1ULL) == 0);
		if (vd->vdev_islog)
			VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG,
			    1ULL) == 0);
		vd = vd->vdev_top;		/* label contains top config */
	} else {
		/*
		 * Only add the (potentially large) split information
		 * in the mos config, and not in the vdev labels
		 */
		if (spa->spa_config_splitting != NULL)
			VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
			    spa->spa_config_splitting) == 0);
	}

	/*
	 * Add the top-level config.  We even add this on pools which
	 * don't support holes in the namespace.
	 */
	vdev_top_config_generate(spa, config);

	/*
	 * If we're splitting, record the original pool's guid.
	 */
	if (spa->spa_config_splitting != NULL &&
	    nvlist_lookup_uint64(spa->spa_config_splitting,
	    ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
		VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID,
		    split_guid) == 0);
	}

	nvroot = vdev_config_generate(spa, vd, getstats, 0);
	VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
	nvlist_free(nvroot);

	/*
	 * Store what's necessary for reading the MOS in the label.
	 */
	VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
	    spa->spa_label_features) == 0);

	if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
		ddt_histogram_t *ddh;
		ddt_stat_t *dds;
		ddt_object_t *ddo;

		ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
		ddt_get_dedup_histogram(spa, ddh);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_HISTOGRAM,
		    (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t)) == 0);
		kmem_free(ddh, sizeof (ddt_histogram_t));

		ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
		ddt_get_dedup_object_stats(spa, ddo);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_OBJ_STATS,
		    (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t)) == 0);
		kmem_free(ddo, sizeof (ddt_object_t));

		dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
		ddt_get_dedup_stats(spa, dds);
		VERIFY(nvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_STATS,
		    (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t)) == 0);
		kmem_free(dds, sizeof (ddt_stat_t));
	}

	if (locked)
		spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);

	return (config);
}
Beispiel #28
0
/*ARGSUSED*/
static int
ASRU_set(tnode_t *tn, did_t *pd,
    const char *dpnm, const char *tpgrp, const char *tpnm)
{
	topo_mod_t *mp;
	nvlist_t *fmri;
	char *dnpath, *path, *fpath, *nm;
	int d, e, f;

	/*
	 * If this topology node represents a function of device,
	 * set the ASRU to a dev scheme FMRI based on the value of
	 * di_devfs_path().  If that path is NULL, set the ASRU to
	 * be the resource describing this topology node.  If this
	 * isn't a function, inherit any ASRU from the parent.
	 */
	mp = did_mod(pd);
	nm = topo_node_name(tn);
	if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) &&
	    strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) ||
	    strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 ||
	    strcmp(nm, PCIEX_ROOT) == 0) {
		if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) {
			/*
			 * Dup the path, dev_path_fix() may replace it and
			 * dev_path_fix() wouldn't know to use
			 * di_devfs_path_free()
			 */
			if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
				di_devfs_path_free(dnpath);
				return (topo_mod_seterrno(mp, EMOD_NOMEM));
			}
			di_devfs_path_free(dnpath);
			did_BDF(pd, NULL, &d, &f);
			if ((fpath = dev_path_fix(mp, path, d, f)) == NULL)
				return (topo_mod_seterrno(mp, EMOD_NOMEM));

			fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
			    fpath, NULL);
			if (fmri == NULL) {
				topo_mod_dprintf(mp,
				    "dev:///%s fmri creation failed.\n", fpath);
				topo_mod_strfree(mp, fpath);
				return (-1);
			}
			topo_mod_strfree(mp, fpath);
		} else {
			topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
			if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
			    TOPO_PROP_RESOURCE, &fmri, &e) < 0)
				return (topo_mod_seterrno(mp, e));
		}
		if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
			nvlist_free(fmri);
			return (topo_mod_seterrno(mp, e));
		}
		nvlist_free(fmri);
		return (0);
	}
	(void) topo_node_asru_set(tn, NULL, 0, &e);

	return (0);
}
Beispiel #29
0
static void
zpool_open_func(void *arg)
{
	rdsk_node_t *rn = arg;
#ifdef __APPLE__
	struct stat statbuf;
#else
	struct stat64 statbuf;
#endif
	nvlist_t *config;
	int num_labels;
	int fd;

	if (rn->rn_nozpool)
		return;
#if defined (__linux__) || defined (__APPLE__)
	/*
	 * Skip devices with well known prefixes there can be side effects
	 * when opening devices which need to be avoided.
	 *
	 * core     - Symlink to /proc/kcore
	 * fd*      - Floppy interface.
	 * fuse     - Fuse control device.
	 * hpet     - High Precision Event Timer
	 * lp*      - Printer interface.
	 * parport* - Parallel port interface.
	 * ppp      - Generic PPP driver.
	 * random   - Random device
	 * rtc      - Real Time Clock
	 * tty*     - Generic serial interface.
	 * urandom  - Random device.
	 * usbmon*  - USB IO monitor.
	 * vcs*     - Virtual console memory.
	 * watchdog - Watchdog must be closed in a special way.
	 */
	if ((strncmp(rn->rn_name, "core", 4) == 0) ||
	    (strncmp(rn->rn_name, "fd", 2) == 0) ||
	    (strncmp(rn->rn_name, "fuse", 4) == 0) ||
	    (strncmp(rn->rn_name, "hpet", 4) == 0) ||
	    (strncmp(rn->rn_name, "lp", 2) == 0) ||
	    (strncmp(rn->rn_name, "parport", 7) == 0) ||
	    (strncmp(rn->rn_name, "ppp", 3) == 0) ||
	    (strncmp(rn->rn_name, "random", 6) == 0) ||
	    (strncmp(rn->rn_name, "rtc", 3) == 0) ||
	    (strncmp(rn->rn_name, "tty", 3) == 0) ||
	    (strncmp(rn->rn_name, "urandom", 7) == 0) ||
	    (strncmp(rn->rn_name, "usbmon", 6) == 0) ||
	    (strncmp(rn->rn_name, "vcs", 3) == 0) ||
#ifdef __APPLE__
		(strncmp(rn->rn_name, "pty", 3) == 0) || // lots, skip for speed
		(strncmp(rn->rn_name, "com", 3) == 0) || // /dev/com_digidesign_semiface
#endif
	    (strncmp(rn->rn_name, "watchdog", 8) == 0))
		return;

	/*
	 * Ignore failed stats.  We only want regular files and block devices.
	 */
	if (fstatat64(rn->rn_dfd, rn->rn_name, &statbuf, 0) != 0 ||
	    (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode)))
		return;

#ifdef __APPLE__
	/* It is desirable to skip optical media as well, as they are
	 * also called /dev/diskX
	 */
	if (is_optical_media((char *)rn->rn_name))
		return;
#endif

	if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
		/* symlink to a device that's no longer there */
		if (errno == ENOENT)
			nozpool_all_slices(rn->rn_avl, rn->rn_name);
		return;
	}

#else /* LINUX, APPLE -> IllumOS */

	if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
		/* symlink to a device that's no longer there */
		if (errno == ENOENT)
			nozpool_all_slices(rn->rn_avl, rn->rn_name);
		return;
	}
	/*
	 * Ignore failed stats.  We only want regular
	 * files, character devs and block devs.
	 */
	if (fstat64(fd, &statbuf) != 0 ||
	    (!S_ISREG(statbuf.st_mode) &&
	    !S_ISCHR(statbuf.st_mode) &&
	    !S_ISBLK(statbuf.st_mode))) {
		(void) close(fd);
		return;
	}
#endif
	/* this file is too small to hold a zpool */
	if (S_ISREG(statbuf.st_mode) &&
	    statbuf.st_size < SPA_MINDEVSIZE) {
		(void) close(fd);
		return;
	} else if (!S_ISREG(statbuf.st_mode)) {
		/*
		 * Try to read the disk label first so we don't have to
		 * open a bunch of minor nodes that can't have a zpool.
		 */
		check_slices(rn->rn_avl, fd, rn->rn_name);
	}

#ifdef __APPLE__
	int32_t blksz = 0;
	if (S_ISBLK(statbuf.st_mode) &&
		(ioctl(fd, DKIOCGETBLOCKSIZE, &blksz) || blksz == 0)) {
		if (strncmp(rn->rn_name, "vn", 2) != 0)
			fprintf(stderr, "device '%s' failed to report blocksize -- skipping\r\n",
					rn->rn_name);
		close(fd);
		return;
	}

	struct sigaction sact;
	sigemptyset(&sact.sa_mask);
	sact.sa_flags = 0;
	sact.sa_handler = signal_alarm;
	sigaction(SIGALRM, &sact, NULL);

	if (setjmp(buffer) != 0) {
		printf("ZFS: Warning, timeout reading device '%s'\n", rn->rn_name);
		close(fd);
		return;
	}

	alarm(20);
#endif

	if ((zpool_read_label(fd, &config, &num_labels)) != 0) {
#ifdef __APPLE__
		alarm(0);
#endif
		(void) close(fd);
		(void) no_memory(rn->rn_hdl);
		return;
	}

#ifdef __APPLE__
	alarm(0);
#endif

	if (num_labels == 0) {
		(void) close(fd);
		nvlist_free(config);
		return;
	}

	(void) close(fd);

	rn->rn_config = config;
	rn->rn_num_labels = num_labels;
}
Beispiel #30
0
static int
lzc_ioctl(zfs_ioc_t ioc, const char *name,
    nvlist_t *source, nvlist_t **resultp)
{
	zfs_cmd_t zc = { 0 };
	int error = 0;
	char *packed;
#ifdef __FreeBSD__
	nvlist_t *oldsource;
#endif
	size_t size;

	ASSERT3S(g_refcount, >, 0);

	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));

#ifdef __FreeBSD__
	if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
		zfs_ioctl_version = get_zfs_ioctl_version();

	if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
		oldsource = source;
		error = lzc_compat_pre(&zc, &ioc, &source);
		if (error)
			return (error);
	}
#endif

	packed = fnvlist_pack(source, &size);
	zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
	zc.zc_nvlist_src_size = size;

	if (resultp != NULL) {
		*resultp = NULL;
		zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
		zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
		    malloc(zc.zc_nvlist_dst_size);
#ifdef illumos
		if (zc.zc_nvlist_dst == NULL) {
#else
		if (zc.zc_nvlist_dst == 0) {
#endif
			error = ENOMEM;
			goto out;
		}
	}

	while (ioctl(g_fd, ioc, &zc) != 0) {
		if (errno == ENOMEM && resultp != NULL) {
			free((void *)(uintptr_t)zc.zc_nvlist_dst);
			zc.zc_nvlist_dst_size *= 2;
			zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
			    malloc(zc.zc_nvlist_dst_size);
#ifdef illumos
			if (zc.zc_nvlist_dst == NULL) {
#else
			if (zc.zc_nvlist_dst == 0) {
#endif
				error = ENOMEM;
				goto out;
			}
		} else {
			error = errno;
			break;
		}
	}

#ifdef __FreeBSD__
	if (zfs_ioctl_version < ZFS_IOCVER_LZC)
		lzc_compat_post(&zc, ioc);
#endif
	if (zc.zc_nvlist_dst_filled) {
		*resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
		    zc.zc_nvlist_dst_size);
	}
#ifdef __FreeBSD__
	if (zfs_ioctl_version < ZFS_IOCVER_LZC)
		lzc_compat_outnvl(&zc, ioc, resultp);
#endif
out:
#ifdef __FreeBSD__
	if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
		if (source != oldsource)
			nvlist_free(source);
		source = oldsource;
	}
#endif
	fnvlist_pack_free(packed, size);
	free((void *)(uintptr_t)zc.zc_nvlist_dst);
	return (error);
}

int
lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props)
{
	int error;
	nvlist_t *args = fnvlist_alloc();
	fnvlist_add_int32(args, "type", (dmu_objset_type_t)type);
	if (props != NULL)
		fnvlist_add_nvlist(args, "props", props);
	error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
	nvlist_free(args);
	return (error);
}