Esempio n. 1
0
File: zfs_sa.c Progetto: avg-I/zfs
int
zfs_sa_set_xattr(znode_t *zp)
{
    zfs_sb_t *zsb = ZTOZSB(zp);
    dmu_tx_t *tx;
    char *obj;
    size_t size;
    int error;

    ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
    ASSERT(zp->z_xattr_cached);
    ASSERT(zp->z_is_sa);

    error = nvlist_size(zp->z_xattr_cached, &size, NV_ENCODE_XDR);
    if (error)
        goto out;

    obj = zio_buf_alloc(size);

    error = nvlist_pack(zp->z_xattr_cached, &obj, &size,
                        NV_ENCODE_XDR, KM_SLEEP);
    if (error)
        goto out_free;

    tx = dmu_tx_create(zsb->z_os);
    dmu_tx_hold_sa_create(tx, size);
    dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);

    error = dmu_tx_assign(tx, TXG_WAIT);
    if (error) {
        dmu_tx_abort(tx);
    } else {
        error = sa_update(zp->z_sa_hdl, SA_ZPL_DXATTR(zsb),
                          obj, size, tx);
        if (error)
            dmu_tx_abort(tx);
        else
            dmu_tx_commit(tx);
    }
out_free:
    zio_buf_free(obj, size);
out:
    return (error);
}
Esempio n. 2
0
static int
pci_iov_get_schema_ioctl(struct cdev *cdev, struct pci_iov_schema *output)
{
	struct pci_devinfo *dinfo;
	void *packed;
	size_t output_len, size;
	int error;

	packed = NULL;

	mtx_lock(&Giant);
	dinfo = cdev->si_drv1;
	packed = nvlist_pack(dinfo->cfg.iov->iov_schema, &size);
	mtx_unlock(&Giant);

	if (packed == NULL) {
		error = ENOMEM;
		goto fail;
	}

	output_len = output->len;
	output->len = size;
	if (size <= output_len) {
		error = copyout(packed, output->schema, size);

		if (error != 0)
			goto fail;

		output->error = 0;
	} else
		/*
		 * If we return an error then the ioctl code won't copyout
		 * output back to userland, so we flag the error in the struct
		 * instead.
		 */
		output->error = EMSGSIZE;

	error = 0;

fail:
	free(packed, M_NVLIST);

	return (error);
}
Esempio n. 3
0
int
zfs_sa_set_xattr(znode_t *zp)
{
	zfsvfs_t *zfsvfs = ZTOZSB(zp);
	dmu_tx_t *tx;
	char *obj;
	size_t size;
	int error;

	ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
	ASSERT(zp->z_xattr_cached);
	ASSERT(zp->z_is_sa);

	error = nvlist_size(zp->z_xattr_cached, &size, NV_ENCODE_XDR);
	if ((error == 0) && (size > SA_ATTR_MAX_LEN))
		error = EFBIG;
	if (error)
		goto out;

	obj = vmem_alloc(size, KM_SLEEP);

	error = nvlist_pack(zp->z_xattr_cached, &obj, &size,
	    NV_ENCODE_XDR, KM_SLEEP);
	if (error)
		goto out_free;

	tx = dmu_tx_create(zfsvfs->z_os);
	dmu_tx_hold_sa_create(tx, size);
	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);

	error = dmu_tx_assign(tx, TXG_WAIT);
	if (error) {
		dmu_tx_abort(tx);
	} else {
		VERIFY0(sa_update(zp->z_sa_hdl, SA_ZPL_DXATTR(zfsvfs),
		    obj, size, tx));
		dmu_tx_commit(tx);
	}
out_free:
	vmem_free(obj, size);
out:
	return (error);
}
Esempio n. 4
0
int
zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl,
    size_t *size)
{
	char *packed;
	size_t len;

	verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);

	if ((packed = zfs_alloc(hdl, len)) == NULL)
		return (-1);

	verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);

	zc->zc_nvlist_src = (uint64_t)(uintptr_t)packed;
	zc->zc_nvlist_src_size = len;

	if (size)
		*size = len;
	return (0);
}
Esempio n. 5
0
static PyObject *
py_set_fsacl(PyObject *self, PyObject *args)
{
	int un;
	size_t nvsz;
	zfs_cmd_t zc = { 0 };
	char *name, *nvbuf;
	PyObject *dict, *file;
	nvlist_t *nvl;
	int err;

	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
	    &PyDict_Type, &dict))
		return (NULL);

	nvl = dict2nvl(dict);
	if (nvl == NULL)
		return (NULL);

	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
	assert(err == 0);
	nvbuf = malloc(nvsz);
	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
	assert(err == 0);

	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
	zc.zc_nvlist_src_size = nvsz;
	zc.zc_nvlist_src = (uintptr_t)nvbuf;
	zc.zc_perm_action = un;

	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
	free(nvbuf);
	if (err) {
		seterr(_("cannot set permissions on %s"), name);
		return (NULL);
	}

	Py_RETURN_NONE;
}
Esempio n. 6
0
/*
 * This function posts the incoming piclevent
 * It packs the nvlist and posts it to PICL
 */
static void
parse_piclevent(nvlist_t *nvlp)
{
	char		*enval;
	char		*ename;
	size_t		nvl_size;
	char		*packed_nvl;
	int		err;

	if (nvlist_lookup_string(nvlp, PICLEVENTARG_EVENT_NAME, &enval))
		return;

	packed_nvl = NULL;
	if (nvlist_pack(nvlp, &packed_nvl, &nvl_size, NV_ENCODE_NATIVE, NULL))
		return;

	ename = strdup(enval);
	if (ename == NULL) {
		free(packed_nvl);
		return;
	}

	if (piclevent_debug) {
		syslog(LOG_INFO, "piclevent: posting ename:%s packed_nvl:%p "
		    "nvl_size:0x%x\n", ename, packed_nvl, nvl_size);
	}
	err = ptree_post_event(ename, packed_nvl, nvl_size,
	    piclevent_completion_handler);

	if (err != PICL_SUCCESS) {
		if (piclevent_debug)
			syslog(LOG_INFO,
			    "piclevent: posting ename:%s failed err:%d\n",
			    ename, err);
		free(ename);
		free(packed_nvl);
	}
}
Esempio n. 7
0
static int
ippctl_add_nvlist(
	nvlist_t	*nvlp,
	int		i)
{
	char		*buf;
	size_t		buflen;
	int		rc;

	/*
	 * NULL the buffer pointer so that a buffer is automatically
	 * allocated for us.
	 */

	buf = NULL;

	/*
	 * Pack the nvlist and get back the buffer pointer and length.
	 */

	if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE,
	    KM_SLEEP)) != 0) {
		ippctl_array[i].buf = NULL;
		ippctl_array[i].buflen = 0;
		return (rc);
	}

	DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen);

	/*
	 * Store the pointer an length in the array at the given index.
	 */

	ippctl_array[i].buf = buf;
	ippctl_array[i].buflen = buflen;

	return (0);
}
Esempio n. 8
0
int
smb_kmod_unshare(nvlist_t *shrlist)
{
	smb_ioc_share_t *ioc;
	uint32_t ioclen;
	char *shrbuf = NULL;
	size_t bufsz;
	int rc = ENOMEM;

	if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0)
		return (rc);

	ioclen = sizeof (smb_ioc_share_t) + bufsz;

	if ((ioc = malloc(ioclen)) != NULL) {
		ioc->shrlen = bufsz;
		bcopy(shrbuf, ioc->shr, bufsz);
		rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr, ioclen);
		free(ioc);
	}

	free(shrbuf);
	return (rc);
}
Esempio n. 9
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);
}
Esempio n. 10
0
/*
 * Create the named pool, using the provided vdev list.  It is assumed
 * that the consumer has already validated the contents of the nvlist, so we
 * don't have to worry about error semantics.
 */
