Exemple #1
0
static void
ofdisk_attach(device_t parent, device_t self, void *aux)
{
	struct ofdisk_softc *of = device_private(self);
	struct ofbus_attach_args *oba = aux;
	char child[64];
	int l;

	of->sc_dev = self;
	if ((l = OF_getprop(oba->oba_phandle, "name", child,
	    sizeof child - 1)) < 0)
		panic("device without name?");
	if (l >= sizeof child)
		l = sizeof child - 1;
	child[l] = 0;

	of->sc_flags = 0;
	of->sc_phandle = oba->oba_phandle;
	of->sc_unit = oba->oba_unit;
	of->sc_ihandle = 0;
	disk_init(&of->sc_dk, device_xname(of->sc_dev), &ofdisk_dkdriver);
	disk_attach(&of->sc_dk);
	printf("\n");

	if (strcmp(child, "floppy") == 0)
		of->sc_flags |= OFDF_ISFLOPPY;
	else {
		/* Discover wedges on this disk. */
		dkwedge_discover(&of->sc_dk);
	}
}
Exemple #2
0
/*
 * disk_ioctl --
 *	Generic disk ioctl handling.
 */
int
disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag,
    struct lwp *l)
{
	struct dkwedge_info *dkw;
	struct partinfo *pi;
	struct partition *dp;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	switch (cmd) {
	case DIOCGDISKINFO:
		if (dk->dk_info == NULL)
			return ENOTSUP;
		return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info);

	case DIOCGSECTORSIZE:
		*(u_int *)data = dk->dk_geom.dg_secsize;
		return 0;

	case DIOCGMEDIASIZE:
		*(off_t *)data = (off_t)dk->dk_geom.dg_secsize *
		    dk->dk_geom.dg_secperunit;
		return 0;
	default:
		break;
	}

	if (dev == NODEV)
		return EPASSTHROUGH;

	/* The following should be moved to dk_ioctl */
	switch (cmd) {
	case DIOCGDINFO:
		if (dk->dk_label == NULL)
			return EBUSY;
		memcpy(data, dk->dk_label, sizeof (*dk->dk_label));
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		if (dk->dk_label == NULL)
			return EBUSY;
		memcpy(&newlabel, dk->dk_label, sizeof(newlabel));
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof(struct olddisklabel));
		return 0;
