Esempio n. 1
0
static void
vndshutdown(void)
{
	struct vnd_softc *vnd;

	for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
		if (vnd->sc_flags & VNF_INITED)
			vndclear(vnd);
}
Esempio n. 2
0
static int
vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force)
{
	int error;

	if ((error = vndlock(vnd)) != 0)
		return error;

	/*
	 * Don't unconfigure if any other partitions are open
	 * or if both the character and block flavors of this
	 * partition are open.
	 */
	if (DK_BUSY(vnd, pmask) && !force) {
		vndunlock(vnd);
		return EBUSY;
	}

	/* Delete all of our wedges */
	dkwedge_delall(&vnd->sc_dkdev);

	/*
	 * XXX vndclear() might call vndclose() implicitly;
	 * release lock to avoid recursion
	 *
	 * Set VNF_CLEARING to prevent vndopen() from
	 * sneaking in after we vndunlock().
	 */
	vnd->sc_flags |= VNF_CLEARING;
	vndunlock(vnd);
	vndclear(vnd, minor);
#ifdef DEBUG
	if (vnddebug & VDB_INIT)
		printf("vndioctl: CLRed\n");
#endif

	/* Destroy the xfer and buffer pools. */
	pool_destroy(&vnd->sc_vxpool);

	/* Detach the disk. */
	disk_detach(&vnd->sc_dkdev);

	return 0;
}
Esempio n. 3
0
/* ARGSUSED */
int
vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
	int unit = DISKUNIT(dev);
	struct disklabel *lp;
	struct vnd_softc *sc;
	struct vnd_ioctl *vio;
	struct vnd_user *vnu;
	struct vattr vattr;
	struct nameidata nd;
	int error, part, pmask;

	DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
	    dev, cmd, addr, flag, p, unit);

	error = suser(p, 0);
	if (error)
		return (error);
	if (unit >= numvnd)
		return (ENXIO);

	sc = &vnd_softc[unit];
	vio = (struct vnd_ioctl *)addr;
	switch (cmd) {

	case VNDIOCSET:
		if (sc->sc_flags & VNF_INITED)
			return (EBUSY);

		/* Geometry eventually has to fit into label fields */
		if (vio->vnd_secsize > UINT_MAX ||
		    vio->vnd_ntracks > UINT_MAX ||
		    vio->vnd_nsectors > UINT_MAX)
			return (EINVAL);

		if ((error = disk_lock(&sc->sc_dk)) != 0)
			return (error);

		if ((error = copyinstr(vio->vnd_file, sc->sc_file,
		    sizeof(sc->sc_file), NULL))) {
			disk_unlock(&sc->sc_dk);
			return (error);
		}

		/* Set geometry for device. */
		sc->sc_secsize = vio->vnd_secsize;
		sc->sc_ntracks = vio->vnd_ntracks;
		sc->sc_nsectors = vio->vnd_nsectors;

		/*
		 * Open for read and write first. This lets vn_open() weed out
		 * directories, sockets, etc. so we don't have to worry about
		 * them.
		 */
		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
		sc->sc_flags &= ~VNF_READONLY;
		error = vn_open(&nd, FREAD|FWRITE, 0);
		if (error == EROFS) {
			sc->sc_flags |= VNF_READONLY;
			error = vn_open(&nd, FREAD, 0);
		}
		if (error) {
			disk_unlock(&sc->sc_dk);
			return (error);
		}

		if (nd.ni_vp->v_type == VBLK)
			sc->sc_size = vndbdevsize(nd.ni_vp, p);
		else {
			error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
			if (error) {
				VOP_UNLOCK(nd.ni_vp, 0, p);
				vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
				disk_unlock(&sc->sc_dk);
				return (error);
			}
			sc->sc_size = vattr.va_size / sc->sc_secsize;
		}
		VOP_UNLOCK(nd.ni_vp, 0, p);
		sc->sc_vp = nd.ni_vp;
		if ((error = vndsetcred(sc, p->p_ucred)) != 0) {
			(void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
			disk_unlock(&sc->sc_dk);
			return (error);
		}

		if (vio->vnd_keylen > 0) {
			char key[BLF_MAXUTILIZED];

			if (vio->vnd_keylen > sizeof(key))
				vio->vnd_keylen = sizeof(key);

			if ((error = copyin(vio->vnd_key, key,
			    vio->vnd_keylen)) != 0) {
				(void) vn_close(nd.ni_vp, VNDRW(sc),
				    p->p_ucred, p);
				disk_unlock(&sc->sc_dk);
				return (error);
			}

			sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF,
			    M_WAITOK);
			blf_key(sc->sc_keyctx, key, vio->vnd_keylen);
			explicit_bzero(key, vio->vnd_keylen);
		} else
			sc->sc_keyctx = NULL;

		vio->vnd_size = sc->sc_size * sc->sc_secsize;
		sc->sc_flags |= VNF_INITED;

		DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n",
		    sc->sc_vp, (unsigned long long)sc->sc_size);

		/* Attach the disk. */
		sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
		disk_attach(&sc->sc_dev, &sc->sc_dk);

		disk_unlock(&sc->sc_dk);

		break;

	case VNDIOCCLR:
		if ((sc->sc_flags & VNF_INITED) == 0)
			return (ENXIO);

		if ((error = disk_lock(&sc->sc_dk)) != 0)
			return (error);

		/*
		 * Don't unconfigure if any other partitions are open
		 * or if both the character and block flavors of this
		 * partition are open.
		 */
		part = DISKPART(dev);
		pmask = (1 << part);
		if ((sc->sc_dk.dk_openmask & ~pmask) ||
		    ((sc->sc_dk.dk_bopenmask & pmask) &&
		    (sc->sc_dk.dk_copenmask & pmask))) {
			disk_unlock(&sc->sc_dk);
			return (EBUSY);
		}

		vndclear(sc);
		DNPRINTF(VDB_INIT, "vndioctl: CLRed\n");

		/* Free crypto key */
		if (sc->sc_keyctx) {
			explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx));
			free(sc->sc_keyctx, M_DEVBUF, sizeof(*sc->sc_keyctx));
		}

		/* Detach the disk. */
		disk_detach(&sc->sc_dk);
		disk_unlock(&sc->sc_dk);
		break;

	case VNDIOCGET:
		vnu = (struct vnd_user *)addr;

		if (vnu->vnu_unit == -1)
			vnu->vnu_unit = unit;
		if (vnu->vnu_unit >= numvnd)
			return (ENXIO);
		if (vnu->vnu_unit < 0)
			return (EINVAL);

		sc = &vnd_softc[vnu->vnu_unit];

		if (sc->sc_flags & VNF_INITED) {
			error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p);
			if (error)
				return (error);

			strlcpy(vnu->vnu_file, sc->sc_file,
			    sizeof(vnu->vnu_file));
			vnu->vnu_dev = vattr.va_fsid;
			vnu->vnu_ino = vattr.va_fileid;
		} else {
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
		}

		break;

	case DIOCRLDINFO:
		if ((sc->sc_flags & VNF_HAVELABEL) == 0)
			return (ENOTTY);
		lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
		vndgetdisklabel(dev, sc, lp, 0);
		*(sc->sc_dk.dk_label) = *lp;
		free(lp, M_TEMP, sizeof(*lp));
		return (0);

	case DIOCGPDINFO:
		if ((sc->sc_flags & VNF_HAVELABEL) == 0)
			return (ENOTTY);
		vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
		return (0);

	case DIOCGDINFO:
		if ((sc->sc_flags & VNF_HAVELABEL) == 0)
			return (ENOTTY);
		*(struct disklabel *)addr = *(sc->sc_dk.dk_label);
		return (0);

	case DIOCGPART:
		if ((sc->sc_flags & VNF_HAVELABEL) == 0)
			return (ENOTTY);
		((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
		((struct partinfo *)addr)->part =
		    &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
		return (0);

	case DIOCWDINFO:
	case DIOCSDINFO:
		if ((sc->sc_flags & VNF_HAVELABEL) == 0)
			return (ENOTTY);
		if ((flag & FWRITE) == 0)
			return (EBADF);

		if ((error = disk_lock(&sc->sc_dk)) != 0)
			return (error);

		error = setdisklabel(sc->sc_dk.dk_label,
		    (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0);
		if (error == 0) {
			if (cmd == DIOCWDINFO)
				error = writedisklabel(DISKLABELDEV(dev),
				    vndstrategy, sc->sc_dk.dk_label);
		}

		disk_unlock(&sc->sc_dk);
		return (error);

	default:
		return (ENOTTY);
	}

	return (0);
}