int
zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
    const char *altroot)
{
	zfs_cmd_t zc = { 0 };
	char *packed;
	size_t len;
	char msg[1024];

	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
	    "cannot create '%s'"), pool);

	if (!zpool_name_valid(hdl, B_FALSE, pool))
		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));

	if (altroot != NULL && altroot[0] != '/')
		return (zfs_error(hdl, EZFS_BADPATH,
		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot));

	if (nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) != 0)
		return (no_memory(hdl));

	if ((packed = zfs_alloc(hdl, len)) == NULL)
		return (-1);

	if (nvlist_pack(nvroot, &packed, &len,
	    NV_ENCODE_NATIVE, 0) != 0) {
		free(packed);
		return (no_memory(hdl));
	}

	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
	zc.zc_config_src = (uint64_t)(uintptr_t)packed;
	zc.zc_config_src_size = len;

	if (altroot != NULL)
		(void) strlcpy(zc.zc_root, altroot, sizeof (zc.zc_root));

	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) {
		free(packed);

		switch (errno) {
		case EBUSY:
			/*
			 * This can happen if the user has specified the same
			 * device multiple times.  We can't reliably detect this
			 * until we try to add it and see we already have a
			 * label.
			 */
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "one or more vdevs refer to the same device"));
			return (zfs_error(hdl, EZFS_BADDEV, msg));

		case EOVERFLOW:
			/*
			 * This occurs when one of the devices is below
			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
			 * device was the problem device since there's no
			 * reliable way to determine device size from userland.
			 */
			{
				char buf[64];

				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));

				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
				    "one or more devices is less than the "
				    "minimum size (%s)"), buf);
			}
			return (zfs_error(hdl, EZFS_BADDEV, msg));

		case ENOSPC:
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "one or more devices is out of space"));
			return (zfs_error(hdl, EZFS_BADDEV, msg));

		default:
			return (zpool_standard_error(hdl, errno, msg));
		}
	}

	free(packed);

	/*
	 * If this is an alternate root pool, then we automatically set the
	 * moutnpoint of the root dataset to be '/'.
	 */
	if (altroot != NULL) {
		zfs_handle_t *zhp;

		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL);
		verify(zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, "/") == 0);

		zfs_close(zhp);
	}

	return (0);
}
Esempio n. 11
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 */
}
Esempio n. 12
0
static void
spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
{
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	int error;
	char *temp;

	/*
	 * If the nvlist is empty (NULL), then remove the old cachefile.
	 */
	if (nvl == NULL) {
		(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
		return;
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);

	buf = vmem_alloc(buflen, KM_SLEEP);
	temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);

	VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

#if defined(__linux__) && defined(_KERNEL)
	/*
	 * Write the configuration to disk.  Due to the complexity involved
	 * in performing a rename from within the kernel the file is truncated
	 * and overwritten in place.  In the event of an error the file is
	 * unlinked to make sure we always have a consistent view of the data.
	 */
	error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
	if (error == 0) {
		error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
		    UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL);
		if (error == 0)
			error = VOP_FSYNC(vp, FSYNC, kcred, NULL);

		(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);

		if (error)
			(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
	}
#else
	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);

	error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
	if (error == 0) {
		if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
		    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
		    VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
			(void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
		}
		(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
	}

	(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
#endif

	vmem_free(buf, buflen);
	kmem_free(temp, MAXPATHLEN);
}
Esempio n. 13
0
int
main(int argc, char **argv)
{
	struct stat cachestat;
	int mapfd = 0;
	int rv = 0;
	char *ondiskbuf;
	size_t newsz = 0;

	parse_args(argc, argv);
	errno = 0;
	devinfo_root = di_init("/", DINFOCPYALL|DINFOFORCE);
	logmsg(MSG_INFO, "errno = %d after "
	    "di_init(/,DINFOCPYALL|DINFOFORCE)\n", errno);
	if (devinfo_root == NULL) {
		logmsg(MSG_ERROR,
		    gettext("Unable to take device tree snapshot "
		    "(%s: %d)\n"), strerror(errno), errno);
		return (-1);
	}
	logmsg(MSG_INFO, "opened root di_node\n");

	if (globarg == MPX_CAPABLE_CTRL) {
		/* we just want to find MPxIO-capable controllers and exit */
		if (drvlimit != NULL) {
			print_mpx_capable(di_drv_first_node(drvlimit,
			    devinfo_root));
		} else {
			print_mpx_capable(di_drv_first_node("fp",
			    devinfo_root));
			print_mpx_capable(di_drv_first_node("mpt",
			    devinfo_root));
			print_mpx_capable(di_drv_first_node("mpt_sas",
			    devinfo_root));
			print_mpx_capable(di_drv_first_node("pmcs",
			    devinfo_root));
		}
		di_fini(devinfo_root);
		return (0);
	}

	mapfd = open(ondiskname, O_RDWR|O_CREAT|O_SYNC, S_IRUSR | S_IWUSR);
	if (mapfd < 0) {
		/* we could be in single-user, so try for RO */
		if ((mapfd = open(ondiskname, O_RDONLY)) < 0) {
			logmsg(MSG_ERROR,
			    gettext("Unable to open or create %s:%s\n"),
			    ondiskname, strerror(errno));
			return (errno);
		}
		readonlyroot = 1;
	}

	if (stat(ondiskname, &cachestat) != 0) {
		logmsg(MSG_ERROR,
		    gettext("Unable to stat() %s: %s\n"),
		    ondiskname, strerror(errno));
		return (errno);
	}
	ondiskbuf = calloc(1, cachestat.st_size);
	if (ondiskbuf == NULL) {
		logmsg(MSG_ERROR,
		    gettext("Unable to allocate memory for the devid "
		    "cache file: %s\n"), strerror(errno));
		return (errno);
	}
	rv = read(mapfd, ondiskbuf, cachestat.st_size);
	if (rv != cachestat.st_size) {
		logmsg(MSG_ERROR,
		    gettext("Unable to read all of devid cache file (got %d "
		    "from expected %d bytes): %s\n"),
		    rv, cachestat.st_size, strerror(errno));
		return (errno);
	}
	errno = 0;
	rv = nvlist_unpack(ondiskbuf, cachestat.st_size, &mapnvl, 0);
	if (rv) {
		logmsg(MSG_INFO,
		    "Unable to unpack devid cache file %s: %s (%d)\n",
		    ondiskname, strerror(rv), rv);
		if (nvlist_alloc(&mapnvl, NV_UNIQUE_NAME, 0) != 0) {
			logmsg(MSG_ERROR,
			    gettext("Unable to allocate root property"
			    "list\n"));
			return (errno);
		}
	}
	free(ondiskbuf);

	if (validate_devnvl() < 0) {
		logmsg(MSG_ERROR,
		    gettext("unable to validate kernel with on-disk devid "
		    "cache file\n"));
		return (errno);
	}

	/*
	 * If we're in single-user mode or maintenance mode, we won't
	 * necessarily have a writable root device (ZFSroot; ufs root is
	 * different in that we _do_ have a writable root device.
	 * This causes problems for the devlink calls (see
	 * $SRC/lib/libdevinfo/devinfo_devlink.c) and we do not try to
	 * write out the devnvl if root is readonly.
	 */
	if (!readonlyroot) {
		rv = nvlist_size(mapnvl, &newsz, NV_ENCODE_NATIVE);
		if (rv) {
			logmsg(MSG_ERROR,
			    gettext("Unable to determine size of packed "
			    "on-disk devid cache file %s: %s (%d).\n"),
			    ondiskname, strerror(rv), rv);
			logmsg(MSG_ERROR, gettext("Terminating\n"));
			nvlist_free(mapnvl);
			(void) close(mapfd);
			return (rv);
		}

		if ((ondiskbuf = calloc(1, newsz)) == NULL) {
			logmsg(MSG_ERROR,
			    "Unable to allocate space for writing out new "
			    "on-disk devid cache file: %s\n", strerror(errno));
			(void) close(mapfd);
			nvlist_free(mapnvl);
			return (errno);
		}

		rv = nvlist_pack(mapnvl, &ondiskbuf, &newsz,
		    NV_ENCODE_NATIVE, 0);
		if (rv) {
			logmsg(MSG_ERROR,
			    gettext("Unable to pack on-disk devid cache "
			    "file: %s (%d)\n"), strerror(rv), rv);
			(void) close(mapfd);
			free(ondiskbuf);
			nvlist_free(mapnvl);
			return (rv);
		}

		rv = lseek(mapfd, 0, 0);
		if (rv == -1) {
			logmsg(MSG_ERROR,
			    gettext("Unable to seek to start of devid cache "
			    "file: %s (%d)\n"), strerror(errno), errno);
			(void) close(mapfd);
			free(ondiskbuf);
			nvlist_free(mapnvl);
			return (-1);
		}

		if (write(mapfd, ondiskbuf, newsz) != newsz) {
			logmsg(MSG_ERROR,
			    gettext("Unable to completely write out "
			    "on-disk devid cache file: %s\n"), strerror(errno));
			(void) close(mapfd);
			nvlist_free(mapnvl);
			free(ondiskbuf);
			return (errno);
		}
	} /* !readonlyroot */

	/* Now we can process the command line args */
	if (globarg == MPX_PHYSICAL) {
		report_map(devicep, BOOT);
	} else if (globarg == MPX_BOOTPATH) {
		rv = print_bootpath();
		di_fini(devinfo_root);
		return (rv);
	} else if (globarg == MPX_UPDATEVFSTAB) {
		rv = update_vfstab();
		di_fini(devinfo_root);
		return (rv);
	} else if (globarg == MPX_GETPATH) {
		report_dev_node_name(devicep);
	} else if (globarg == MPX_DEV_PATH) {
		report_map(devicep, BOOT_PATH);
	} else if (globarg != MPX_INIT) {
		if (globarg & MPX_LIST)
			list_devs(guid, limctrl);

		if (globarg == MPX_MAP)
			report_map(devicep, NONBOOT);
	} else {
		logmsg(MSG_INFO, "\nprivate devid cache file initialised\n");
	}

	nvlist_free(mapnvl);
	di_fini(devinfo_root);
	return (0);
}
Esempio n. 14
0
int
fwrite_nvlist(char *filename, nvlist_t *nvl)
{
	char	*buf;
	char	*nvbuf;
	kfile_t	*fp;
	char	*newname;
	int	len, err, err1;
	size_t	buflen;
	ssize_t	n;

	ASSERT(modrootloaded);

	nvbuf = NULL;
	err = nvlist_pack(nvl, &nvbuf, &buflen, NV_ENCODE_NATIVE, 0);
	if (err != 0) {
		KFIOERR((CE_CONT, "%s: error %d packing nvlist\n",
			filename, err));
		return (err);
	}

	buf = kmem_alloc(sizeof (nvpf_hdr_t) + buflen, KM_SLEEP);
	bzero(buf, sizeof (nvpf_hdr_t));

	((nvpf_hdr_t *)buf)->nvpf_magic = NVPF_HDR_MAGIC;
	((nvpf_hdr_t *)buf)->nvpf_version = NVPF_HDR_VERSION;
	((nvpf_hdr_t *)buf)->nvpf_size = buflen;
	((nvpf_hdr_t *)buf)->nvpf_chksum = nvp_cksum((uchar_t *)nvbuf, buflen);
	((nvpf_hdr_t *)buf)->nvpf_hdr_chksum =
		nvp_cksum((uchar_t *)buf, sizeof (nvpf_hdr_t));

	bcopy(nvbuf, buf + sizeof (nvpf_hdr_t), buflen);
	kmem_free(nvbuf, buflen);
	buflen += sizeof (nvpf_hdr_t);

	len = strlen(filename) + MAX_SUFFIX_LEN + 2;
	newname = kmem_alloc(len, KM_SLEEP);


	(void) sprintf(newname, "%s.%s",
		filename, NEW_FILENAME_SUFFIX);

	/*
	 * To make it unlikely we suffer data loss, write
	 * data to the new temporary file.  Once successful
	 * complete the transaction by renaming the new file
	 * to replace the previous.
	 */

	if ((err = kfcreate(newname, &fp)) == 0) {
		err = kfwrite(fp, buf, buflen, &n);
		if (err) {
			KFIOERR((CE_CONT, "%s: write error - %d\n",
				newname, err));
		} else {
			if (n != buflen) {
				KFIOERR((CE_CONT,
				    "%s: partial write %ld of %ld bytes\n",
				    newname, n, buflen));
				KFIOERR((CE_CONT,
				    "%s: filesystem may be full?\n", newname));
				err = EIO;
			}
		}
		if ((err1 = kfclose(fp)) != 0) {
			KFIOERR((CE_CONT, "%s: close error\n", newname));
			if (err == 0)
				err = err1;
		}
		if (err != 0) {
			if (kfremove(newname) != 0) {
				KFIOERR((CE_CONT, "%s: remove failed\n",
				    newname));
			}
		}
	} else {
		KFIOERR((CE_CONT, "%s: create failed - %d\n",
			filename, err));
	}

	if (err == 0) {
		if ((err = kfrename(newname, filename)) != 0) {
			KFIOERR((CE_CONT, "%s: rename from %s failed\n",
				newname, filename));
		}
	}

	kmem_free(newname, len);
	kmem_free(buf, buflen);

	return (err);
}
Esempio n. 15
0
/*
 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
 * interface configuration (interface properties and addresses), for all those
 * interfaces that need to be initialized.
 */
static void
ipmgmt_initif_handler(void *argp)
{
	ipmgmt_initif_arg_t	*initif = argp;
	size_t			buflen, nvlsize;
	char			*buf = NULL, *onvlbuf, *invlbuf;
	ipmgmt_get_rval_t	rval, *rvalp = &rval;
	ipmgmt_initif_cbarg_t	cbarg;
	int			err;

	assert(initif->ia_cmd == IPMGMT_CMD_INITIF);

	bzero(&cbarg, sizeof (cbarg));
	invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
	nvlsize = initif->ia_nvlsize;
	err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
	if (err != 0)
		goto fail;

	cbarg.cb_family = initif->ia_family;
	if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
		goto fail;

	err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
	if (err == ENOENT && cbarg.cb_ocnt > 0) {
		/*
		 * If there is atleast one entry in the nvlist,
		 * do not return error.
		 */
		err = 0;
	}
	if (err != 0)
		goto fail;

	if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
		goto fail;
	buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
	/*
	 * We cannot use malloc() here because door_return never returns, and
	 * memory allocated by malloc() would get leaked. Use alloca() instead.
	 */
	buf = alloca(buflen);
	onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
	if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
	    NV_ENCODE_NATIVE, 0)) != 0) {
		goto fail;
	}
	nvlist_free(cbarg.cb_invl);
	nvlist_free(cbarg.cb_onvl);
	rvalp = (ipmgmt_get_rval_t *)(void *)buf;
	rvalp->ir_err = 0;
	rvalp->ir_nvlsize = nvlsize;

	(void) door_return(buf, buflen, NULL, 0);
	return;