#endif

	case DIOCGPARTINFO:
		pi = data;
		memset(pi, 0, sizeof(*pi));
		pi->pi_secsize = dk->dk_geom.dg_secsize;
		pi->pi_bsize = BLKDEV_IOSIZE;

		if (DISKPART(dev) == RAW_PART) {
			pi->pi_size = dk->dk_geom.dg_secperunit;
			return 0;
		}

		if (dk->dk_label == NULL)
			return EBUSY;

		dp = &dk->dk_label->d_partitions[DISKPART(dev)];
		pi->pi_offset = dp->p_offset;
		pi->pi_size = dp->p_size;

		pi->pi_fstype = dp->p_fstype;
		pi->pi_frag = dp->p_frag;
		pi->pi_fsize = dp->p_fsize;
		pi->pi_cpg = dp->p_cpg;
		
		/*
		 * dholland 20130616: XXX this logic should not be
		 * here. It is here because the old buffer cache
		 * demands that all accesses to the same blocks need
		 * to be the same size; but it only works for FFS and
		 * nowadays I think it'll fail silently if the size
		 * info in the disklabel is wrong. (Or missing.) The
		 * buffer cache needs to be smarter; or failing that
		 * we need a reliable way here to get the right block
		 * size; or a reliable way to guarantee that (a) the
		 * fs is not mounted when we get here and (b) any
		 * buffers generated here will get purged when the fs
		 * does get mounted.
		 */
		if (dp->p_fstype == FS_BSDFFS &&
		    dp->p_frag != 0 && dp->p_fsize != 0)
			pi->pi_bsize = dp->p_frag * dp->p_fsize;
		return 0;

	case DIOCAWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		return dkwedge_list(dk, data, l);

	case DIOCMWEDGES:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkwedge_discover(dk);
		return 0;

	default:
		return EPASSTHROUGH;
	}
}
Exemple #3
0
/* ARGSUSED */
static int
cgd_ioctl_set(struct cgd_softc *cs, void *data, struct lwp *l)
{
	struct	 cgd_ioctl *ci = data;
	struct	 vnode *vp;
	int	 ret;
	size_t	 i;
	size_t	 keybytes;			/* key length in bytes */
	const char *cp;
	struct pathbuf *pb;
	char	 *inbuf;
	struct dk_softc *dksc = &cs->sc_dksc;

	cp = ci->ci_disk;

	ret = pathbuf_copyin(ci->ci_disk, &pb);
	if (ret != 0) {
		return ret;
	}
	ret = dk_lookup(pb, l, &vp);
	pathbuf_destroy(pb);
	if (ret != 0) {
		return ret;
	}

	inbuf = malloc(MAX_KEYSIZE, M_TEMP, M_WAITOK);

	if ((ret = cgdinit(cs, cp, vp, l)) != 0)
		goto bail;

	(void)memset(inbuf, 0, MAX_KEYSIZE);
	ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
	if (ret)
		goto bail;
	cs->sc_cfuncs = cryptfuncs_find(inbuf);
	if (!cs->sc_cfuncs) {
		ret = EINVAL;
		goto bail;
	}

	(void)memset(inbuf, 0, MAX_KEYSIZE);
	ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL);
	if (ret)
		goto bail;

	for (i = 0; i < __arraycount(encblkno); i++)
		if (strcmp(encblkno[i].n, inbuf) == 0)
			break;

	if (i == __arraycount(encblkno)) {
		ret = EINVAL;
		goto bail;
	}

	keybytes = ci->ci_keylen / 8 + 1;
	if (keybytes > MAX_KEYSIZE) {
		ret = EINVAL;
		goto bail;
	}

	(void)memset(inbuf, 0, MAX_KEYSIZE);
	ret = copyin(ci->ci_key, inbuf, keybytes);
	if (ret)
		goto bail;

	cs->sc_cdata.cf_blocksize = ci->ci_blocksize;
	cs->sc_cdata.cf_mode = encblkno[i].v;
	cs->sc_cdata.cf_keylen = ci->ci_keylen;
	cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
	    &cs->sc_cdata.cf_blocksize);
	if (cs->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) {
	    log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n",
		cs->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE);
	    cs->sc_cdata.cf_priv = NULL;
	}

	/*
	 * The blocksize is supposed to be in bytes. Unfortunately originally
	 * it was expressed in bits. For compatibility we maintain encblkno
	 * and encblkno8.
	 */
	cs->sc_cdata.cf_blocksize /= encblkno[i].d;
	(void)explicit_memset(inbuf, 0, MAX_KEYSIZE);
	if (!cs->sc_cdata.cf_priv) {
		ret = EINVAL;		/* XXX is this the right error? */
		goto bail;
	}
	free(inbuf, M_TEMP);

	bufq_alloc(&dksc->sc_bufq, "fcfs", 0);

	cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK);
	cs->sc_data_used = 0;

	/* Attach the disk. */
	dk_attach(dksc);
	disk_attach(&dksc->sc_dkdev);

	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);

	/* Discover wedges on this disk. */
	dkwedge_discover(&dksc->sc_dkdev);

	return 0;

bail:
	free(inbuf, M_TEMP);
	(void)vn_close(vp, FREAD|FWRITE, l->l_cred);
	return ret;
}
/* ARGSUSED */
static int
vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
	bool force;
	int unit = vndunit(dev);
	struct vnd_softc *vnd;
	struct vnd_ioctl *vio;
	struct vattr vattr;
	struct pathbuf *pb;
	struct nameidata nd;
	int error, part, pmask;
	uint64_t geomsize;
	int fflags;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif
	struct dkwedge_info *dkw;
	struct dkwedge_list *dkwl;