fail:
	nvlist_free(cbarg.cb_invl);
	nvlist_free(cbarg.cb_onvl);
	rvalp->ir_err = err;
	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
}
Esempio n. 16
0
/*
 * Attach new_disk (fully described by nvroot) to old_disk.
 * If 'replacing' is specified, tne new disk will replace the old one.
 */
int
zpool_vdev_attach(zpool_handle_t *zhp,
    const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	char *packed;
	int ret;
	size_t len;
	nvlist_t *tgt;
	boolean_t avail_spare;
	uint64_t val;
	char *path;
	nvlist_t **child;
	uint_t children;
	nvlist_t *config_root;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	if (replacing)
		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
		    "cannot replace %s with %s"), old_disk, new_disk);
	else
		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
		    "cannot attach %s to %s"), new_disk, old_disk);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	if (avail_spare)
		return (zfs_error(hdl, EZFS_ISSPARE, msg));

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
	zc.zc_cookie = replacing;

	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) != 0 || children != 1) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "new device must be a single disk"));
		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
	}

	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);

	/*
	 * If the target is a hot spare that has been swapped in, we can only
	 * replace it with another hot spare.
	 */
	if (replacing &&
	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
	    (zpool_find_vdev(zhp, path, &avail_spare) == NULL ||
	    !avail_spare) && is_replacing_spare(config_root, tgt, 1)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "can only be replaced by another hot spare"));
		return (zfs_error(hdl, EZFS_BADTARGET, msg));
	}

	/*
	 * If we are attempting to replace a spare, it canot be applied to an
	 * already spared device.
	 */
	if (replacing &&
	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
	    zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare &&
	    is_replacing_spare(config_root, tgt, 0)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "device has already been replaced with a spare"));
		return (zfs_error(hdl, EZFS_BADTARGET, msg));
	}

	verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);

	if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
		return (-1);

	verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);

	zc.zc_config_src = (uint64_t)(uintptr_t)packed;
	zc.zc_config_src_size = len;

	ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);

	free(packed);

	if (ret == 0)
		return (0);

	switch (errno) {
	case ENOTSUP:
		/*
		 * Can't attach to or replace this type of vdev.
		 */
		if (replacing)
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "cannot replace a replacing device"));
		else
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "can only attach to mirrors and top-level "
			    "disks"));
		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
		break;

	case EINVAL:
		/*
		 * The new device must be a single disk.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "new device must be a single disk"));
		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
		break;

	case EBUSY:
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
		    new_disk);
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case EOVERFLOW:
		/*
		 * The new device is too small.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "device is too small"));
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case EDOM:
		/*
		 * The new device has a different alignment requirement.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "devices have different sector alignment"));
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case ENAMETOOLONG:
		/*
		 * The resulting top-level vdev spec won't fit in the label.
		 */
		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
		break;

	default:
		(void) zpool_standard_error(hdl, errno, msg);
	}

	return (-1);
}
Esempio n. 17
0
/*
 * Synchronize all pools to disk.  This must be called with the namespace lock
 * held.
 */
void
spa_config_sync(void)
{
	spa_t *spa = NULL;
	nvlist_t *config;
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	char pathname[128];
	char pathname2[128];

	ASSERT(MUTEX_HELD(&spa_namespace_lock));

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

	/*
	 * Add all known pools to the configuration list, ignoring those with
	 * alternate root paths.
	 */
	spa = NULL;
	while ((spa = spa_next(spa)) != NULL) {
		mutex_enter(&spa->spa_config_cache_lock);
		if (spa->spa_config && spa->spa_name && spa->spa_root == NULL)
			VERIFY(nvlist_add_nvlist(config, spa->spa_name,
			    spa->spa_config) == 0);
		mutex_exit(&spa->spa_config_cache_lock);
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(config, &buflen, NV_ENCODE_XDR) == 0);

	buf = kmem_alloc(buflen, KM_SLEEP);

	VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(pathname, sizeof (pathname), "%s/%s", spa_config_dir,
	    ZPOOL_CACHE_TMP);

	if (vn_open(pathname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0)
		goto out;

	if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
	    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
	    VOP_FSYNC(vp, FSYNC, kcred) == 0) {
		(void) snprintf(pathname2, sizeof (pathname2), "%s/%s",
		    spa_config_dir, ZPOOL_CACHE_FILE);
		(void) vn_rename(pathname, pathname2, UIO_SYSSPACE);
	}

	(void) VOP_CLOSE(vp, oflags, 1, 0, kcred);
	VN_RELE(vp);

out:
	(void) vn_remove(pathname, UIO_SYSSPACE, RMFILE);
	spa_config_generation++;

	kmem_free(buf, buflen);
	nvlist_free(config);
}
Esempio n. 18
0
static void
spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
{
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	char tempname[128];

	/*
	 * If the nvlist is empty (NULL), then remove the old cachefile.
	 */
	if (nvl == NULL) {
		(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
		return;
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);

	buf = kmem_alloc(buflen, KM_SLEEP);

	VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

#ifdef __APPLE_KERNEL__
	/*
	 * OS X - since vn_rename() and vn_remove() are both missing from
	 * the KPI, we have to just write over the existing file!  Since
	 * the OS X cache file only contains pools that are built from
	 * file VDEVs, this cache file should be small.
	 */
	(void) snprintf(tempname, sizeof (tempname), "%s", dp->scd_path);
#else
	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(tempname, sizeof (tempname), "%s.tmp", dp->scd_path);
#endif

	if (vn_open(tempname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0)
		goto out;

	if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
	    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
	    VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
		(void) vn_rename(tempname, dp->scd_path, UIO_SYSSPACE);
	}

	(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
#ifndef __APPLE__
	VN_RELE(vp);
#endif
out:
	(void) vn_remove(tempname, UIO_SYSSPACE, RMFILE);
	kmem_free(buf, buflen);
}
Esempio n. 19
0
/*ARGSUSED*/
static int
fm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
{
	char *buf;
	int err;
	uint_t model;
	const fm_subr_t *subr;
	uint32_t vers;
	fm_ioc_data_t fid;
	nvlist_t *invl = NULL, *onvl = NULL;
#ifdef _MULTI_DATAMODEL
	fm_ioc_data32_t fid32;
#endif

	if (getminor(dev) != 0)
		return (ENXIO);

	for (subr = fm_subrs; subr->cmd != cmd; subr++)
		if (subr->cmd == -1)
			return (ENOTTY);

	if (subr->priv && (flag & FWRITE) == 0 &&
	    secpolicy_sys_config(CRED(), 0) != 0)
		return (EPERM);

	model = ddi_model_convert_from(flag & FMODELS);

	switch (model) {
#ifdef _MULTI_DATAMODEL
	case DDI_MODEL_ILP32:
		if (ddi_copyin((void *)data, &fid32,
		    sizeof (fm_ioc_data32_t), flag) != 0)
			return (EFAULT);
		fid.fid_version = fid32.fid_version;
		fid.fid_insz = fid32.fid_insz;
		fid.fid_inbuf = (caddr_t)(uintptr_t)fid32.fid_inbuf;
		fid.fid_outsz = fid32.fid_outsz;
		fid.fid_outbuf = (caddr_t)(uintptr_t)fid32.fid_outbuf;
		break;
#endif /* _MULTI_DATAMODEL */
	case DDI_MODEL_NONE:
	default:
		if (ddi_copyin((void *)data, &fid, sizeof (fm_ioc_data_t),
		    flag) != 0)
			return (EFAULT);
	}

	if (nvlist_lookup_uint32(fm_vers_nvl, subr->version, &vers) != 0 ||
	    fid.fid_version != vers)
		return (ENOTSUP);

	if (fid.fid_insz > FM_IOC_MAXBUFSZ)
		return (ENAMETOOLONG);
	if (fid.fid_outsz > FM_IOC_OUT_MAXBUFSZ)
		return (EINVAL);

	/*
	 * Copy in and unpack the input nvlist.
	 */
	if (fid.fid_insz != 0 && fid.fid_inbuf != (caddr_t)0) {
		buf = kmem_alloc(fid.fid_insz, KM_SLEEP);
		if (ddi_copyin(fid.fid_inbuf, buf, fid.fid_insz, flag) != 0) {
			kmem_free(buf, fid.fid_insz);
			return (EFAULT);
		}
		err = nvlist_unpack(buf, fid.fid_insz, &invl, KM_SLEEP);
		kmem_free(buf, fid.fid_insz);
		if (err != 0)
			return (err);
	}

	err = subr->func(cmd, invl, &onvl);

	if (invl != NULL)
		nvlist_free(invl);

	if (err != 0) {
		if (onvl != NULL)
			nvlist_free(onvl);
		return (err);
	}

	/*
	 * If the output nvlist contains any data, pack it and copyout.
	 */
	if (onvl != NULL) {
		size_t sz;

		if ((err = nvlist_size(onvl, &sz, NV_ENCODE_NATIVE)) != 0) {
			nvlist_free(onvl);
			return (err);
		}
		if (sz > fid.fid_outsz) {
			nvlist_free(onvl);
			return (ENAMETOOLONG);
		}

		buf = kmem_alloc(sz, KM_SLEEP);
		if ((err = nvlist_pack(onvl, &buf, &sz, NV_ENCODE_NATIVE,
		    KM_SLEEP)) != 0) {
			kmem_free(buf, sz);
			nvlist_free(onvl);
			return (err);
		}
		nvlist_free(onvl);
		if (ddi_copyout(buf, fid.fid_outbuf, sz, flag) != 0) {
			kmem_free(buf, sz);
			return (EFAULT);
		}
		kmem_free(buf, sz);
		fid.fid_outsz = sz;

		switch (model) {
#ifdef _MULTI_DATAMODEL
		case DDI_MODEL_ILP32:
			fid32.fid_outsz = (size32_t)fid.fid_outsz;
			if (ddi_copyout(&fid32, (void *)data,
			    sizeof (fm_ioc_data32_t), flag) != 0)
				return (EFAULT);
			break;
#endif /* _MULTI_DATAMODEL */
		case DDI_MODEL_NONE:
		default:
			if (ddi_copyout(&fid, (void *)data,
			    sizeof (fm_ioc_data_t), flag) != 0)
				return (EFAULT);
		}
	}

	return (err);
}
Esempio n. 20
0
/*
 * Take a snapshot of the current state of processor sets and CPUs,
 * pack it in the exacct format, and attach it to specified exacct record.
 */
int
pool_pset_pack(ea_object_t *eo_system)
{
	ea_object_t *eo_pset, *eo_cpu;
	cpupart_t *cpupart;
	psetid_t mypsetid;
	pool_pset_t *pset;
	nvlist_t *nvl;
	size_t bufsz;
	cpu_t *cpu;
	char *buf;
	int ncpu;

	ASSERT(pool_lock_held());

	mutex_enter(&cpu_lock);
	mypsetid = zone_pset_get(curproc->p_zone);
	for (pset = list_head(&pool_pset_list); pset;
	    pset = list_next(&pool_pset_list, pset)) {
		psetid_t psetid = pset->pset_id;

		if (!INGLOBALZONE(curproc) && mypsetid != psetid)
			continue;
		cpupart = cpupart_find(psetid);
		ASSERT(cpupart != NULL);
		eo_pset = ea_alloc_group(EXT_GROUP |
		    EXC_LOCAL | EXD_GROUP_PSET);
		(void) ea_attach_item(eo_pset, &psetid, sizeof (id_t),
		    EXC_LOCAL | EXD_PSET_PSETID | EXT_UINT32);
		/*
		 * Pack info for all CPUs in this processor set.
		 */
		ncpu = 0;
		cpu = cpu_list;
		do {
			if (cpu->cpu_part != cpupart)	/* not our pset */
				continue;
			ncpu++;
			eo_cpu = ea_alloc_group(EXT_GROUP
			    | EXC_LOCAL | EXD_GROUP_CPU);
			(void) ea_attach_item(eo_cpu, &cpu->cpu_id,
			    sizeof (processorid_t),
			    EXC_LOCAL | EXD_CPU_CPUID | EXT_UINT32);
			if (cpu->cpu_props == NULL) {
				(void) nvlist_alloc(&cpu->cpu_props,
				    NV_UNIQUE_NAME, KM_SLEEP);
				(void) nvlist_add_string(cpu->cpu_props,
				    "cpu.comment", "");
			}
			(void) nvlist_dup(cpu->cpu_props, &nvl, KM_SLEEP);
			(void) nvlist_add_int64(nvl, "cpu.sys_id", cpu->cpu_id);
			(void) nvlist_add_string(nvl, "cpu.status",
			    (char *)cpu_get_state_str(cpu));
			buf = NULL;
			bufsz = 0;
			(void) nvlist_pack(nvl, &buf, &bufsz,
			    NV_ENCODE_NATIVE, 0);
			(void) ea_attach_item(eo_cpu, buf, bufsz,
			    EXC_LOCAL | EXD_CPU_PROP | EXT_RAW);
			(void) nvlist_free(nvl);
			kmem_free(buf, bufsz);
			(void) ea_attach_to_group(eo_pset, eo_cpu);
		} while ((cpu = cpu->cpu_next) != cpu_list);

		(void) nvlist_dup(pset->pset_props, &nvl, KM_SLEEP);
		(void) nvlist_add_uint64(nvl, "pset.size", ncpu);
		(void) nvlist_add_uint64(nvl, "pset.load",
		    (uint64_t)PSET_LOAD(cpupart->cp_hp_avenrun[0]));
		buf = NULL;
		bufsz = 0;
		(void) nvlist_pack(nvl, &buf, &bufsz, NV_ENCODE_NATIVE, 0);
		(void) ea_attach_item(eo_pset, buf, bufsz,
		    EXC_LOCAL | EXD_PSET_PROP | EXT_RAW);
		(void) nvlist_free(nvl);
		kmem_free(buf, bufsz);

		(void) ea_attach_to_group(eo_system, eo_pset);
	}
	mutex_exit(&cpu_lock);
	return (0);
}
Esempio n. 21
0
/*ARGSUSED*/
static void
door_service(void *cookie, char *args, size_t alen,
    door_desc_t *ddp, uint_t ndid)
{
	nvlist_t *nvl;
	size_t nvl_size = 0;
	char rbuf[BUF_THRESHOLD];
	door_cookie_t *cook = (door_cookie_t *)cookie;
	uint64_t seq_num = 0;

	/*
	 * Special case for asking to free buffer
	 */
	if (alen == sizeof (uint64_t)) {
		free_door_result(cookie, *(uint64_t *)(void *)args);
		(void) door_return(NULL, 0, NULL, 0);
	}

	/*
	 * door_func update args to point to return results.
	 * memory for results are dynamically allocated.
	 */
	(*cook->door_func)((void **)&args, &alen);

	/*
	 * If no results, just return
	 */
	if (args == NULL) {
		dprint("null results returned from door_func().\n");
		(void) door_return(NULL, 0, NULL, 0);
	}

	/* Determine the size of the packed nvlist */
	nvl = (nvlist_t *)(void *)args;
	args = NULL;
	alen = 0;
	if (errno = nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE)) {
		nvlist_free(nvl);
		dprint("failure to sizeup door results: %s\n", strerror(errno));
		(void) door_return(NULL, 0, NULL, 0);
	}

	/*
	 * If the size of the packed nvlist would exceed the buffer threshold
	 * then get a sequence number and add it to the nvlist.
	 */
	if (nvl_size > BUF_THRESHOLD) {
		(void) mutex_lock(&cook->door_lock);
		cook->seq_num++;
		seq_num = cook->seq_num;
		(void) mutex_unlock(&cook->door_lock);
		(void) nvlist_add_uint64(nvl, RCM_SEQ_NUM, seq_num);
	}

	/* Refill the args with a packed version of the nvlist */
	if (errno = nvlist_pack(nvl, &args, &alen, NV_ENCODE_NATIVE, 0)) {
		nvlist_free(nvl);
		dprint("failure to pack door results: %s\n", strerror(errno));
		(void) door_return(NULL, 0, NULL, 0);
	}
	nvlist_free(nvl);

	/*
	 * Based on the size of the packed nvlist, either use the local buffer
	 * or add it to the results list.
	 */
	if (alen <= BUF_THRESHOLD) {
		bcopy(args, rbuf, alen);
		(void) free(args);
		args = rbuf;
	} else {
		/*
		 * for long data, append results to end of queue in cook
		 * and set ndid, ask client to do another door_call
		 * to free the buffer.
		 */
		add_door_result(cook, args, seq_num);
	}

	(void) door_return(args, alen, NULL, 0);
}
Esempio n. 22
0
/*
 * Add the given vdevs to the pool.  The caller must have already performed the
 * necessary verification to ensure that the vdev specification is well-formed.
 */
int
zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
{
	char *packed;
	size_t len;
	zfs_cmd_t zc;
	int ret;
	libzfs_handle_t *hdl = zhp->zpool_hdl;
	char msg[1024];
	nvlist_t **spares;
	uint_t nspares;

	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
	    "cannot add to '%s'"), zhp->zpool_name);

	if (zpool_get_version(zhp) < ZFS_VERSION_SPARES &&
	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
	    &spares, &nspares) == 0) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
		    "upgraded to add hot spares"));
		return (zfs_error(hdl, EZFS_BADVERSION, msg));
	}

	verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);

	if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
		return (-1);

	verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	zc.zc_config_src = (uint64_t)(uintptr_t)packed;
	zc.zc_config_src_size = len;

	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) {
		switch (errno) {
		case EBUSY:
			/*
			 * This can happen if the user has specified the same
			 * device multiple times.  We can't reliably detect this
			 * until we try to add it and see we already have a
			 * label.
			 */
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "one or more vdevs refer to the same device"));
			(void) zfs_error(hdl, EZFS_BADDEV, msg);
			break;

		case EOVERFLOW:
			/*
			 * This occurrs when one of the devices is below
			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
			 * device was the problem device since there's no
			 * reliable way to determine device size from userland.
			 */
			{
				char buf[64];

				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));

				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
				    "device is less than the minimum "
				    "size (%s)"), buf);
			}
			(void) zfs_error(hdl, EZFS_BADDEV, msg);
			break;

		case ENOTSUP:
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "pool must be upgraded to add raidz2 vdevs"));
			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
			break;

		default:
			(void) zpool_standard_error(hdl, errno, msg);
		}

		ret = -1;
	} else {
		ret = 0;
	}

	free(packed);

	return (ret);
}
Esempio n. 23
0
/*
 * Function:  it_config_commit()
 *
 * Informs the iscsit service that the configuration has changed and
 * commits the new configuration to persistent store by calling
 * stmfSetProviderData.  This function can be called multiple times
 * during a configuration sequence if necessary.
 *
 * Parameters:
 *    cfg	A C representation of the current iSCSI configuration
 *
 * Return Values:
 *    0		Success
 *    ENOMEM	Could not allocate resources
 *    EINVAL	Invalid it_config_t structure
 *    TBD	ioctl() failed
 *    TBD	could not save config to STMF
 */