#ifdef DEBUG
	if (vnddebug & VDB_FOLLOW)
		printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n",
		    dev, cmd, data, flag, l->l_proc, unit);
#endif
	vnd = device_lookup_private(&vnd_cd, unit);
	if (vnd == NULL &&
#ifdef COMPAT_30
	    cmd != VNDIOCGET30 &&
#endif
#ifdef COMPAT_50
	    cmd != VNDIOCGET50 &&
#endif
	    cmd != VNDIOCGET)
		return ENXIO;
	vio = (struct vnd_ioctl *)data;

	/* Must be open for writes for these commands... */
	switch (cmd) {
	case VNDIOCSET:
	case VNDIOCCLR:
#ifdef COMPAT_50
	case VNDIOCSET50:
	case VNDIOCCLR50:
#endif
	case DIOCSDINFO:
	case DIOCWDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCSDINFO:
	case ODIOCWDINFO:
#endif
	case DIOCKLABEL:
	case DIOCWLABEL:
		if ((flag & FWRITE) == 0)
			return EBADF;
	}

	/* Must be initialized for these... */
	switch (cmd) {
	case VNDIOCCLR:
#ifdef VNDIOCCLR50
	case VNDIOCCLR50:
#endif
	case DIOCGDINFO:
	case DIOCSDINFO:
	case DIOCWDINFO:
	case DIOCGPART:
	case DIOCKLABEL:
	case DIOCWLABEL:
	case DIOCGDEFLABEL:
	case DIOCCACHESYNC:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
	case ODIOCSDINFO:
	case ODIOCWDINFO:
	case ODIOCGDEFLABEL:
#endif
		if ((vnd->sc_flags & VNF_INITED) == 0)
			return ENXIO;
	}

	switch (cmd) {
#ifdef VNDIOCSET50
	case VNDIOCSET50:
#endif
	case VNDIOCSET:
		if (vnd->sc_flags & VNF_INITED)
			return EBUSY;

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

		fflags = FREAD;
		if ((vio->vnd_flags & VNDIOF_READONLY) == 0)
			fflags |= FWRITE;
		error = pathbuf_copyin(vio->vnd_file, &pb);
		if (error) {
			goto unlock_and_exit;
		}
		NDINIT(&nd, LOOKUP, FOLLOW, pb);
		if ((error = vn_open(&nd, fflags, 0)) != 0) {
			pathbuf_destroy(pb);
			goto unlock_and_exit;
		}
		KASSERT(l);
		error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred);
		if (!error && nd.ni_vp->v_type != VREG)
			error = EOPNOTSUPP;
		if (!error && vattr.va_bytes < vattr.va_size)
			/* File is definitely sparse, use vn_rdwr() */
			vnd->sc_flags |= VNF_USE_VN_RDWR;
		if (error) {
			VOP_UNLOCK(nd.ni_vp);
			goto close_and_exit;
		}

		/* If using a compressed file, initialize its info */
		/* (or abort with an error if kernel has no compression) */
		if (vio->vnd_flags & VNF_COMP) {
#ifdef VND_COMPRESSION
			struct vnd_comp_header *ch;
			int i;
			u_int32_t comp_size;
			u_int32_t comp_maxsize;
 
			/* allocate space for compresed file header */
			ch = malloc(sizeof(struct vnd_comp_header),
			M_TEMP, M_WAITOK);
 
			/* read compressed file header */
			error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch,
			  sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE,
			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
			if (error) {
				free(ch, M_TEMP);
				VOP_UNLOCK(nd.ni_vp);
				goto close_and_exit;
			}
 
			/* save some header info */
			vnd->sc_comp_blksz = ntohl(ch->block_size);
			/* note last offset is the file byte size */
			vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1;
			free(ch, M_TEMP);
			if (vnd->sc_comp_blksz == 0 ||
			    vnd->sc_comp_blksz % DEV_BSIZE !=0) {
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
			if (sizeof(struct vnd_comp_header) +
			  sizeof(u_int64_t) * vnd->sc_comp_numoffs >
			  vattr.va_size) {
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
 
			/* set decompressed file size */
			vattr.va_size =
			    ((u_quad_t)vnd->sc_comp_numoffs - 1) *
			     (u_quad_t)vnd->sc_comp_blksz;
 
			/* allocate space for all the compressed offsets */
			vnd->sc_comp_offsets =
			malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs,
			M_DEVBUF, M_WAITOK);
 
			/* read in the offsets */
			error = vn_rdwr(UIO_READ, nd.ni_vp,
			  (void *)vnd->sc_comp_offsets,
			  sizeof(u_int64_t) * vnd->sc_comp_numoffs,
			  sizeof(struct vnd_comp_header), UIO_SYSSPACE,
			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
			if (error) {
				VOP_UNLOCK(nd.ni_vp);
				goto close_and_exit;
			}
			/*
			 * find largest block size (used for allocation limit).
			 * Also convert offset to native byte order.
			 */
			comp_maxsize = 0;
			for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) {
				vnd->sc_comp_offsets[i] =
				  be64toh(vnd->sc_comp_offsets[i]);
				comp_size = be64toh(vnd->sc_comp_offsets[i + 1])
				  - vnd->sc_comp_offsets[i];
				if (comp_size > comp_maxsize)
					comp_maxsize = comp_size;
			}
			vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] =
			  be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]);
 
			/* create compressed data buffer */
			vnd->sc_comp_buff = malloc(comp_maxsize,
			  M_DEVBUF, M_WAITOK);
 
			/* create decompressed buffer */
			vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz,
			  M_DEVBUF, M_WAITOK);
			vnd->sc_comp_buffblk = -1;
 
			/* Initialize decompress stream */
			memset(&vnd->sc_comp_stream, 0, sizeof(z_stream));
			vnd->sc_comp_stream.zalloc = vnd_alloc;
			vnd->sc_comp_stream.zfree = vnd_free;
			error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS);
			if (error) {
				if (vnd->sc_comp_stream.msg)
					printf("vnd%d: compressed file, %s\n",
					  unit, vnd->sc_comp_stream.msg);
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
 
			vnd->sc_flags |= VNF_COMP | VNF_READONLY;
#else /* !VND_COMPRESSION */
			VOP_UNLOCK(nd.ni_vp);
			error = EOPNOTSUPP;
			goto close_and_exit;
#endif /* VND_COMPRESSION */
		}
 
		VOP_UNLOCK(nd.ni_vp);
		vnd->sc_vp = nd.ni_vp;
		vnd->sc_size = btodb(vattr.va_size);	/* note truncation */

		/*
		 * Use pseudo-geometry specified.  If none was provided,
		 * use "standard" Adaptec fictitious geometry.
		 */
		if (vio->vnd_flags & VNDIOF_HASGEOM) {

			memcpy(&vnd->sc_geom, &vio->vnd_geom,
			    sizeof(vio->vnd_geom));

			/*
			 * Sanity-check the sector size.
			 * XXX Don't allow secsize < DEV_BSIZE.	 Should
			 * XXX we?
			 */
			if (vnd->sc_geom.vng_secsize < DEV_BSIZE ||
			    (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 ||
			    vnd->sc_geom.vng_ncylinders == 0 ||
			    (vnd->sc_geom.vng_ntracks *
			     vnd->sc_geom.vng_nsectors) == 0) {
				error = EINVAL;
				goto close_and_exit;
			}

			/*
			 * Compute the size (in DEV_BSIZE blocks) specified
			 * by the geometry.
			 */
			geomsize = (vnd->sc_geom.vng_nsectors *
			    vnd->sc_geom.vng_ntracks *
			    vnd->sc_geom.vng_ncylinders) *
			    (vnd->sc_geom.vng_secsize / DEV_BSIZE);

			/*
			 * Sanity-check the size against the specified
			 * geometry.
			 */
			if (vnd->sc_size < geomsize) {
				error = EINVAL;
				goto close_and_exit;
			}
		} else if (vnd->sc_size >= (32 * 64)) {
			/*
			 * Size must be at least 2048 DEV_BSIZE blocks
			 * (1M) in order to use this geometry.
			 */
			vnd->sc_geom.vng_secsize = DEV_BSIZE;
			vnd->sc_geom.vng_nsectors = 32;
			vnd->sc_geom.vng_ntracks = 64;
			vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32);
		} else {
			vnd->sc_geom.vng_secsize = DEV_BSIZE;
			vnd->sc_geom.vng_nsectors = 1;
			vnd->sc_geom.vng_ntracks = 1;
			vnd->sc_geom.vng_ncylinders = vnd->sc_size;
		}

		vnd_set_geometry(vnd);

		if (vio->vnd_flags & VNDIOF_READONLY) {
			vnd->sc_flags |= VNF_READONLY;
		}

		if ((error = vndsetcred(vnd, l->l_cred)) != 0)
			goto close_and_exit;

		vndthrottle(vnd, vnd->sc_vp);
		vio->vnd_osize = dbtob(vnd->sc_size);