int
it_config_commit(it_config_t *cfg)
{
	int			ret;
	nvlist_t		*cfgnv = NULL;
	char			*packednv = NULL;
	int			iscsit_fd = -1;
	size_t			pnv_size;
	iscsit_ioc_set_config_t	iop;
	it_tgt_t		*tgtp;

	if (!cfg) {
		return (EINVAL);
	}

	ret = it_config_to_nv(cfg, &cfgnv);
	if (ret == 0) {
		ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE);
	}

	/*
	 * If the iscsit service is enabled, send the changes to the
	 * kernel first.  Kernel will be the final sanity check before
	 * the config is saved persistently.
	 *
	 * This somewhat leaves open the simultaneous-change hole
	 * that STMF was trying to solve, but is a better sanity
	 * check and allows for graceful handling of target renames.
	 */
	if ((ret == 0) && is_iscsit_enabled()) {
		packednv = malloc(pnv_size);
		if (!packednv) {
			ret = ENOMEM;
		} else {
			ret = nvlist_pack(cfgnv, &packednv, &pnv_size,
			    NV_ENCODE_NATIVE, 0);
		}

		if (ret == 0) {
			iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL);
			if (iscsit_fd != -1) {
				iop.set_cfg_vers = ISCSIT_API_VERS0;
				iop.set_cfg_pnvlist = packednv;
				iop.set_cfg_pnvlist_len = pnv_size;
				if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG,
				    &iop)) != 0) {
					ret = errno;
				}

				(void) close(iscsit_fd);
			} else {
				ret = errno;
			}
		}

		if (packednv != NULL) {
			free(packednv);
		}
	}

	/*
	 * Before saving the config persistently, remove any
	 * PROP_OLD_TARGET_NAME entries.  This is only interesting to
	 * the active service.
	 */
	if (ret == 0) {
		boolean_t	changed = B_FALSE;

		tgtp = cfg->config_tgt_list;
		for (; tgtp != NULL; tgtp = tgtp->tgt_next) {
			if (!tgtp->tgt_properties) {
				continue;
			}
			if (nvlist_exists(tgtp->tgt_properties,
			    PROP_OLD_TARGET_NAME)) {
				(void) nvlist_remove_all(tgtp->tgt_properties,
				    PROP_OLD_TARGET_NAME);
				changed = B_TRUE;
			}
		}

		if (changed) {
			/* rebuild the config nvlist */
			nvlist_free(cfgnv);
			cfgnv = NULL;
			ret = it_config_to_nv(cfg, &cfgnv);
		}
	}

	/*
	 * stmfGetProviderDataProt() checks to ensure
	 * that the config data hasn't changed since we fetched it.
	 *
	 * The kernel now has a version we need to save persistently.
	 * CLI will 'do the right thing' and warn the user if it
	 * gets STMF_ERROR_PROV_DATA_STALE.  We'll try once to revert
	 * the kernel to the persistently saved data, but ultimately,
	 * it's up to the administrator to validate things are as they
	 * want them to be.
	 */
	if (ret == 0) {
		ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv,
		    STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token));

		if (ret == STMF_STATUS_SUCCESS) {
			ret = 0;
		} else if (ret == STMF_ERROR_NOMEM) {
			ret = ENOMEM;
		} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
			int		st;
			it_config_t	*rcfg = NULL;

			st = it_config_load(&rcfg);
			if (st == 0) {
				(void) it_config_commit(rcfg);
				it_config_free(rcfg);
			}
		}
	}

	if (cfgnv) {
		nvlist_free(cfgnv);
	}

	return (ret);
}
Esempio n. 24
0
/*
 * Import the given pool using the known configuration.  The configuration
 * should have come from zpool_find_import().  The 'newname' and 'altroot'
 * parameters control whether the pool is imported with a different name or with
 * an alternate root, respectively.
 */