#ifdef VNDIOCSET50
		if (cmd != VNDIOCSET50)
#endif
			vio->vnd_size = dbtob(vnd->sc_size);
		vnd->sc_flags |= VNF_INITED;

		/* create the kernel thread, wait for it to be up */
		error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd,
		    &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev));
		if (error)
			goto close_and_exit;
		while ((vnd->sc_flags & VNF_KTHREAD) == 0) {
			tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0);
		}
#ifdef DEBUG
		if (vnddebug & VDB_INIT)
			printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
			    vnd->sc_vp, (unsigned long) vnd->sc_size,
			    vnd->sc_geom.vng_secsize,
			    vnd->sc_geom.vng_nsectors,
			    vnd->sc_geom.vng_ntracks,
			    vnd->sc_geom.vng_ncylinders);
#endif

		/* Attach the disk. */
		disk_attach(&vnd->sc_dkdev);
		disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize);

		/* Initialize the xfer and buffer pools. */
		pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
		    0, 0, "vndxpl", NULL, IPL_BIO);

		vndunlock(vnd);

		pathbuf_destroy(pb);

		/* Discover wedges on this disk */
		dkwedge_discover(&vnd->sc_dkdev);

		break;

close_and_exit:
		(void) vn_close(nd.ni_vp, fflags, l->l_cred);
		pathbuf_destroy(pb);