int
zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
    const char *altroot)
{
	zfs_cmd_t zc;
	char *packed;
	size_t len;
	char *thename;
	char *origname;
	int ret;

	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
	    &origname) == 0);

	if (newname != NULL) {
		if (!zpool_name_valid(hdl, B_FALSE, newname))
			return (zfs_error(hdl, EZFS_INVALIDNAME,
			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
			    newname));
		thename = (char *)newname;
	} else {
		thename = origname;
	}

	if (altroot != NULL && altroot[0] != '/')
		return (zfs_error(hdl, EZFS_BADPATH,
		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"),
		    altroot));

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

	if (altroot != NULL)
		(void) strlcpy(zc.zc_root, altroot, sizeof (zc.zc_root));
	else
		zc.zc_root[0] = '\0';

	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
	    &zc.zc_guid) == 0);

	verify(nvlist_size(config, &len, NV_ENCODE_NATIVE) == 0);

	if ((packed = zfs_alloc(hdl, len)) == NULL)
		return (-1);

	verify(nvlist_pack(config, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);

	zc.zc_config_src = (uint64_t)(uintptr_t)packed;
	zc.zc_config_src_size = len;

	ret = 0;
	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
		char desc[1024];
		if (newname == NULL)
			(void) snprintf(desc, sizeof (desc),
			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
			    thename);
		else
			(void) snprintf(desc, sizeof (desc),
			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
			    origname, thename);

		switch (errno) {
		case ENOTSUP:
			/*
			 * Unsupported version.
			 */
			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
			break;

		case EINVAL:
			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
			break;

		default:
			(void) zpool_standard_error(hdl, errno, desc);
		}

		ret = -1;
	} else {
		zpool_handle_t *zhp;
		/*
		 * This should never fail, but play it safe anyway.
		 */
		if (zpool_open_silent(hdl, thename, &zhp) != 0) {
			ret = -1;
		} else if (zhp != NULL) {
			ret = zpool_create_zvol_links(zhp);
			zpool_close(zhp);
		}
	}

	free(packed);
	return (ret);
}
Esempio n. 25
0
/*ARGSUSED*/
static void
door_server(void *cookie, char *argp, size_t sz, door_desc_t *dp, uint_t ndesc)
{
    nvlist_t	*args = NULL;
    nvlist_t	*results = NULL;
    hp_cmd_t	cmd;
    int		rv;

    dprintf("Door call: cookie=%p, argp=%p, sz=%d\n", cookie, (void *)argp,
            sz);

    /* Special case to free a results buffer */
    if (sz == sizeof (uint64_t)) {
        free_buffer(*(uint64_t *)(uintptr_t)argp);
        (void) door_return(NULL, 0, NULL, 0);
        return;
    }

    /* Unpack the arguments nvlist */
    if (nvlist_unpack(argp, sz, &args, 0) != 0) {
        log_err("Cannot unpack door arguments.\n");
        rv = EINVAL;
        goto fail;
    }

    /* Extract the requested command */
    if (nvlist_lookup_int32(args, HPD_CMD, (int32_t *)&cmd) != 0) {
        log_err("Cannot decode door command.\n");
        rv = EINVAL;
        goto fail;
    }

    /* Implement the command */
    switch (cmd) {
    case HP_CMD_GETINFO:
        rv = cmd_getinfo(args, &results);
        break;
    case HP_CMD_CHANGESTATE:
        rv = cmd_changestate(args, &results);
        break;
    case HP_CMD_SETPRIVATE:
    case HP_CMD_GETPRIVATE:
        rv = cmd_private(cmd, args, &results);
        break;
    default:
        rv = EINVAL;
        break;
    }

    /* The arguments nvlist is no longer needed */
    nvlist_free(args);
    args = NULL;

    /*
     * If an nvlist was constructed for the results,
     * then pack the results nvlist and return it.
     */
    if (results != NULL) {
        uint64_t	seqnum;
        char		*buf = NULL;
        size_t		len = 0;

        /* Add a sequence number to the results */
        seqnum = get_seqnum();
        if (nvlist_add_uint64(results, HPD_SEQNUM, seqnum) != 0) {
            log_err("Cannot add sequence number.\n");
            rv = EFAULT;
            goto fail;
        }

        /* Pack the results nvlist */
        if (nvlist_pack(results, &buf, &len,
                        NV_ENCODE_NATIVE, 0) != 0) {
            log_err("Cannot pack door results.\n");
            rv = EFAULT;
            goto fail;
        }

        /* Link results buffer into list */
        add_buffer(seqnum, buf);

        /* The results nvlist is no longer needed */
        nvlist_free(results);

        /* Return the results */
        (void) door_return(buf, len, NULL, 0);
        return;
    }

    /* Return result code (when no nvlist) */
    (void) door_return((char *)&rv, sizeof (int), NULL, 0);
    return;

fail:
    log_err("Door call failed (%s)\n", strerror(rv));
    nvlist_free(args);
    nvlist_free(results);
    (void) door_return((char *)&rv, sizeof (int), NULL, 0);
}
Esempio n. 26
0
/*ARGSUSED*/
static void
spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
	spa_t		*spa = arg1;
	history_arg_t	*hap = arg2;
	const char	*history_str = hap->ha_history_str;
	objset_t	*mos = spa->spa_meta_objset;
	dmu_buf_t	*dbp;
	spa_history_phys_t *shpp;
	size_t		reclen;
	uint64_t	le_len;
	nvlist_t	*nvrecord;
	char		*record_packed = NULL;
	int		ret;

	/*
	 * If we have an older pool that doesn't have a command
	 * history object, create it now.
	 */
	mutex_enter(&spa->spa_history_lock);
	if (!spa->spa_history)
		spa_history_create_obj(spa, tx);
	mutex_exit(&spa->spa_history_lock);

	/*
	 * Get the offset of where we need to write via the bonus buffer.
	 * Update the offset when the write completes.
	 */
	VERIFY(0 == dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp));
	shpp = dbp->db_data;

	dmu_buf_will_dirty(dbp, tx);

#ifdef ZFS_DEBUG
	{
		dmu_object_info_t doi;
		dmu_object_info_from_db(dbp, &doi);
		ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS);
	}
#endif

	VERIFY(nvlist_alloc(&nvrecord, NV_UNIQUE_NAME, KM_SLEEP) == 0);
	VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TIME,
	    gethrestime_sec()) == 0);
	VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_WHO, hap->ha_uid) == 0);
	if (hap->ha_zone != NULL)
		VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_ZONE,
		    hap->ha_zone) == 0);
#ifdef _KERNEL
	VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_HOST,
	    utsname.nodename) == 0);
#endif
	if (hap->ha_log_type == LOG_CMD_POOL_CREATE ||
	    hap->ha_log_type == LOG_CMD_NORMAL) {
		VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_CMD,
		    history_str) == 0);

		zfs_dbgmsg("command: %s", history_str);
	} else {
		VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_INT_EVENT,
		    hap->ha_event) == 0);
		VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TXG,
		    tx->tx_txg) == 0);
		VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_INT_STR,
		    history_str) == 0);

		zfs_dbgmsg("internal %s pool:%s txg:%llu %s",
		    zfs_history_event_names[hap->ha_event], spa_name(spa),
		    (longlong_t)tx->tx_txg, history_str);

	}

	VERIFY(nvlist_size(nvrecord, &reclen, NV_ENCODE_XDR) == 0);
	record_packed = kmem_alloc(reclen, KM_SLEEP);

	VERIFY(nvlist_pack(nvrecord, &record_packed, &reclen,
	    NV_ENCODE_XDR, KM_SLEEP) == 0);

	mutex_enter(&spa->spa_history_lock);
	if (hap->ha_log_type == LOG_CMD_POOL_CREATE)
		VERIFY(shpp->sh_eof == shpp->sh_pool_create_len);

	/* write out the packed length as little endian */
	le_len = LE_64((uint64_t)reclen);
	ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx);
	if (!ret)
		ret = spa_history_write(spa, record_packed, reclen, shpp, tx);

	if (!ret && hap->ha_log_type == LOG_CMD_POOL_CREATE) {
		shpp->sh_pool_create_len += sizeof (le_len) + reclen;
		shpp->sh_bof = shpp->sh_pool_create_len;
	}

	mutex_exit(&spa->spa_history_lock);
	nvlist_free(nvrecord);
	kmem_free(record_packed, reclen);
	dmu_buf_rele(dbp, FTAG);

	strfree(hap->ha_history_str);
	if (hap->ha_zone != NULL)
		strfree(hap->ha_zone);
	kmem_free(hap, sizeof (history_arg_t));
}
Esempio n. 27
0
File: logfix.c Progetto: pjjw/logfix
int
main(int argc, char **argv)
{
	int fd_pool;
	int fd_log;
	vdev_label_t vl_pool;
	vdev_label_t vl_log;
	nvlist_t *config_pool;
	nvlist_t *config_log;

	uint64_t guid;		// ZPOOL_CONFIG_GUID
	uint64_t is_log;	// ZPOOL_CONFIG_IS_LOG
	nvlist_t *vdev_tree;	// ZPOOL_CONFIG_VDEV_TREE

	char *buf;
	size_t buflen;

	VERIFY(argc == 4);
	VERIFY((fd_pool = open(argv[1], O_RDWR)) != -1);
	VERIFY((fd_log = open(argv[2], O_RDWR)) != -1);
	VERIFY(sscanf(argv[3], "%" SCNu64 , &guid) == 1);
	//guid = 9851295902337437618ULL;

	VERIFY(pread64(fd_pool, &vl_pool, sizeof (vdev_label_t), 0) ==
	    sizeof (vdev_label_t));
	VERIFY(nvlist_unpack(vl_pool.vl_vdev_phys.vp_nvlist,
	    sizeof (vl_pool.vl_vdev_phys.vp_nvlist), &config_pool, 0) == 0);
	VERIFY(pread64(fd_log, &vl_log, sizeof (vdev_label_t), 0) ==
	    sizeof (vdev_label_t));
	VERIFY(nvlist_unpack(vl_log.vl_vdev_phys.vp_nvlist,
	    sizeof (vl_log.vl_vdev_phys.vp_nvlist), &config_log, 0) == 0);

	// save what we want from config_log -- is_log, vdev_tree
	VERIFY(nvlist_lookup_uint64(config_log, ZPOOL_CONFIG_IS_LOG, &is_log) == 0);
	VERIFY(nvlist_lookup_nvlist(config_log, ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) == 0);

	// fix guid for vdev_log
	VERIFY(nvlist_remove_all(vdev_tree, ZPOOL_CONFIG_GUID) == 0);
	VERIFY(nvlist_add_uint64(vdev_tree, ZPOOL_CONFIG_GUID, guid) == 0);

	// remove what we are going to replace on config_pool
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_TOP_GUID) == 0);
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_GUID) == 0);
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_VDEV_TREE) == 0);

	// add back what we want 
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_TOP_GUID, guid) == 0);
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_GUID, guid) == 0);
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
	VERIFY(nvlist_add_nvlist(config_pool, ZPOOL_CONFIG_VDEV_TREE, vdev_tree) == 0);

	buf = vl_pool.vl_vdev_phys.vp_nvlist;
	buflen = sizeof (vl_pool.vl_vdev_phys.vp_nvlist);
	VERIFY(nvlist_pack(config_pool, &buf, &buflen, NV_ENCODE_XDR, 0) == 0);

	label_write(fd_log, offsetof(vdev_label_t, vl_vdev_phys),
	    VDEV_PHYS_SIZE, &vl_pool.vl_vdev_phys);

	fsync(fd_log);

	return (0);
}
Esempio n. 28
0
static
#endif
int
zfs_fuid_find_by_domain(zfsvfs_t *zfsvfs, const char *domain, char **retdomain,
    dmu_tx_t *tx)
{
	fuid_domain_t searchnode, *findnode;
	avl_index_t loc;

	/*
	 * If the dummy "nobody" domain then return an index of 0
	 * to cause the created FUID to be a standard POSIX id
	 * for the user nobody.
	 */
	if (domain[0] == '\0') {
		*retdomain = "";
		return (0);
	}

	searchnode.f_ksid = ksid_lookupdomain(domain);
	if (retdomain) {
		*retdomain = searchnode.f_ksid->kd_name;
	}
	if (!zfsvfs->z_fuid_loaded)
		zfs_fuid_init(zfsvfs, tx);

	rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
	findnode = avl_find(&zfsvfs->z_fuid_domain, &searchnode, &loc);
	rw_exit(&zfsvfs->z_fuid_lock);

	if (findnode) {
		ksiddomain_rele(searchnode.f_ksid);
		return (findnode->f_idx);
	} else {
		fuid_domain_t *domnode;
		nvlist_t *nvp;
		nvlist_t **fuids;
		uint64_t retidx;
		size_t nvsize = 0;
		char *packed;
		dmu_buf_t *db;
		int i = 0;

		domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
		domnode->f_ksid = searchnode.f_ksid;

		rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
		retidx = domnode->f_idx = avl_numnodes(&zfsvfs->z_fuid_idx) + 1;

		avl_add(&zfsvfs->z_fuid_domain, domnode);
		avl_add(&zfsvfs->z_fuid_idx, domnode);
		/*
		 * Now resync the on-disk nvlist.
		 */
		VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);

		domnode = avl_first(&zfsvfs->z_fuid_domain);
		fuids = kmem_alloc(retidx * sizeof (void *), KM_SLEEP);
		while (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);
			domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode);
		}
		VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY,
		    fuids, retidx) == 0);
		for (i = 0; i != retidx; i++)
			nvlist_free(fuids[i]);
		kmem_free(fuids, retidx * 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);

		rw_exit(&zfsvfs->z_fuid_lock);
		return (retidx);
	}
}
Esempio n. 29
0
/*
 * Perform /dev/fm ioctl.  The input and output data are represented by
 * name-value lists (nvlists).
 */