unlock_and_exit:
#ifdef VND_COMPRESSION
		/* free any allocated memory (for compressed file) */
		if (vnd->sc_comp_offsets) {
			free(vnd->sc_comp_offsets, M_DEVBUF);
			vnd->sc_comp_offsets = NULL;
		}
		if (vnd->sc_comp_buff) {
			free(vnd->sc_comp_buff, M_DEVBUF);
			vnd->sc_comp_buff = NULL;
		}
		if (vnd->sc_comp_decombuf) {
			free(vnd->sc_comp_decombuf, M_DEVBUF);
			vnd->sc_comp_decombuf = NULL;
		}
#endif /* VND_COMPRESSION */
		vndunlock(vnd);
		return error;

#ifdef VNDIOCCLR50
	case VNDIOCCLR50:
#endif
	case VNDIOCCLR:
		part = DISKPART(dev);
		pmask = (1 << part);
		force = (vio->vnd_flags & VNDIOF_FORCE) != 0;

		if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0)
			return error;

		break;

#ifdef COMPAT_30
	case VNDIOCGET30: {
		struct vnd_user30 *vnu;
		struct vattr va;
		vnu = (struct vnd_user30 *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}
#endif

#ifdef COMPAT_50
	case VNDIOCGET50: {
		struct vnd_user50 *vnu;
		struct vattr va;
		vnu = (struct vnd_user50 *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}
#endif

	case VNDIOCGET: {
		struct vnd_user *vnu;
		struct vattr va;
		vnu = (struct vnd_user *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}

	case DIOCGDINFO:
		*(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		newlabel = *(vnd->sc_dkdev.dk_label);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCGPART:
		((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label;
		((struct partinfo *)data)->part =
		    &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
		break;

	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
	{
		struct disklabel *lp;

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

		vnd->sc_flags |= VNF_LABELLING;

#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, data, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = (struct disklabel *)data;

		error = setdisklabel(vnd->sc_dkdev.dk_label,
		    lp, 0, vnd->sc_dkdev.dk_cpulabel);
		if (error == 0) {
			if (cmd == DIOCWDINFO
#ifdef __HAVE_OLD_DISKLABEL
			    || cmd == ODIOCWDINFO
#endif
			   )
				error = writedisklabel(VNDLABELDEV(dev),
				    vndstrategy, vnd->sc_dkdev.dk_label,
				    vnd->sc_dkdev.dk_cpulabel);
		}

		vnd->sc_flags &= ~VNF_LABELLING;

		vndunlock(vnd);

		if (error)
			return error;
		break;
	}

	case DIOCKLABEL:
		if (*(int *)data != 0)
			vnd->sc_flags |= VNF_KLABEL;
		else
			vnd->sc_flags &= ~VNF_KLABEL;
		break;

	case DIOCWLABEL:
		if (*(int *)data != 0)
			vnd->sc_flags |= VNF_WLABEL;
		else
			vnd->sc_flags &= ~VNF_WLABEL;
		break;

	case DIOCGDEFLABEL:
		vndgetdefaultlabel(vnd, (struct disklabel *)data);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		vndgetdefaultlabel(vnd, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCCACHESYNC:
		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred,
		    FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0);
		VOP_UNLOCK(vnd->sc_vp);
		return error;

	case DIOCAWEDGE:
		dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return EBADF;

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
		    sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return EBADF;

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
		    sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		dkwl = (void *) data;

		return dkwedge_list(&vnd->sc_dkdev, dkwl, l);

	default:
		return ENOTTY;
	}

	return 0;
}
Exemple #5
0
/*
 * disk_ioctl --
 *	Generic disk ioctl handling.
 */
int
disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag,
    struct lwp *l)
{
	struct dkwedge_info *dkw;
	struct partinfo *pt;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	switch (cmd) {
	case DIOCGDISKINFO:
		if (dk->dk_info == NULL)
			return ENOTSUP;
		return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info);

	case DIOCGSECTORSIZE:
		*(u_int *)data = dk->dk_geom.dg_secsize;
		return 0;

	case DIOCGMEDIASIZE:
		*(off_t *)data = (off_t)dk->dk_geom.dg_secsize *
		    dk->dk_geom.dg_secperunit;
		return 0;
	default:
		break;
	}

	if (dev == NODEV)
		return EPASSTHROUGH;

	/* The following should be moved to dk_ioctl */
	switch (cmd) {
	case DIOCGDINFO:
		memcpy(data, dk->dk_label, sizeof (*dk->dk_label));
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		memcpy(&newlabel, dk->dk_label, sizeof(newlabel));
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof(struct olddisklabel));
		return 0;
#endif

	case DIOCGPART:
		if (dk->dk_label == NULL)
			return EBUSY;
		pt = data;
		pt->disklab = dk->dk_label;
		pt->part = &dk->dk_label->d_partitions[DISKPART(dev)];
		return 0;

	case DIOCAWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		return dkwedge_list(dk, data, l);

	case DIOCMWEDGES:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkwedge_discover(dk);
		return 0;

	default:
		return EPASSTHROUGH;
	}
}