int
fmd_agent_nvl_ioctl(fmd_agent_hdl_t *hdl, int cmd, uint32_t ver,
    nvlist_t *innvl, nvlist_t **outnvlp)
{
	fm_ioc_data_t fid;
	int err = 0;
	char *inbuf = NULL, *outbuf = NULL;
	size_t insz = 0, outsz = 0;

	if (innvl != NULL) {
		if ((err = nvlist_size(innvl, &insz, NV_ENCODE_NATIVE)) != 0)
			return (err);
		if (insz > FM_IOC_MAXBUFSZ)
			return (ENAMETOOLONG);
		if ((inbuf = umem_alloc(insz, UMEM_DEFAULT)) == NULL)
			return (errno);

		if ((err = nvlist_pack(innvl, &inbuf, &insz,
		    NV_ENCODE_NATIVE, 0)) != 0) {
			umem_free(inbuf, insz);
			return (err);
		}
	}

	if (outnvlp != NULL) {
		outsz = FM_IOC_OUT_BUFSZ;
	}
	for (;;) {
		if (outnvlp != NULL) {
			outbuf = umem_alloc(outsz, UMEM_DEFAULT);
			if (outbuf == NULL) {
				err = errno;
				break;
			}
		}

		fid.fid_version = ver;
		fid.fid_insz = insz;
		fid.fid_inbuf = inbuf;
		fid.fid_outsz = outsz;
		fid.fid_outbuf = outbuf;

		if (ioctl(hdl->agent_devfd, cmd, &fid) < 0) {
			if (errno == ENAMETOOLONG && outsz != 0 &&
			    outsz < (FM_IOC_OUT_MAXBUFSZ / 2)) {
				umem_free(outbuf, outsz);
				outsz *= 2;
				outbuf = umem_alloc(outsz, UMEM_DEFAULT);
				if (outbuf == NULL) {
					err = errno;
					break;
				}
			} else {
				err = errno;
				break;
			}
		} else if (outnvlp != NULL) {
			err = nvlist_unpack(fid.fid_outbuf, fid.fid_outsz,
			    outnvlp, 0);
			break;
		} else {
			break;
		}
	}

	if (inbuf != NULL)
		umem_free(inbuf, insz);
	if (outbuf != NULL)
		umem_free(outbuf, outsz);

	return (err);
}