diff options
| author | artem <none@none> | 2006-10-12 22:44:10 -0700 | 
|---|---|---|
| committer | artem <none@none> | 2006-10-12 22:44:10 -0700 | 
| commit | 18c2aff776a775d34a4c9893a4c72e0434d68e36 (patch) | |
| tree | 2ce07e824c6b4db04bfedb4dea79bc5f255851ed /usr/src/uts/common/io/vol.c | |
| parent | 38787b9f841232f52e2f48dd8a9e475d09954391 (diff) | |
| download | illumos-joyent-18c2aff776a775d34a4c9893a4c72e0434d68e36.tar.gz | |
PSARC 2005/399 Tamarack: Removable Media Enhancements in Solaris
6460497 Tamarack (ON)
6460498 vold EOF removal
--HG--
rename : usr/src/cmd/fs.d/hsfs/ident/Makefile => deleted_files/usr/src/cmd/fs.d/hsfs/ident/Makefile
rename : usr/src/cmd/fs.d/hsfs/ident/ident_hsfs.c => deleted_files/usr/src/cmd/fs.d/hsfs/ident/ident_hsfs.c
rename : usr/src/cmd/fs.d/pcfs/ident/Makefile => deleted_files/usr/src/cmd/fs.d/pcfs/ident/Makefile
rename : usr/src/cmd/fs.d/pcfs/ident/ident_pcfs.c => deleted_files/usr/src/cmd/fs.d/pcfs/ident/ident_pcfs.c
rename : usr/src/cmd/fs.d/udfs/ident/Makefile => deleted_files/usr/src/cmd/fs.d/udfs/ident/Makefile
rename : usr/src/cmd/fs.d/udfs/ident/ident_udfs.c => deleted_files/usr/src/cmd/fs.d/udfs/ident/ident_udfs.c
rename : usr/src/cmd/fs.d/ufs/ident/Makefile => deleted_files/usr/src/cmd/fs.d/ufs/ident/Makefile
rename : usr/src/cmd/fs.d/ufs/ident/ident_ufs.c => deleted_files/usr/src/cmd/fs.d/ufs/ident/ident_ufs.c
rename : usr/src/cmd/initpkg/init.d/volmgt => deleted_files/usr/src/cmd/initpkg/init.d/volmgt
rename : usr/src/cmd/volmgt/Makefile => deleted_files/usr/src/cmd/volmgt/Makefile
rename : usr/src/cmd/volmgt/Makefile.volmgt => deleted_files/usr/src/cmd/volmgt/Makefile.volmgt
rename : usr/src/cmd/volmgt/etc/Makefile => deleted_files/usr/src/cmd/volmgt/etc/Makefile
rename : usr/src/cmd/volmgt/etc/rmmount.conf => deleted_files/usr/src/cmd/volmgt/etc/rmmount.conf
rename : usr/src/cmd/volmgt/etc/svc-volfs => deleted_files/usr/src/cmd/volmgt/etc/svc-volfs
rename : usr/src/cmd/volmgt/etc/vold.conf => deleted_files/usr/src/cmd/volmgt/etc/vold.conf
rename : usr/src/cmd/volmgt/etc/volfs.xml => deleted_files/usr/src/cmd/volmgt/etc/volfs.xml
rename : usr/src/cmd/volmgt/req.flg => deleted_files/usr/src/cmd/volmgt/req.flg
rename : usr/src/cmd/volmgt/rmm/Makefile => deleted_files/usr/src/cmd/volmgt/rmm/Makefile
rename : usr/src/cmd/volmgt/rmm/action_dvdvideo.c => deleted_files/usr/src/cmd/volmgt/rmm/action_dvdvideo.c
rename : usr/src/cmd/volmgt/rmm/action_filemgr.c => deleted_files/usr/src/cmd/volmgt/rmm/action_filemgr.c
rename : usr/src/cmd/volmgt/rmm/action_test.c => deleted_files/usr/src/cmd/volmgt/rmm/action_test.c
rename : usr/src/cmd/volmgt/rmm/action_wabi.c => deleted_files/usr/src/cmd/volmgt/rmm/action_wabi.c
rename : usr/src/cmd/volmgt/rmm/action_workman.c => deleted_files/usr/src/cmd/volmgt/rmm/action_workman.c
rename : usr/src/cmd/volmgt/rmm/action_xmcd.c => deleted_files/usr/src/cmd/volmgt/rmm/action_xmcd.c
rename : usr/src/cmd/volmgt/rmm/req.flg => deleted_files/usr/src/cmd/volmgt/rmm/req.flg
rename : usr/src/cmd/volmgt/rmm/rmm.c => deleted_files/usr/src/cmd/volmgt/rmm/rmm.c
rename : usr/src/cmd/volmgt/rmm/rmm_config.c => deleted_files/usr/src/cmd/volmgt/rmm/rmm_config.c
rename : usr/src/cmd/volmgt/rmm/rmm_int.h => deleted_files/usr/src/cmd/volmgt/rmm/rmm_int.h
rename : usr/src/cmd/volmgt/rmm/rmm_util.c => deleted_files/usr/src/cmd/volmgt/rmm/rmm_util.c
rename : usr/src/cmd/volmgt/test/Makefile => deleted_files/usr/src/cmd/volmgt/test/Makefile
rename : usr/src/cmd/volmgt/test/README => deleted_files/usr/src/cmd/volmgt/test/README
rename : usr/src/cmd/volmgt/test/devlink.vt => deleted_files/usr/src/cmd/volmgt/test/devlink.vt
rename : usr/src/cmd/volmgt/test/stress => deleted_files/usr/src/cmd/volmgt/test/stress
rename : usr/src/cmd/volmgt/test/test_class_list => deleted_files/usr/src/cmd/volmgt/test/test_class_list
rename : usr/src/cmd/volmgt/test/test_suite_list => deleted_files/usr/src/cmd/volmgt/test/test_suite_list
rename : usr/src/cmd/volmgt/test/test_utilities_list => deleted_files/usr/src/cmd/volmgt/test/test_utilities_list
rename : usr/src/cmd/volmgt/test/voltestdrv.c => deleted_files/usr/src/cmd/volmgt/test/voltestdrv.c
rename : usr/src/cmd/volmgt/test/voltestdrv.conf => deleted_files/usr/src/cmd/volmgt/test/voltestdrv.conf
rename : usr/src/cmd/volmgt/test/voltestdrv.h => deleted_files/usr/src/cmd/volmgt/test/voltestdrv.h
rename : usr/src/cmd/volmgt/test/vttest.c => deleted_files/usr/src/cmd/volmgt/test/vttest.c
rename : usr/src/cmd/volmgt/util/Makefile => deleted_files/usr/src/cmd/volmgt/util/Makefile
rename : usr/src/cmd/volmgt/util/volcancel.c => deleted_files/usr/src/cmd/volmgt/util/volcancel.c
rename : usr/src/cmd/volmgt/util/volck.c => deleted_files/usr/src/cmd/volmgt/util/volck.c
rename : usr/src/cmd/volmgt/util/volmissing.c => deleted_files/usr/src/cmd/volmgt/util/volmissing.c
rename : usr/src/cmd/volmgt/util/volrmmount.c => deleted_files/usr/src/cmd/volmgt/util/volrmmount.c
rename : usr/src/cmd/volmgt/util/volsetup => deleted_files/usr/src/cmd/volmgt/util/volsetup
rename : usr/src/cmd/volmgt/util/volstat.c => deleted_files/usr/src/cmd/volmgt/util/volstat.c
rename : usr/src/cmd/volmgt/util/volutil.h => deleted_files/usr/src/cmd/volmgt/util/volutil.h
rename : usr/src/cmd/volmgt/vold/Makefile => deleted_files/usr/src/cmd/volmgt/vold/Makefile
rename : usr/src/cmd/volmgt/vold/action.h => deleted_files/usr/src/cmd/volmgt/vold/action.h
rename : usr/src/cmd/volmgt/vold/blank_partition.c => deleted_files/usr/src/cmd/volmgt/vold/blank_partition.c
rename : usr/src/cmd/volmgt/vold/db.h => deleted_files/usr/src/cmd/volmgt/vold/db.h
rename : usr/src/cmd/volmgt/vold/db_mem.c => deleted_files/usr/src/cmd/volmgt/vold/db_mem.c
rename : usr/src/cmd/volmgt/vold/db_nis.c => deleted_files/usr/src/cmd/volmgt/vold/db_nis.c
rename : usr/src/cmd/volmgt/vold/db_nis.h => deleted_files/usr/src/cmd/volmgt/vold/db_nis.h
rename : usr/src/cmd/volmgt/vold/dev.h => deleted_files/usr/src/cmd/volmgt/vold/dev.h
rename : usr/src/cmd/volmgt/vold/dev_cdrom.c => deleted_files/usr/src/cmd/volmgt/vold/dev_cdrom.c
rename : usr/src/cmd/volmgt/vold/dev_cdtest.c => deleted_files/usr/src/cmd/volmgt/vold/dev_cdtest.c
rename : usr/src/cmd/volmgt/vold/dev_floppy.c => deleted_files/usr/src/cmd/volmgt/vold/dev_floppy.c
rename : usr/src/cmd/volmgt/vold/dev_pcmem.c => deleted_files/usr/src/cmd/volmgt/vold/dev_pcmem.c
rename : usr/src/cmd/volmgt/vold/dev_rmdisk.c => deleted_files/usr/src/cmd/volmgt/vold/dev_rmdisk.c
rename : usr/src/cmd/volmgt/vold/dev_rmscsi.c => deleted_files/usr/src/cmd/volmgt/vold/dev_rmscsi.c
rename : usr/src/cmd/volmgt/vold/dev_test.c => deleted_files/usr/src/cmd/volmgt/vold/dev_test.c
rename : usr/src/cmd/volmgt/vold/fdisk_partition.c => deleted_files/usr/src/cmd/volmgt/vold/fdisk_partition.c
rename : usr/src/cmd/volmgt/vold/hsfs_partition.c => deleted_files/usr/src/cmd/volmgt/vold/hsfs_partition.c
rename : usr/src/cmd/volmgt/vold/label.h => deleted_files/usr/src/cmd/volmgt/vold/label.h
rename : usr/src/cmd/volmgt/vold/label_cdrom.c => deleted_files/usr/src/cmd/volmgt/vold/label_cdrom.c
rename : usr/src/cmd/volmgt/vold/label_dos.c => deleted_files/usr/src/cmd/volmgt/vold/label_dos.c
rename : usr/src/cmd/volmgt/vold/label_sun.c => deleted_files/usr/src/cmd/volmgt/vold/label_sun.c
rename : usr/src/cmd/volmgt/vold/label_test.c => deleted_files/usr/src/cmd/volmgt/vold/label_test.c
rename : usr/src/cmd/volmgt/vold/medium.c => deleted_files/usr/src/cmd/volmgt/vold/medium.c
rename : usr/src/cmd/volmgt/vold/medium.h => deleted_files/usr/src/cmd/volmgt/vold/medium.h
rename : usr/src/cmd/volmgt/vold/medium_private.h => deleted_files/usr/src/cmd/volmgt/vold/medium_private.h
rename : usr/src/cmd/volmgt/vold/name_factory.c => deleted_files/usr/src/cmd/volmgt/vold/name_factory.c
rename : usr/src/cmd/volmgt/vold/name_factory.h => deleted_files/usr/src/cmd/volmgt/vold/name_factory.h
rename : usr/src/cmd/volmgt/vold/nfs_server.c => deleted_files/usr/src/cmd/volmgt/vold/nfs_server.c
rename : usr/src/cmd/volmgt/vold/nfs_trace.c => deleted_files/usr/src/cmd/volmgt/vold/nfs_trace.c
rename : usr/src/cmd/volmgt/vold/node.h => deleted_files/usr/src/cmd/volmgt/vold/node.h
rename : usr/src/cmd/volmgt/vold/obj.h => deleted_files/usr/src/cmd/volmgt/vold/obj.h
rename : usr/src/cmd/volmgt/vold/partition.c => deleted_files/usr/src/cmd/volmgt/vold/partition.c
rename : usr/src/cmd/volmgt/vold/partition.h => deleted_files/usr/src/cmd/volmgt/vold/partition.h
rename : usr/src/cmd/volmgt/vold/partition_private.h => deleted_files/usr/src/cmd/volmgt/vold/partition_private.h
rename : usr/src/cmd/volmgt/vold/pcfs_partition.c => deleted_files/usr/src/cmd/volmgt/vold/pcfs_partition.c
rename : usr/src/cmd/volmgt/vold/solaris_partition.c => deleted_files/usr/src/cmd/volmgt/vold/solaris_partition.c
rename : usr/src/cmd/volmgt/vold/udfs_partition.c => deleted_files/usr/src/cmd/volmgt/vold/udfs_partition.c
rename : usr/src/cmd/volmgt/vold/ufs_partition.c => deleted_files/usr/src/cmd/volmgt/vold/ufs_partition.c
rename : usr/src/cmd/volmgt/vold/util.h => deleted_files/usr/src/cmd/volmgt/vold/util.h
rename : usr/src/cmd/volmgt/vold/vold.h => deleted_files/usr/src/cmd/volmgt/vold/vold.h
rename : usr/src/cmd/volmgt/vold/vold_action.c => deleted_files/usr/src/cmd/volmgt/vold/vold_action.c
rename : usr/src/cmd/volmgt/vold/vold_config.c => deleted_files/usr/src/cmd/volmgt/vold/vold_config.c
rename : usr/src/cmd/volmgt/vold/vold_db.c => deleted_files/usr/src/cmd/volmgt/vold/vold_db.c
rename : usr/src/cmd/volmgt/vold/vold_dev.c => deleted_files/usr/src/cmd/volmgt/vold/vold_dev.c
rename : usr/src/cmd/volmgt/vold/vold_err.c => deleted_files/usr/src/cmd/volmgt/vold/vold_err.c
rename : usr/src/cmd/volmgt/vold/vold_label.c => deleted_files/usr/src/cmd/volmgt/vold/vold_label.c
rename : usr/src/cmd/volmgt/vold/vold_main.c => deleted_files/usr/src/cmd/volmgt/vold/vold_main.c
rename : usr/src/cmd/volmgt/vold/vold_mnt.c => deleted_files/usr/src/cmd/volmgt/vold/vold_mnt.c
rename : usr/src/cmd/volmgt/vold/vold_node.c => deleted_files/usr/src/cmd/volmgt/vold/vold_node.c
rename : usr/src/cmd/volmgt/vold/vold_obj.c => deleted_files/usr/src/cmd/volmgt/vold/vold_obj.c
rename : usr/src/cmd/volmgt/vold/vold_path.c => deleted_files/usr/src/cmd/volmgt/vold/vold_path.c
rename : usr/src/cmd/volmgt/vold/vold_proc.c => deleted_files/usr/src/cmd/volmgt/vold/vold_proc.c
rename : usr/src/cmd/volmgt/vold/vold_props.c => deleted_files/usr/src/cmd/volmgt/vold/vold_props.c
rename : usr/src/cmd/volmgt/vold/vold_sysevent.c => deleted_files/usr/src/cmd/volmgt/vold/vold_sysevent.c
rename : usr/src/cmd/volmgt/vold/vold_util.c => deleted_files/usr/src/cmd/volmgt/vold/vold_util.c
rename : usr/src/cmd/volmgt/vold/vold_vol.c => deleted_files/usr/src/cmd/volmgt/vold/vold_vol.c
rename : usr/src/cmd/volmgt/vold/vtoc.c => deleted_files/usr/src/cmd/volmgt/vold/vtoc.c
rename : usr/src/cmd/volmgt/vold/vtoc.h => deleted_files/usr/src/cmd/volmgt/vold/vtoc.h
rename : usr/src/head/rmmount.h => deleted_files/usr/src/head/rmmount.h
rename : usr/src/lib/libvolmgt/common/volattr.c => deleted_files/usr/src/lib/libvolmgt/common/volattr.c
rename : usr/src/lib/libvolmgt/common/volmgt_fsi.c => deleted_files/usr/src/lib/libvolmgt/common/volmgt_fsi.c
rename : usr/src/lib/libvolmgt/common/volmgt_fsi_private.h => deleted_files/usr/src/lib/libvolmgt/common/volmgt_fsi_private.h
rename : usr/src/lib/libvolmgt/common/volmgt_fsidbi.c => deleted_files/usr/src/lib/libvolmgt/common/volmgt_fsidbi.c
rename : usr/src/lib/libvolmgt/common/volname.c => deleted_files/usr/src/lib/libvolmgt/common/volname.c
rename : usr/src/lib/libvolmgt/common/volutil.c => deleted_files/usr/src/lib/libvolmgt/common/volutil.c
rename : usr/src/pkgdefs/SUNWpcmem/preinstall => deleted_files/usr/src/pkgdefs/SUNWpcmem/preinstall
rename : usr/src/pkgdefs/SUNWvolr/Makefile => deleted_files/usr/src/pkgdefs/SUNWvolr/Makefile
rename : usr/src/pkgdefs/SUNWvolr/pkginfo.tmpl => deleted_files/usr/src/pkgdefs/SUNWvolr/pkginfo.tmpl
rename : usr/src/pkgdefs/SUNWvolr/postinstall => deleted_files/usr/src/pkgdefs/SUNWvolr/postinstall
rename : usr/src/pkgdefs/SUNWvolr/preinstall => deleted_files/usr/src/pkgdefs/SUNWvolr/preinstall
rename : usr/src/pkgdefs/SUNWvolr/prototype_com => deleted_files/usr/src/pkgdefs/SUNWvolr/prototype_com
rename : usr/src/pkgdefs/SUNWvolr/prototype_i386 => deleted_files/usr/src/pkgdefs/SUNWvolr/prototype_i386
rename : usr/src/pkgdefs/SUNWvolr/prototype_sparc => deleted_files/usr/src/pkgdefs/SUNWvolr/prototype_sparc
rename : usr/src/pkgdefs/SUNWvolu/Makefile => deleted_files/usr/src/pkgdefs/SUNWvolu/Makefile
rename : usr/src/pkgdefs/SUNWvolu/depend => deleted_files/usr/src/pkgdefs/SUNWvolu/depend
rename : usr/src/pkgdefs/SUNWvolu/pkginfo.tmpl => deleted_files/usr/src/pkgdefs/SUNWvolu/pkginfo.tmpl
rename : usr/src/pkgdefs/SUNWvolu/postremove => deleted_files/usr/src/pkgdefs/SUNWvolu/postremove
rename : usr/src/pkgdefs/SUNWvolu/prototype_com => deleted_files/usr/src/pkgdefs/SUNWvolu/prototype_com
rename : usr/src/pkgdefs/SUNWvolu/prototype_i386 => deleted_files/usr/src/pkgdefs/SUNWvolu/prototype_i386
rename : usr/src/pkgdefs/SUNWvolu/prototype_sparc => deleted_files/usr/src/pkgdefs/SUNWvolu/prototype_sparc
rename : usr/src/pkgdefs/common_files/i.rmmconf => deleted_files/usr/src/pkgdefs/common_files/i.rmmconf
rename : usr/src/pkgdefs/common_files/i.voldconf => deleted_files/usr/src/pkgdefs/common_files/i.voldconf
rename : usr/src/uts/common/io/vol.c => deleted_files/usr/src/uts/common/io/vol.c
rename : usr/src/uts/common/io/vol.conf => deleted_files/usr/src/uts/common/io/vol.conf
rename : usr/src/uts/common/sys/vol.h => deleted_files/usr/src/uts/common/sys/vol.h
rename : usr/src/uts/intel/vol/Makefile => deleted_files/usr/src/uts/intel/vol/Makefile
rename : usr/src/uts/sparc/vol/Makefile => deleted_files/usr/src/uts/sparc/vol/Makefile
rename : usr/src/cmd/volmgt/util/eject.c => usr/src/cmd/eject/eject.c
rename : usr/src/cmd/volmgt/util/volcheck.c => usr/src/cmd/volcheck/volcheck.c
Diffstat (limited to 'usr/src/uts/common/io/vol.c')
| -rw-r--r-- | usr/src/uts/common/io/vol.c | 3717 | 
1 files changed, 0 insertions, 3717 deletions
| diff --git a/usr/src/uts/common/io/vol.c b/usr/src/uts/common/io/vol.c deleted file mode 100644 index 64db74b970..0000000000 --- a/usr/src/uts/common/io/vol.c +++ /dev/null @@ -1,3717 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License").  You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc.  All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident	"%Z%%M%	%I%	%E% SMI" - -/* - * vol: the volume management driver - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/proc.h> -#include <sys/user.h> -#include <sys/cred.h> -#include <sys/file.h> -#include <sys/open.h> -#include <sys/poll.h> -#include <sys/errno.h> -#include <sys/ioccom.h> -#include <sys/cmn_err.h> -#include <sys/kmem.h> -#include <sys/uio.h> -#include <sys/cpu.h> -#include <sys/modctl.h> -#include <sys/stat.h> -#include <sys/dkio.h> -#include <sys/cdio.h> -#include <sys/fdio.h> -#include <sys/sysmacros.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/fdio.h> -#include <sys/vol.h> -#include <sys/session.h> -#include <sys/systm.h> -#include <sys/debug.h> - -/* - * NOTE: - * - * there was originally code in this module that would attempt to - * enqueue IO requests in a local queue if the reason for an IO - * failure was because the requested media was not present.  there - * was a kernel thread that would run automatically when the requested - * media was inserted and would attempt to restart the queued IO's once - * the media was present.  the code that enqueued the IO's had been - * ifdef'ed out for some time (since around version 1.27) due to some - * problems experienced with the sparc floppy driver.  finally, the - * rest of the code, including the kernel thread itself was removed, - * because it wasn't really being used and was wasting resources.  the - * code was removed as of version 1.67.  if you're interested in seeing - * it, please retrieve that version. - */ - -/* names */ -#define	VOLLONGNAME	"Volume Management Driver, %I%" -#define	VOLNBUFPROP	"nbuf"			/* number of bufs property */ - - -static char	*vold_root = NULL;		/* location of vol root */ -static size_t	vold_root_len = 0; -#define	VOL_ROOT_DEFAULT	"/vol"		/* default vold_root */ -#define	VOL_ROOT_DEFAULT_LEN	(strlen(VOL_ROOT_DEFAULT)) /* it's length */ - - -/* - * debug stuff - */ - -#ifndef	VOLDEBUG -#define	VOLDEBUG	0 -#endif - -int		voldebug = VOLDEBUG; - -#define	DPRINTF		if (voldebug > 0) printf -#define	DPRINTF2	if (voldebug > 1) printf -#define	DPRINTF3	if (voldebug > 2) printf -#define	DPRINTF4	if (voldebug > 3) printf - - -/* - * keep kvioc_queue and kvioc_event in sync.  It is important that - * kve_next and kve_prev are in the same order and relative position - * in the respective structures. - */ -struct kvioc_queue { -	struct kvioc_event *kve_next; -	struct kvioc_event *kve_prev; -}; - -struct kvioc_event { -	struct kvioc_event *kve_next; -	struct kvioc_event *kve_prev; -	struct vioc_event   kve_event; -}; - -/* - * Data required to interface ioctls between vold. - */ -struct vol_ioctl { -	kmutex_t	mutex; -	kcondvar_t	cv;		/* cond to wait for ioctl resp */ -	kcondvar_t	s_cv;		/* cond to serialize the ioctl */ -	kcondvar_t	close_cv;	/* cond to wait for unref */ -	uintptr_t	argp;		/* value passed to vold ioctl */ -	uintptr_t	rptr;		/* return pointer from vold */ -	int		rval;		/* return value from vold */ -	int		nwait;		/* # of threads waiting */ -	char		active;		/* set while waiting for a resp */ -	char		closing;	/* set while closing unit 0 */ -	char		closewait;	/* set while waiting for shutdown */ -}; - -/* - * private device info -- controlling device "volctl" - */ -static struct volctl { -	dev_info_t	*ctl_dip;	/* dev info */ -	struct buf	*ctl_bhead;	/* bufs to use for strategy */ -	uint_t		ctl_evcnt;	/* count of events on queue */ -	uint_t		ctl_maxunit;	/* largest unit # we've seen */ -	uint_t		ctl_open;	/* control port open flag */ -	int		ctl_daemon_pid;	/* pid of daemon at work */ -	struct kvioc_queue ctl_events;	/* queue of events for vold */ -	struct kvioc_event *ctl_evend;	/* pointer to end of queue */ -	ksema_t		ctl_bsema;	/* semaphore for vol_bhead */ -	kmutex_t	ctl_bmutex;	/* mutex for vol_bhead */ -	kmutex_t	ctl_muxmutex;	/* mutex for voltab */ -	kmutex_t	ctl_evmutex;	/* mutex for events */ -	kmutex_t	ctl_volrmutex;	/* mutex for vold_root */ -	struct vol_ioctl ctl_insert; -	struct vol_ioctl ctl_inuse; -	struct vol_ioctl ctl_symname; -	struct vol_ioctl ctl_symdev; -	uint_t		ctl_closing;	/* device being closed */ -} volctl; - -static struct pollhead vol_pollhead; - -/* - * private device info, per active minor node. - */ -struct vol_tab { -	dev_t		vol_dev;	/* stacked device */ -	struct dev_ops	*vol_devops;	/* stacked dev_ops */ -	uint_t		vol_bocnt; 	/* open count, block  */ -	uint_t		vol_cocnt; 	/* open count, character  */ -	uint_t		vol_locnt;	/* open count, layered */ -	uint_t		vol_flags;	/* miscellaneous flags */ -	int		vol_cancel;	/* cancel flag */ -	int		vol_unit;	/* minor number of this struct */ -	int		vol_mtype;	/* type of media (for checking) */ -	uint64_t	vol_id;		/* id of the volume */ -	char		*vol_path;	/* path of mapped device */ -	size_t		vol_pathlen;	/* length of above path */ -	kcondvar_t	vol_incv;	/* insertion condvar */ -	struct vol_ioctl vol_eject; -	struct vol_ioctl vol_attr; -	kmutex_t	vol_rwlck_mutex; /* mutex for rw lock */ -	kcondvar_t	vol_rwlck_cv;	/* cv for reader/writer lock */ -	uint_t		vol_nreader;	/* number of readers */ -	uint_t		vol_lckwaiter;	/* number of lock waiter */ -	uint_t		vol_refcnt;	/* number of references */ -	kcondvar_t	vol_rele_cv;	/* cv waiting for release */ -	char		vol_relewait;	/* release waiting flag */ -	char		vol_locked;	/* lock flag 1:READ 2:WRITE locked */ -}; - -#define	VOL_TAB_UNLOCKED	0 -#define	VOL_TAB_RD_LOCKED	1 -#define	VOL_TAB_WR_LOCKED	2 - -static void  *voltab;		/* dynamic voltab */ - -/* vol_flags */ -#define	ST_OPEN		0x0001		/* device is open */ -#define	ST_EXCL		0x0002		/* device is open exclusively */ -#define	ST_ENXIO	0x0004		/* return enxio till close */ -#define	ST_CHKMEDIA	0x0008		/* device should be checked b4 i/o */ -#define	ST_RDONLY	0x0010		/* volume is read-only */ - -/* vol_mtype */ -#define	MT_FLOPPY	0x0001		/* floppy that supports FDGETCHANGE */ - -/* flags to the vol_gettab function */ -#define	VGT_NOWAIT	0x01 -#define	VGT_WAITSIG	0x02 -#define	VGT_NEW		0x04 -#define	VGT_OPEN	0x08 -#define	VGT_CLOSE	0x10 -#define	VGT_NDELAY	0x20 - -/* local functions */ -static void 		vol_enqueue(enum vie_event type, void *data); -static int		vol_done(struct buf *bp); -static void		vol_cleanup(void); -static void		vol_unmap(struct vol_tab *); -static void		vol_checkwrite(struct vol_tab *tp, -				struct uio *uiop, int unit); -#ifdef _SYSCALL32_IMPL -static int		vol_event32(struct vioc_event32 *e32p, -				struct vioc_event *e); -#endif -static struct vol_tab 	*vol_gettab(int unit, -				uint_t flags, int *error); -static int		vol_checkmedia(struct vol_tab *tp, int *found_media); -static int		vol_checkmedia_machdep(struct vol_tab *tp); - -static void		vol_release_driver(struct vol_tab *tp); -static int		vol_daemon_check(void); - -static void		vol_ioctl_init(struct vol_ioctl *vic); -static void		vol_ioctl_fini(struct vol_ioctl *vic); -static int		vol_ioctl_enter(struct vol_ioctl *vic); -static int		vol_ioctl_wait(struct vol_ioctl *vic, -				int *rvalp, void *); -static void		vol_ioctl_exit(struct vol_ioctl *vic); -static void		vol_ioctl_fail(struct vol_ioctl *vic); -static void		vol_ioctl_enable(struct vol_ioctl *vic); -static int		vold_ioctl_enter(struct vol_ioctl *vic, void *rptrp); -static void		vold_ioctl_respond(struct vol_ioctl *vic, -				int rval, void *rptr); -static void		vold_ioctl_exit(struct vol_ioctl *vic); - -static void		vol_tab_init(struct vol_tab *tp); -static void		vol_tab_fini(struct vol_tab *tp); -static void		vol_tab_rlock(struct vol_tab *tp); -static int		vol_tab_rlock_sig(struct vol_tab *tp); -static void		vol_tab_rwlock_upgrade(struct vol_tab *tp); -static int		vol_tab_rwlock_upgrade_sig(struct vol_tab *tp); -static void		vol_tab_unlock(struct vol_tab *tp); -static void		vol_tab_rele(struct vol_tab *tp); -static void		vol_tab_unlock_and_rele(struct vol_tab *tp); -static void		vol_tab_rele_wait(struct vol_tab *tp); - -/* defaults */ -#define	DEFAULT_NBUF	20	/* default number of bufs to allocate */ -#define	DEFAULT_MAXUNIT	100	/* default number of minor units to alloc */ - -/* devsw ops */ -static int	volopen(dev_t *devp, int flag, int otyp, cred_t *credp); -static int	volclose(dev_t dev, int flag, int otyp, cred_t *credp); -static int	volstrategy(struct buf *bp); -static int	volread(dev_t dev, struct uio *uiop, cred_t *credp); -static int	volwrite(dev_t dev, struct uio *uiop, cred_t *credp); -static int	volprop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, -			int flags, char *name, caddr_t valuep, int *lengthp); -static int	volioctl(dev_t dev, int cmd, intptr_t arg, int mode, -			cred_t *credp, int *rvalp); -static int	volpoll(dev_t dev, short events, int anyyet, -			short *reventsp, struct pollhead **phpp); - -static struct cb_ops	vol_cb_ops = { -	volopen,		/* open */ -	volclose,		/* close */ -	volstrategy,		/* strategy */ -	nodev,			/* print */ -	nodev,			/* dump */ -	volread,		/* read */ -	volwrite,		/* write */ -	volioctl,		/* ioctl */ -	nodev,			/* devmap */ -	nodev,			/* mmap */ -	nodev,			/* segmap */ -	volpoll,		/* poll */ -	volprop_op,		/* prop_op */ -	(struct streamtab *)0,	/* streamtab */ -	D_NEW | D_MP | D_64BIT,	/* flags */ -}; - -static int	volattach(dev_info_t *dip, ddi_attach_cmd_t cmd); -static int	voldetach(dev_info_t *dip, ddi_detach_cmd_t cmd); -static int	volinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, -			void **result); - -static struct dev_ops	vol_ops = { -	DEVO_REV,		/* rev */ -	0,			/* refcnt */ -	volinfo,		/* info */ -	nulldev,		/* identify */ -	nulldev,		/* probe */ -	volattach,		/* attach */ -	voldetach,		/* detach */ -	nulldev,		/* reset */ -	&vol_cb_ops,		/* cb_ops */ -	(struct bus_ops *)0,	/* bus_ops */ -}; - -extern struct mod_ops	mod_pseudodrvops; -extern struct mod_ops	mod_driverops; - -extern int	ddi_create_internal_pathname(dev_info_t *dip, char *name, -		    int spec_type, minor_t minor_num); - -static struct modldrv	vol_driver_info = { -	&mod_driverops,		/* modops */ -	VOLLONGNAME,		/* name */ -	&vol_ops,		/* dev_ops */ -}; - -static struct modlinkage vol_linkage = { -	MODREV_1,			/* rev */ -	{				/* linkage */ -		&vol_driver_info, -		NULL, -		NULL, -		NULL, -	}, -}; - -static kmutex_t	floppy_chk_mutex; - -/* - * Virtual driver loader entry points - */ - -int -_init(void) -{ -	int ret; - -	DPRINTF("vol: _init\n"); - -	/* -	 * The ddi_soft_state code automatically grows the array -	 * when more is asked for.  DEFAULT_MAXUNIT is -	 * just a reasonable lower bound. -	 */ -	ret = ddi_soft_state_init(&voltab, sizeof (struct vol_tab), -	    DEFAULT_MAXUNIT); -	if (ret != 0) { -		cmn_err(CE_CONT, "vol: _init, could not init soft state"); -		return (-1); -	} - -	ret = mod_install(&vol_linkage); -	if (ret != 0) -		ddi_soft_state_fini(&voltab); - -	return (ret); -} - - -int -_fini(void) -{ -	int ret; - -	DPRINTF("vol: _fini\n"); -	ret = mod_remove(&vol_linkage); -	if (ret != 0) -		return (ret); - -	ddi_soft_state_fini(&voltab); -	return (0); -} - - -int -_info(struct modinfo *modinfop) -{ -	DPRINTF("vol: _info: modinfop %p\n", (void *)modinfop); -	return (mod_info(&vol_linkage, modinfop)); -} - - -/* - * Driver administration entry points - */ -static int -volattach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ -	struct vol_tab	*tp; -	int		unit; -	int		length; -	int		nbuf; -	int		i; -	int		err = DDI_SUCCESS; - -	DPRINTF("vol: attach: %d: dip %p cmd 0x%x\n", -	    ddi_get_instance(dip), (void *)dip, (int)cmd); - -	unit = ddi_get_instance(dip); - -	/* check unit */ -	if (unit != 0) -		return (ENXIO); - -	/* check command */ -	if (cmd != DDI_ATTACH) { -		cmn_err(CE_CONT, "vol: attach: %d: unknown cmd %d\n", -		    unit, cmd); -		return (DDI_FAILURE); -	} - -	if (volctl.ctl_dip != NULL) { -		cmn_err(CE_CONT, -		    "vol: attach: %d: already attached\n", unit); -		return (DDI_FAILURE); -	} - -	/* clear device entry, initialize locks, and save dev info */ -	bzero(&volctl, sizeof (volctl)); -	volctl.ctl_dip = dip; - -	/* get number of buffers, must use DDI_DEV_T_ANY */ -	length = sizeof (nbuf); -	if ((err = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, -	    0, VOLNBUFPROP, (caddr_t)&nbuf, &length)) != DDI_SUCCESS) { -		DPRINTF("vol: couldn't get nbuf prop, using default %d\n", -		    DEFAULT_NBUF); -		nbuf = DEFAULT_NBUF; -		err = 0;	/* no biggie */ -	} - -	DPRINTF2("vol: attach: %d: nbuf %d\n", ddi_get_instance(dip), nbuf); - -	sema_init(&volctl.ctl_bsema, 0, NULL, SEMA_DRIVER, NULL); - -	/* allocate buffers to stack with */ -	volctl.ctl_bhead = NULL; -	for (i = 0; (i < nbuf); ++i) { -		struct buf	*bp; - -		if ((bp = getrbuf(KM_NOSLEEP)) == NULL) { -			cmn_err(CE_CONT, -			    "vol: attach: %d: could not allocate buf\n", unit); -			err = ENOMEM; -			goto out; -		} -		bp->b_chain = volctl.ctl_bhead; -		volctl.ctl_bhead = bp; -		sema_v(&volctl.ctl_bsema); -	} - -	/* create minor node for /dev/volctl */ -	if ((err = ddi_create_minor_node(dip, VOLCTLNAME, S_IFCHR, -	    0, DDI_PSEUDO, 0)) != DDI_SUCCESS) { -		cmn_err(CE_CONT, -		    "vol: attach: %d: ddi_create_minor_node '%s' failed\n", -		    unit, VOLCTLNAME); -		goto out; -	} - -	/* -	 * build our 'tp' for unit 0.  makes things look better below -	 */ -	(void) ddi_soft_state_zalloc(voltab, 0); -	if ((tp = (struct vol_tab *)ddi_get_soft_state(voltab, 0)) == NULL) { -		cmn_err(CE_CONT, "vol: attach, could not get soft state"); -		err = DDI_FAILURE; -		goto out; -	} - -	/* build the mapping */ -	tp->vol_dev = NODEV; -	tp->vol_devops = NULL; - -	/* initialize my linked list */ -	volctl.ctl_events.kve_next = -	    (struct kvioc_event *)&volctl.ctl_events; -	volctl.ctl_evcnt = 0; -	volctl.ctl_evend = NULL; - -out: -	/* cleanup or return success */ -	if (err != DDI_SUCCESS) { -		ddi_remove_minor_node(dip, NULL); -		while (volctl.ctl_bhead != NULL) { -			struct buf	*bp; - -			bp = volctl.ctl_bhead; -			volctl.ctl_bhead = bp->b_chain; -			freerbuf(bp); -		} -		sema_destroy(&volctl.ctl_bsema); -		bzero(&volctl, sizeof (volctl)); -		return (err); -	} - -	mutex_init(&volctl.ctl_bmutex, NULL, MUTEX_DRIVER, NULL); -	mutex_init(&volctl.ctl_muxmutex, NULL, MUTEX_DRIVER, NULL); -	mutex_init(&volctl.ctl_evmutex, NULL, MUTEX_DRIVER, NULL); -	mutex_init(&volctl.ctl_volrmutex, NULL, MUTEX_DRIVER, NULL); -	vol_ioctl_init(&volctl.ctl_insert); -	vol_ioctl_init(&volctl.ctl_inuse); -	vol_ioctl_init(&volctl.ctl_symname); -	vol_ioctl_init(&volctl.ctl_symdev); - -	ddi_report_dev(dip); - -	return (DDI_SUCCESS); -} - - -static int -voldetach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ -	int		unit; -	int		stat; - -	DPRINTF("vol: detach: %d: dip %p cmd %d\n", ddi_get_instance(dip), -	    (void *)dip, (int)cmd); - -	/* get and check unit */ -	if ((unit = ddi_get_instance(dip)) != 0) -		return (ENXIO); - -	switch (cmd) { -		/* cleanup and detach */ -	case DDI_DETACH: -		/* -		 * if the daemon has us open, say no without looking -		 * any further. -		 */ -		if (volctl.ctl_open != 0) -			return (DDI_FAILURE); -		/* -		 * Free various data structures that have been allocated -		 * behind our back. -		 */ -		ddi_soft_state_free(voltab, 0); - -		/* -		 * Return our bufs to the world. -		 */ -		while (volctl.ctl_bhead != NULL) { -			struct buf	*bp; - -			bp = volctl.ctl_bhead; -			volctl.ctl_bhead = bp->b_chain; -			freerbuf(bp); -		} - -		/* -		 * Get rid of our various locks. -		 */ -		sema_destroy(&volctl.ctl_bsema); -		mutex_destroy(&volctl.ctl_bmutex); -		mutex_destroy(&volctl.ctl_muxmutex); -		mutex_destroy(&volctl.ctl_evmutex); -		mutex_destroy(&volctl.ctl_volrmutex); -		vol_ioctl_fini(&volctl.ctl_insert); -		vol_ioctl_fini(&volctl.ctl_inuse); -		vol_ioctl_fini(&volctl.ctl_symname); -		vol_ioctl_fini(&volctl.ctl_symdev); - -		/* -		 * A nice fresh volctl, for the next attach. -		 */ -		bzero(&volctl, sizeof (volctl)); - -		stat = DDI_SUCCESS; -		break; - -	default: -		cmn_err(CE_CONT, "vol: detach: %d: unknown cmd %d\n", -		    unit, cmd); -		stat = DDI_FAILURE; -		break; -	} -	return (stat); -} - - -/* ARGSUSED */ -static int -volinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) -{ -	dev_t		dev = (dev_t)arg; -	int		unit = getminor(dev); -	int		err = DDI_FAILURE; - -	DPRINTF("vol: info: dip %p cmd %d arg %p (%u.%u) result %p\n", -	    (void *)dip, (int)cmd, arg, getmajor(dev), unit, (void *)result); - -	/* process command */ -	switch (cmd) { -	case DDI_INFO_DEVT2INSTANCE: -		*result = (void *)0;		/* only instance zero */ -		err = DDI_SUCCESS; -		break; - -	case DDI_INFO_DEVT2DEVINFO: -		if (volctl.ctl_dip) { -			*result = (void *)volctl.ctl_dip; -			err = DDI_SUCCESS; -		} -		break; - -	default: -		cmn_err(CE_CONT, "vol: info: %d: unknown cmd %d\n", -		    unit, cmd); -		break; -	} - -	return (err); -} - - -/* - * Common entry points - */ - -/* ARGSUSED3 */ -static int -volopen(dev_t *devp, int flag, int otyp, cred_t *credp) -{ -	int		unit; -	struct vol_tab	*tp; -	int		err = 0; -	uint_t		gflags; - -	DPRINTF("vol: open: devp %p (%u.%u) flag %x otyp %x credp %p\n", -	    (void *)devp, (int)getmajor(*devp), (int)getminor(*devp), -	    flag, otyp, (void *)credp); - -	unit = getminor(*devp); -	gflags = VGT_NEW | VGT_WAITSIG; - -	/* implement non-blocking open */ -	if (flag & FNDELAY) -		gflags |= VGT_NDELAY; - -	if (unit == 0) { -		if (otyp != OTYP_CHR) -			return (EINVAL); -		gflags |= VGT_OPEN; -	} - -	/* get our vol structure for this unit */ -	if ((tp = vol_gettab(unit, gflags, &err)) == NULL) { -		DPRINTF("vol: open: gettab on unit %d, err %d\n", unit, err); -		if (err == EAGAIN) -			err = EIO;		/* convert to usable errno */ -		return (err); -	} - -	/* -	 * wrlock upgrade creates a race where other threads can -	 * modify flags while unlocking the rlock. -	 * We need write lock before testing all the flags. -	 */ -	if (vol_tab_rwlock_upgrade_sig(tp)) { -		/* we've lost the lock */ -		vol_tab_rele(tp); -		return (EINTR); -	} - -	/* check for opening read-only with write flag set */ -	if ((flag & FWRITE) && (tp->vol_flags & ST_RDONLY)) { -		vol_tab_unlock_and_rele(tp); -		return (EROFS); -	} - -	/* implement exclusive use */ -	if (((flag & FEXCL) && (tp->vol_flags & ST_OPEN)) || -	    (tp->vol_flags & ST_EXCL)) { -		vol_tab_unlock_and_rele(tp); -		return (EBUSY); -	} - -	if (unit == 0 && (tp->vol_flags & ST_OPEN) == 0) -		volctl.ctl_open = 1; - -	if (flag & FEXCL) -		tp->vol_flags |= ST_EXCL; - -	/* count and flag open */ -	if (otyp == OTYP_BLK) { -		tp->vol_bocnt = 1;	/* user block device open */ -	} else if (otyp == OTYP_CHR) { -		tp->vol_cocnt = 1;	/* user character device */ -	} else { -		tp->vol_locnt++;	/* kernel open */ -	} - -	tp->vol_flags |= ST_OPEN; - -	/* release lock, and return */ -	vol_tab_unlock_and_rele(tp); -	return (0); -} - - -/* ARGSUSED3 */ -static int -volclose(dev_t dev, int flag, int otyp, cred_t *credp) -{ -	int		unit; -	struct vol_tab	*tp; -	int		err; - -	DPRINTF("vol: close: dev %u.%u flag %x otyp %x credp %p\n", -	    (int)getmajor(dev), (int)getminor(dev), flag, otyp, (void *)credp); - -	unit = getminor(dev); - -	if ((tp = vol_gettab(unit, VGT_NOWAIT, &err)) == NULL) { -		/* unit 0 has already been closed */ -		return (0); -	} - -	vol_tab_rwlock_upgrade(tp); - -	if (otyp == OTYP_BLK) { -		tp->vol_bocnt = 0;	/* block opens */ -	} else if (otyp == OTYP_CHR) { -		tp->vol_cocnt = 0;	/* character opens */ -	} else { -		tp->vol_locnt--;	/* kernel opens */ -	} - -	if ((tp->vol_bocnt == 0) && (tp->vol_cocnt == 0) && -	    (tp->vol_locnt == 0)) { -		tp->vol_flags &= ~(ST_OPEN|ST_EXCL); -		/* -		 * ST_ENXIO should be cleared on the last close. -		 * Otherwise, there is no way to reset the flags -		 * other than killing the vold. -		 */ -		tp->vol_flags &= ~ST_ENXIO; -	} - -	/* -	 * If we've closed the device clean up after ourselves -	 */ -	if (((tp->vol_flags & ST_OPEN) == 0) && (unit != 0)) { -#ifdef	NOT_NEEDED -		/* -		 * unmapping here means that every close unmaps so every open -		 * will have to remap -		 */ -		(void) mutex_enter(&volctl.ctl_muxmutex); -		vol_unmap(tp); -		/* "tp" is invalid after vol_unmap!!! */ -		(void) mutex_exit(&volctl.ctl_muxmutex); -#endif -		vol_enqueue(VIE_CLOSE, (void *)&unit); -	} - -	if (unit == 0) { -		/* vold is no longer responding */ -		volctl.ctl_daemon_pid = 0; - -		/* closing unit 0 by vold. clean up all vol_tabs */ -		vol_cleanup(); - -		/* -		 * we've grabbed write lock for vol_tab unit#0, so no race -		 * between open to drop the ctl_open. -		 */ -		volctl.ctl_open = 0; -	} - -	/* release lock */ -	vol_tab_unlock_and_rele(tp); - -	/* done */ -	return (0); -} - - -static int -volstrategy(struct buf *bp) -{ -	int		unit; -	struct vol_tab	*tp; -	struct buf	*mybp; -	int		err = 0; - -	DPRINTF2("vol: strategy: bp %p dev %u.%u off %lu len %ld\n", -	    (void *)bp, getmajor(bp->b_edev), getminor(bp->b_edev), -	    (unsigned long)dbtob(bp->b_blkno), bp->b_bcount); - -	unit = getminor(bp->b_edev); -	if (unit == 0) { -		bp->b_resid = bp->b_bcount; -		bioerror(bp, ENXIO); -		biodone(bp); -		return (0); -	} - -	if ((tp = vol_gettab(unit, VGT_WAITSIG, &err)) == NULL) { -		bp->b_resid = bp->b_bcount; -		bioerror(bp, err); -		biodone(bp); -		DPRINTF("vol: strategy: gettab error %d\n", err); -		return (0); -	} - -	if ((tp->vol_flags & ST_OPEN) == 0) { -		/* it's not even open */ -		bp->b_resid = bp->b_bcount; -		bioerror(bp, ENXIO); -		vol_tab_unlock_and_rele(tp); -		biodone(bp); -		DPRINTF("vol: strategy: device not even open (ENXIO)\n"); -		return (0); -	} - -	/* allocate new buffer */ -	sema_p(&volctl.ctl_bsema); -	mutex_enter(&volctl.ctl_bmutex); - -	if (volctl.ctl_bhead == NULL) { -		panic("vol: strategy: bhead == NULL"); -		/*NOTREACHED*/ -	} - -	mybp = volctl.ctl_bhead; -	volctl.ctl_bhead = mybp->b_chain; -	mutex_exit(&volctl.ctl_bmutex); - -	/* setup buffer */ -	ASSERT(tp->vol_dev != NODEV); -	*mybp = *bp;		/* structure copy */ -	mybp->b_forw = mybp->b_back = mybp; -	mybp->av_forw = mybp->av_back = NULL; -	mybp->b_dev = cmpdev(tp->vol_dev); -	mybp->b_iodone = vol_done; -	mybp->b_edev = tp->vol_dev; -	mybp->b_chain = bp;	/* squirrel away old buf for vol_done */ -	sema_init(&mybp->b_io, 0, NULL, SEMA_DRIVER, NULL); -	sema_init(&mybp->b_sem, 0, NULL, SEMA_DRIVER, NULL); - -	if (tp->vol_flags & ST_CHKMEDIA) { -		err = vol_checkmedia(tp, NULL); -		if (err) { -			if (err == EINTR) -				vol_tab_rele(tp); -			else -				vol_tab_unlock_and_rele(tp); - -			/* free buffer */ -			mutex_enter(&volctl.ctl_bmutex); -			mybp->b_chain = volctl.ctl_bhead; -			volctl.ctl_bhead = mybp; -			mutex_exit(&volctl.ctl_bmutex); - -			/* release semaphore */ -			sema_v(&volctl.ctl_bsema); - -			bp->b_resid = bp->b_bcount; -			bioerror(bp, err); -			biodone(bp); -			DPRINTF("vol: strategy: precheck failed, error %d\n", -			    err); -			return (0); -		} -	} - -	/* release lock, pass request on to stacked driver */ -	vol_tab_unlock_and_rele(tp); - -	/* pass request on to stacked driver */ -	return (bdev_strategy(mybp)); -} - - -static int -vol_done(struct buf *mybp) -{ -	struct buf		*bp = mybp->b_chain; - -	DPRINTF2("vol: done: mybp %p bp %p dev %u.%u off %lu len %ld\n", -	    (void *)mybp, (void *)bp, getmajor(bp->b_edev), -	    getminor(bp->b_edev), (unsigned long)dbtob(bp->b_blkno), -	    bp->b_bcount); - -	/* -	 * See NOTE comment at beginning of this module about code that -	 * used to queue failed IO requests. -	 */ -	if (mybp->b_error) { -		DPRINTF("vol: error %d from device (should retry)\n", -		    mybp->b_error); -	} - -	/* copy status */ -	bp->b_flags = mybp->b_flags; -	bp->b_un = mybp->b_un; -	bp->b_resid = mybp->b_resid; -	bp->b_error = mybp->b_error; - -	/* free buffer */ -	mutex_enter(&volctl.ctl_bmutex); -	mybp->b_chain = volctl.ctl_bhead; -	volctl.ctl_bhead = mybp; -	mutex_exit(&volctl.ctl_bmutex); - -	/* release semaphore */ -	sema_v(&volctl.ctl_bsema); - -	/* continue on with biodone() */ -	biodone(bp); -	return (0); -} - - -/* ARGSUSED */ -static int -volread(dev_t dev, struct uio *uiop, cred_t *credp) -{ -	struct vol_tab	*tp; -	int		unit; -	int		err = 0; -	int		err1; -	int		found_media; - -	DPRINTF2("vol: read: dev %u.%u uiop %p credp %p\n", -	    getmajor(dev), getminor(dev), (void *)uiop, -	    (void *)credp); - -	unit = getminor(dev); -	if (unit == 0) { -		return (ENXIO); -	} - -	if ((tp = vol_gettab(unit, VGT_WAITSIG, &err)) == NULL) { -		DPRINTF("vol: read: gettab on unit %d, err %d\n", unit, err); -		if (err == EAGAIN) { -			err = EIO;		/* convert to usable errno */ -		} -		return (err); -	} - -	if ((tp->vol_flags & ST_OPEN) == 0) { -		err = ENXIO; -		goto out; -	} - -	if (tp->vol_flags & ST_CHKMEDIA) { -		err = vol_checkmedia(tp, NULL); -		if (err) { -			if (err == EINTR) { -				vol_tab_rele(tp); -				return (EINTR); -			} -			goto out; -		} -	} - -	for (;;) { -		/* read data */ -		if (tp->vol_dev == NODEV) { -			DPRINTF("vol: read: no device\n"); -			err = ENXIO; -			goto out; -		} - -		err = cdev_read(tp->vol_dev, uiop, kcred); - -		if (err && tp->vol_flags & ST_CHKMEDIA) { -			err1 = vol_checkmedia(tp, &found_media); -			if (err1 == EINTR) { -				vol_tab_rele(tp); -				return (EINTR); -			} -			/* -			 * if we got an error and media was actually -			 * in the drive, just return the error. -			 */ -			if (found_media) { -				break; -			} - -			/* -			 * probably a cancel on the i/o. -			 */ -			if (err1) { -				err = err1; -				break; -			} -		} else { -			break; -		} -	} - -	/* release lock, return success */ -out: -	vol_tab_unlock_and_rele(tp); -	return (err); -} - - -/* ARGSUSED */ -static int -volwrite(dev_t dev, struct uio *uiop, cred_t *credp) -{ -	struct vol_tab	*tp; -	int		unit; -	int		err = 0; -	int		err1; -	int		found_media; - -	DPRINTF2("vol: write: dev %u.%u uiop %p credp %p\n", -	    getmajor(dev), getminor(dev), (void *)uiop, -	    (void *)credp); - -	unit = getminor(dev); -	if (unit == 0) { -		return (ENXIO); -	} - -	if ((tp = vol_gettab(unit, VGT_WAITSIG, &err)) == NULL) { -		DPRINTF("vol: write: gettab on unit %d, err %d\n", unit, err); -		if (err == EAGAIN) { -			err = EIO;		/* convert to usable errno */ -		} -		return (err); -	} - -	if ((tp->vol_flags & ST_OPEN) == 0) { -		err = ENXIO; -		goto out; -	} - -	vol_checkwrite(tp, uiop, unit); - -	if (tp->vol_flags & ST_CHKMEDIA) { -		err = vol_checkmedia(tp, NULL); -		if (err) { -			if (err == EINTR) { -				vol_tab_rele(tp); -				return (EINTR); -			} -			goto out; -		} -	} - -	for (;;) { -		/* write data */ -		if (tp->vol_dev == NODEV) { -			DPRINTF("vol: write: no device"); -			err = ENXIO; -			goto out; -		} - -		err = cdev_write(tp->vol_dev, uiop, kcred); - -		if (err && tp->vol_flags & ST_CHKMEDIA) { -			err1 = vol_checkmedia(tp, &found_media); -			if (err1 == EINTR) { -				vol_tab_rele(tp); -				return (EINTR); -			} -			/* -			 * if we got an error and media was actually -			 * in the drive, just return the error. -			 */ -			if (found_media) { -				break; -			} - -			/* -			 * probably a cancel on the i/o. -			 */ -			if (err1) { -				err = err1; -				break; -			} -		} else { -			break; -		} -	} - -	/* release lock, return err */ -out: -	vol_tab_unlock_and_rele(tp); -	return (err); -} - - -/* - * Check the write to see if we are writing over the label - * on this unit.  If we are, let the daemon know. - */ -static void -vol_checkwrite(struct vol_tab *tp, struct uio *uiop, int unit) -{ -	/* -	 * XXX: this is VERY incomplete. -	 * This only works with a full label write of the Sun label. -	 */ -	if (uiop->uio_loffset == 0) { -		vol_enqueue(VIE_NEWLABEL, (void *)&unit); -		/* -		 * We now need to invalidate the blocks that -		 * are cached for both the device we point at. -		 * Odds are good that the label was written -		 * through the raw device, and we don't want to -		 * read stale stuff. -		 */ -		binval(tp->vol_dev);		/* XXX: not DDI compliant */ -	} -} - - -static int -volprop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, -	int flags, char *name, caddr_t valuep, int *lengthp) -{ -	int		unit; -	struct vol_tab	*tp; -	dev_info_t	*stackdip; -	int		err = 0; - -	DPRINTF2("vol: prop_op: dev %u.%u dip %p prop_op %d flags %x\n", -	    getmajor(dev), getminor(dev), (void *)dip, (int)prop_op, -	    flags); -	DPRINTF2("     name '%s' valuep %p lengthp %p\n", -	    name, (void *)valuep, (void *)lengthp); - -	/* send our props on to ddi_prop_op */ -	if (strcmp(name, "instance") == 0 || -	    strcmp(name, VOLNBUFPROP) == 0) { -		err = ddi_prop_op(dev, dip, prop_op, flags, -		    name, valuep, lengthp); -		return (err); -	} - -	unit = getminor(dev); -	if (unit == 0) { -		return (DDI_PROP_NOT_FOUND); -	} - -	if ((tp = vol_gettab(unit, VGT_NOWAIT, &err)) == NULL) { -		DPRINTF("vol: prop_op: gettab on unit %d, err %d\n", unit, -		    err); -		return (DDI_PROP_NOT_FOUND); -	} - -	if (err) { -		err = DDI_PROP_NOT_FOUND; -		goto out; -	} - -	/* get stacked dev info */ -	ASSERT(tp->vol_devops != NULL); -	if ((err = (*(tp->vol_devops->devo_getinfo))(NULL, -	    DDI_INFO_DEVT2DEVINFO, (void *)tp->vol_dev, (void *)&stackdip)) -	    != DDI_SUCCESS) { -		cmn_err(CE_CONT, -		    "vol: prop_op: %d: could not get child dev info err %d\n", -		    unit, err); -		err = DDI_PROP_NOT_FOUND; -		goto out; -	} - -	/* pass request on to stacked driver */ -	err = cdev_prop_op(tp->vol_dev, stackdip, prop_op, flags, -	    name, valuep, lengthp); - -	if (err) { -		DPRINTF("vol: cdev_prop_op: err = %d\n", err); -	} - -	/* release lock, return err */ -out: -	vol_tab_unlock_and_rele(tp); -	return (err); -} - - -/* ARGSUSED */ -static int -volioctl(dev_t dev, int cmd, intptr_t arg, int mode, -	cred_t *credp, int *rvalp) -{ -	int		unit, tunit; -	struct vol_tab	*tp; -	int		err = 0; -	dev_t		udev; - -	DPRINTF("volioctl: dev=%u.%u cmd=%x arg=%lx mode=%x\n", -	    getmajor(dev), getminor(dev), cmd, arg, mode); - -	unit = getminor(dev); -	if (unit == 0) { -		/* commands from vold */ -		switch (cmd) { - -		/* -		 * The daemon will call this if it's using the driver. -		 */ -		case VOLIOCDAEMON: { -			pid_t pid = (pid_t)arg; - -			if (drv_priv(credp) != 0) { -				err = EPERM; -				break; -			} -			mutex_enter(&volctl.ctl_muxmutex); -			if (volctl.ctl_daemon_pid == 0) { -				volctl.ctl_daemon_pid = pid; -			} else { -				if (vol_daemon_check() == 0) { -					/* i'm vold who can change pid */ -					volctl.ctl_daemon_pid = pid; -				} else { -					/* already a daemon running! */ -					err = EBUSY; -				} -			} -			mutex_exit(&volctl.ctl_muxmutex); -#ifdef VOL_CLEANUP_BY_DAEMON -			if (volctl.ctl_daemon_pid == 0) { -				/* no daemon. clean up */ -				vol_cleanup(); -			} -#endif -			break; -		} - -		/* -		 * Establish a mapping between a unit (minor number) -		 * and a lower level driver (dev_t). -		 */ -		case VOLIOCMAP: { -			STRUCT_DECL(vioc_map, vim); -			struct dev_ops *devp; -			char	*path; -			uint_t	pathlen; - -			if ((err = vol_daemon_check()) != 0) -				break; - -			STRUCT_INIT(vim, mode & FMODELS); -			if (ddi_copyin((void *)arg, STRUCT_BUF(vim), -			    STRUCT_SIZE(vim), mode) != 0) { -				DPRINTF("vol: map:copyin broke\n"); -				err = EFAULT; -				break; -			} -			/* don't allow mapping for unit 0 */ -			if ((tunit = STRUCT_FGET(vim, vim_unit)) == 0) { -				err = EINVAL; -				break; -			} -			/* pathname cannot be longer than MAXPATHLEN */ -			pathlen = STRUCT_FGET(vim, vim_pathlen); -			if (pathlen >= MAXPATHLEN) { -				err = ENAMETOOLONG; -				break; -			} -			path = NULL; -			if (pathlen != 0) { -				path = kmem_alloc(pathlen + 1, KM_SLEEP); -				if (ddi_copyin(STRUCT_FGETP(vim, vim_path), -				    path, pathlen, mode)) { -					kmem_free(path, pathlen + 1); -					err = EFAULT; -					break; -				} -				path[pathlen] = '\0'; -			} - -			/* copyins complete, get vol_tab */ -			tp = vol_gettab(tunit, VGT_NOWAIT|VGT_NEW, &err); -			if (tp == NULL) { -				DPRINTF("vol: map:null on vol %u, err %d\n", -				    (uint_t)tunit, err); -				if (path != NULL) -					kmem_free(path, pathlen + 1); -				break; -			} -			err = 0; - -			if ((mode & FMODELS) == FNATIVE) -				udev = STRUCT_FGET(vim, vim_dev); -			else -				udev = expldev(STRUCT_FGET(vim, vim_dev)); - -			/* ready to grab the driver */ -			if (udev != NODEV) { -				devp = ddi_hold_driver(getmajor(udev)); -				if (devp == NULL) { -					DPRINTF("vol: map:hold_inst broke\n"); -					vol_tab_unlock_and_rele(tp); -					if (path != NULL) -						kmem_free(path, pathlen + 1); -					err = ENODEV; -					break; -				} -				DPRINTF3("vol: ioctl: holding driver %u\n", -				    getmajor(udev)); -			} - -			/* changing vol_tab, needs wlock(no interrupt) */ -			vol_tab_rwlock_upgrade(tp); - -			/* release old driver if it's been held */ -			vol_release_driver(tp); - -			tp->vol_path = path; -			tp->vol_pathlen = pathlen; -			tp->vol_id = STRUCT_FGET(vim, vim_id); - -			if (STRUCT_FGET(vim, vim_flags) & VIM_FLOPPY) { -				tp->vol_flags |= ST_CHKMEDIA; -				tp->vol_mtype = MT_FLOPPY; -			} else { -				/* clear data (in case of previous use) */ -				tp->vol_flags &= ~ST_CHKMEDIA; -				tp->vol_mtype = 0; -			} -			/* is this a read-only volume? */ -			if (STRUCT_FGET(vim, vim_flags) & VIM_RDONLY) { -				tp->vol_flags |= ST_RDONLY; -			} - -			mutex_enter(&volctl.ctl_muxmutex); -			/* -			 * if vim.vim_dev == NODEV, it means that the daemon -			 * is unblocking a "nodelay" request. -			 */ -			if (udev != NODEV) { -				/* build the mapping */ -				tp->vol_dev = udev; -				tp->vol_devops = devp; -				/* clear any pending cancel */ -				tp->vol_cancel = FALSE; -			} -			cv_broadcast(&tp->vol_incv); -			vol_tab_unlock(tp); -			mutex_exit(&volctl.ctl_muxmutex); -			vol_tab_rele(tp); -			break; -		} - -		/* -		 * Break a mapping established with the above -		 * map ioctl. -		 */ -		case VOLIOCUNMAP: { -			if ((err = vol_daemon_check()) != 0) -				break; -			if (ddi_copyin((caddr_t)arg, &tunit, -			    sizeof (tunit), mode) != 0) { -				DPRINTF("vol: unmap:copyin broke\n"); -				err = EFAULT; -				break; -			} -			if (tunit == 0) { -				err = EINVAL; -				break; -			} -			if ((tp = vol_gettab(tunit, VGT_NOWAIT, &err)) == NULL) -				break; -			vol_tab_rwlock_upgrade(tp); -			vol_release_driver(tp); -			vol_tab_unlock_and_rele(tp); -			break; -		} - -		/* -		 * Get an event.  This is used by calling this -		 * ioctl until it returns EWOULDBLOCK.  poll(2) -		 * is the mechanism for waiting around for an -		 * event to happen. -		 */ -		case VOLIOCEVENT: { -			struct kvioc_event *kve = NULL; - -			if ((err = vol_daemon_check()) != 0) -				break; -			mutex_enter(&volctl.ctl_evmutex); -			if (volctl.ctl_evcnt) { -				kve = volctl.ctl_events.kve_next; -				volctl.ctl_evcnt--; -				if (volctl.ctl_evcnt == 0) -					volctl.ctl_evend = NULL; -				remque(kve); -			} -			mutex_exit(&volctl.ctl_evmutex); -			if (kve == NULL) { -				err = EWOULDBLOCK; -				break; -			} -			if ((mode & FMODELS) == FNATIVE) { -				if (ddi_copyout(&kve->kve_event, (caddr_t)arg, -				    sizeof (kve->kve_event), mode) != 0) { -					err = EFAULT; -				} -			} -#ifdef _SYSCALL32_IMPL -			else { -				struct vioc_event32 e32; - -				err = vol_event32(&e32, &kve->kve_event); -				if (err == 0) { -					if (ddi_copyout(&e32, (caddr_t)arg, -					    sizeof (e32), mode) != 0) { -						err = EFAULT; -					} -				} -			} -#endif /* _SYSCALL32_IMPL */ -			if (err != 0 && err != EOVERFLOW) { -				/* add it back on err */ -				mutex_enter(&volctl.ctl_evmutex); -				insque(kve, &volctl.ctl_events); -				volctl.ctl_evcnt++; -				mutex_exit(&volctl.ctl_evmutex); -				DPRINTF("vol: event: copyout %d\n", err); -				break; -			} -			kmem_free(kve, sizeof (*kve)); -			break; -		} - - -		/* -		 * Deliver status (eject or don't eject) to a pending -		 * eject ioctl.  That ioctl will then send down the -		 * eject to the device (or not). -		 */ -		case VOLIOCEJECT: { -			STRUCT_DECL(vioc_eject, viej); -			enum eject_state status; - -			if ((err = vol_daemon_check()) != 0) -				break; -			STRUCT_INIT(viej, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(viej), -			    STRUCT_SIZE(viej), mode) != 0) { -				DPRINTF("VOLIOCEJECT: copyin error\n"); -				err = EFAULT; -				break; -			} -			if ((tunit = STRUCT_FGET(viej, viej_unit)) == 0) { -				err = EINVAL; -				break; -			} -			tp = vol_gettab(tunit, VGT_NOWAIT, &err); -			if (tp == NULL) { -				DPRINTF("VOLIOCEJECT: gettab error\n"); -				break; -			} -			status = STRUCT_FGET(viej, viej_state); -			if (status != VEJ_YES && -			    status != VEJ_NO && -			    status != VEJ_YESSTOP) { -				vol_tab_unlock_and_rele(tp); -				err = EINVAL; -				break; -			} -			if ((err = vold_ioctl_enter(&tp->vol_eject, -			    NULL)) != 0) { -				vol_tab_unlock_and_rele(tp); -				break; -			} -			vold_ioctl_respond(&tp->vol_eject, status, NULL); -			vold_ioctl_exit(&tp->vol_eject); -			vol_tab_unlock_and_rele(tp); -			break; -		} - -		/* Daemon response to setattr from user */ -		case VOLIOCDSATTR: { -			STRUCT_DECL(vioc_dattr, vda); -			int	attr_err; -			struct ve_attr *attr_ptr; - -			if ((err = vol_daemon_check()) != 0) -				break; -			STRUCT_INIT(vda, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vda), -			    STRUCT_SIZE(vda), mode) != 0) { -				err = EFAULT; -				break; -			} -			if ((tunit = STRUCT_FGET(vda, vda_unit)) == 0) { -				err = EINVAL; -				break; -			} -			if ((attr_err = STRUCT_FGET(vda, vda_errno)) < 0) { -				err = EINVAL; -				break; -			} -			tp = vol_gettab(tunit, VGT_NOWAIT, &err); -			if (tp == NULL) -				break; -			if ((err = vold_ioctl_enter(&tp->vol_attr, -			    &attr_ptr)) != 0) { -				vol_tab_unlock_and_rele(tp); -				break; -			} -			if (attr_ptr == NULL || attr_ptr->viea_unit != tunit) { -				/* shouldn't happen, but just in case */ -				err = EAGAIN; -			} else { -				vold_ioctl_respond(&tp->vol_attr, -				    attr_err, attr_ptr); -			} -			vold_ioctl_exit(&tp->vol_attr); -			vol_tab_unlock_and_rele(tp); -			break; -		} -		/* Daemon response to getattr from user */ -		case VOLIOCDGATTR: { -			STRUCT_DECL(vioc_dattr, vda); -			int	attr_err; -			struct	ve_attr *attr_ptr = NULL; - -			if ((err = vol_daemon_check()) != 0) -				break; -			STRUCT_INIT(vda, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vda), -			    STRUCT_SIZE(vda), mode) != 0) { -				err = EFAULT; -				break; -			} -			if ((tunit = STRUCT_FGET(vda, vda_unit)) == 0) { -				err = EINVAL; -				break; -			} -			if ((attr_err = STRUCT_FGET(vda, vda_errno)) < 0) { -				err = EINVAL; -				break; -			} -			tp = vol_gettab(tunit, VGT_NOWAIT, &err); -			if (tp == NULL) -				break; -			if ((err = vold_ioctl_enter(&tp->vol_attr, -			    &attr_ptr)) != 0) { -				vol_tab_unlock_and_rele(tp); -				break; -			} -			if (attr_err == 0 && attr_ptr != NULL) { -				char	*vstr; -				int	len; - -				vstr = STRUCT_FGETP(vda, vda_value); -				/* put end mark so that strlen never overrun */ -				vstr[MAX_ATTR_LEN -1] = '\0'; -				len = strlen(vstr); -				bcopy(vstr, attr_ptr->viea_value, len); -				attr_ptr->viea_value[len] = '\0'; -			} -			vold_ioctl_respond(&tp->vol_attr, attr_err, attr_ptr); -			vold_ioctl_exit(&tp->vol_attr); -			vol_tab_unlock_and_rele(tp); -			break; -		} - -		/* Daemon response to insert from user */ -		case VOLIOCDCHECK: -			if ((err = vol_daemon_check()) != 0) -				break; -			if ((int)arg < 0) { -				err = EINVAL; -				break; -			} -			if ((err = vold_ioctl_enter(&volctl.ctl_insert, -			    NULL)) != 0) -				break; -			vold_ioctl_respond(&volctl.ctl_insert, (int)arg, NULL); -			vold_ioctl_exit(&volctl.ctl_insert); -			break; - -		/* Daemon response to inuse from user */ -		case VOLIOCDINUSE: -			if ((err = vol_daemon_check()) != 0) -				break; -			if ((int)arg < 0) { -				err = EINVAL; -				break; -			} -			if ((err = vold_ioctl_enter(&volctl.ctl_inuse, -			    NULL)) != 0) -				break; -			vold_ioctl_respond(&volctl.ctl_inuse, (int)arg, NULL); -			vold_ioctl_exit(&volctl.ctl_inuse); -			break; - -		/* Daemon response to inuse from user */ -		case VOLIOCFLAGS: { -			STRUCT_DECL(vioc_flags, vfl); - -			if ((err = vol_daemon_check()) != 0) -				break; -			STRUCT_INIT(vfl, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vfl), -			    STRUCT_SIZE(vfl), mode) != 0) { -				err = EFAULT; -				break; -			} -			if ((tunit = STRUCT_FGET(vfl, vfl_unit)) == 0) { -				err = EINVAL; -				break; -			} -			tp = vol_gettab(tunit, VGT_NOWAIT, &err); -			if (tp == NULL) -				break; -			/* if we had an ENXIO error, then that's okay */ -			if (err == ENXIO || err == ENODEV) { -				DPRINTF( -				"volioctl: clearing gettab ENXIO or ENODEV\n"); -				err = 0; -			} - -			/* -			 * vol_gettab() returns the vol_tab struct pointed -			 * to by tp locked in reader mode -- but, to -			 * change something in that struct, we need to -			 * lock it in writer mode -			 */ -			vol_tab_rwlock_upgrade(tp); - -			/* set or clear the ST_ENXIO flag */ -			if (STRUCT_FGET(vfl, vfl_flags) & VFL_ENXIO) { -				tp->vol_flags |= ST_ENXIO; -#ifdef	DEBUG_ENXIO -				(void) printf( -	"volioctl: VOLIOCFLAGS(ST_ENXIO), unit %d (flags=0x%x, tp=%p)\n", -				    tunit, tp->vol_flags, (void *)tp); -#endif -			} else { -				tp->vol_flags &= ~ST_ENXIO; -#ifdef	DEBUG_ENXIO -				(void) printf( -	"volioctl: VOLIOCFLAGS(0), unit %d (flags=0x%x, tp=%p)\n", -				    tunit, tp->vol_flags, (void *)tp); -#endif -			} -			DPRINTF( -			    "vol: volioctl: %s ST_ENXIO flag for unit %u\n", -			    (STRUCT_FGET(vfl, vfl_flags) & VFL_ENXIO) ? -			    "set" : "cleared", tunit); - -			vol_tab_unlock_and_rele(tp); -			break; -		} - -		/* daemon response to symname request from user */ -		case VOLIOCDSYMNAME: { -			STRUCT_DECL(vol_str, vstr); -			char	*symname; -			size_t	symname_len; - -			if ((err = vol_daemon_check()) != 0) -				break; -			/* get the string struct */ -			STRUCT_INIT(vstr, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vstr), -			    STRUCT_SIZE(vstr), mode) != 0) { -				err = EFAULT; -				break; -			} -			symname_len = STRUCT_FGET(vstr, data_len); -			if (symname_len > VOL_SYMNAME_LEN) { -				err = EINVAL; -				break; -			} -			/* if any string to get then get it */ -			if (symname_len != 0) { -				/* allocate some memory for string */ -				symname = kmem_alloc(symname_len + 1, KM_SLEEP); -				/* grab the string */ -				if (ddi_copyin(STRUCT_FGETP(vstr, data), -				    symname, symname_len, mode) != 0) { -					kmem_free(symname, symname_len + 1); -					err = EFAULT; -					break; -				} -				symname[symname_len] = '\0'; -			} else { -				symname = NULL; -			} -			if ((err = vold_ioctl_enter(&volctl.ctl_symname, -			    NULL)) != 0) { -				if (symname != NULL) -					kmem_free(symname, symname_len + 1); -				break; -			} -			/* signal waiter that we have the info */ -			vold_ioctl_respond(&volctl.ctl_symname, -			    symname_len, symname); -			vold_ioctl_exit(&volctl.ctl_symname); -			break; -		} - -		/* daemon response to symdev request from user */ -		case VOLIOCDSYMDEV: { -			STRUCT_DECL(vol_str, vstr); -			char	*symdev; -			size_t	symdev_len; - -			if ((err = vol_daemon_check()) != 0) -				break; -			/* get the string */ -			STRUCT_INIT(vstr, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vstr), -			    STRUCT_SIZE(vstr), mode) != 0) { -				err = EFAULT; -				break; -			} -			symdev_len = STRUCT_FGET(vstr, data_len); -			if (symdev_len >= VOL_SYMDEV_LEN) { -				err = EINVAL; -				break; -			} -			if (symdev_len != 0) { -				/* get memory for string */ -				symdev = kmem_alloc(symdev_len + 1, KM_SLEEP); -				/* now get the dev string */ -				if (ddi_copyin(STRUCT_FGETP(vstr, data), -				    symdev, symdev_len, mode) != 0) { -					kmem_free(symdev, symdev_len + 1); -					err = EFAULT; -					break; -				} -				symdev[symdev_len] = '\0'; -			} else { -				symdev = NULL; -			} -			/* lock data struct */ -			if ((err = vold_ioctl_enter(&volctl.ctl_symdev, -			    NULL)) != 0) { -				if (symdev != NULL) -					kmem_free(symdev, symdev_len + 1); -				break; -			} -			/* signal waiter that we have the info */ -			vold_ioctl_respond(&volctl.ctl_symdev, -			    symdev_len, symdev); -			vold_ioctl_exit(&volctl.ctl_symdev); -			break; -		} - -		/* -		 * Begin: ioctls that joe random program can issue to -		 * the volctl device. -		 */ - -		/* -		 * Tell volume daemon to check for new media and wait -		 * for it to tell us if anything was there. -		 */ -		case VOLIOCCHECK: { -			dev_t	dev; -			int	rval; -			/* -			 * If there's no daemon, we already know the answer. -			 */ -			if (volctl.ctl_daemon_pid == 0) { -				err = ENXIO; -				break; -			} -			if ((err = vol_ioctl_enter(&volctl.ctl_insert)) != 0) -				break; -			if ((mode & FMODELS) == FNATIVE) -				dev = (dev_t)arg; -			else -				dev = expldev((dev32_t)arg); -			vol_enqueue(VIE_CHECK, (void *)&dev); -			err = vol_ioctl_wait(&volctl.ctl_insert, &rval, NULL); -			if (err == 0) -				err = rval; -			vol_ioctl_exit(&volctl.ctl_insert); -			break; -		} - -		/* -		 * ask the volume daemon if it is running (dev_t == -		 * this dev_t), or if it's controlling a particular -		 * device (any dev_t). -		 */ -		case VOLIOCINUSE: { -			dev_t	dev; -			int	rval; -			/* -			 * If there's no daemon, we already know the answer. -			 */ -			if (volctl.ctl_daemon_pid == 0) { -				err = ENXIO; -				break; -			} -			if ((err = vol_ioctl_enter(&volctl.ctl_inuse)) != 0) -				break; -			if ((mode & FMODELS) == FNATIVE) -				dev = (dev_t)arg; -			else -				dev = expldev((dev32_t)arg); -			vol_enqueue(VIE_INUSE, (void *)&dev); -			err = vol_ioctl_wait(&volctl.ctl_inuse, &rval, NULL); -			if (err == 0) -				err = rval; -			vol_ioctl_exit(&volctl.ctl_inuse); -			break; -		} - -		/* Cancel initiated from the daemon */ -		case VOLIOCCANCEL: { -			if ((err = vol_daemon_check()) != 0) -				break; -			if (ddi_copyin((caddr_t)arg, &tunit, -			    sizeof (tunit), mode) != 0) { -				DPRINTF("vol: cancel:copyin broke\n"); -				err = EFAULT; -				break; -			} -			if (tunit == 0) { -				err = EINVAL; -				break; -			} -			tp = vol_gettab(tunit, VGT_NOWAIT, &err); -			if (tp == NULL) -				break; -			if (err == ENXIO || err == ENODEV) -				err = 0; -			/* -			 * need wrlock as we are changing vol_cancel. -			 */ -			vol_tab_rwlock_upgrade(tp); -			mutex_enter(&volctl.ctl_muxmutex); -			DPRINTF("vol: doing cancel on %u\n", tunit); -			tp->vol_cancel = TRUE; -			cv_broadcast(&tp->vol_incv); -			vol_tab_unlock(tp); -			mutex_exit(&volctl.ctl_muxmutex); -			vol_tab_rele(tp); -			break; -		} - -		/* set the volmgt root dir (defaults to "/vol") */ -		case VOLIOCDROOT: { -			STRUCT_DECL(vol_str, vstr); -			char	*rptr; -			size_t	rlen; - -			if ((err = vol_daemon_check()) != 0) -				break; - -			mutex_enter(&volctl.ctl_volrmutex); -			/* can't set if already set */ -			if (vold_root != NULL) { -				/* error */ -				mutex_exit(&volctl.ctl_volrmutex); -				err = EAGAIN; -				break; -			} -			mutex_exit(&volctl.ctl_volrmutex); - -			STRUCT_INIT(vstr, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vstr), -			    STRUCT_SIZE(vstr), mode) != 0) { -				err = EFAULT; -				break; -			} -			rlen = STRUCT_FGET(vstr, data_len); -			if (rlen == 0 || rlen >= MAXPATHLEN) { -				err = EINVAL; -				break; -			} -			rptr = kmem_alloc(rlen + 1, KM_SLEEP); -			if (ddi_copyin(STRUCT_FGETP(vstr, data), -			    rptr, rlen, mode) != 0) { -				kmem_free(rptr, rlen + 1); -				err = EFAULT; -				break; -			} -			rptr[rlen] = '\0'; - -			mutex_enter(&volctl.ctl_volrmutex); -			if (vold_root != NULL) { -				/* someone has set the root */ -				kmem_free(rptr, rlen + 1); -				err = EAGAIN; -			} else { -				vold_root = rptr; -				vold_root_len = rlen; -			} -			mutex_exit(&volctl.ctl_volrmutex); -			break; -		} - -		/* return where the vol root is */ -		case VOLIOCROOT: { -			STRUCT_DECL(vol_str, vd); -			char	path[64], *rptr; - -			mutex_enter(&volctl.ctl_volrmutex); -			/* if no root set then punt */ -			if (vold_root == NULL) { -				/* allocate a default vol root */ -				vold_root = kmem_alloc(VOL_ROOT_DEFAULT_LEN + 1, -				    KM_SLEEP); -				vold_root_len = VOL_ROOT_DEFAULT_LEN; -				(void) strcpy(vold_root, VOL_ROOT_DEFAULT); -			} -			if (vold_root_len >= sizeof (path)) -				rptr = kmem_alloc(vold_root_len + 1, KM_SLEEP); -			else -				rptr = path; -			(void) bcopy(vold_root, rptr, vold_root_len + 1); -			mutex_exit(&volctl.ctl_volrmutex); - -			/* -			 * copy in struct to know buf size at target -			 * for vold_root -			 */ -			STRUCT_INIT(vd, get_udatamodel()); -			if (ddi_copyin((caddr_t)arg, STRUCT_BUF(vd), -			    STRUCT_SIZE(vd), mode) != 0) { -				err = EFAULT; -				goto rootout; -			} -			/* check if our str len is out of range */ -			if ((vold_root_len + 1) > STRUCT_FGET(vd, data_len)) { -				err = EINVAL; -				goto rootout; -			} -			/* all is ok, send back the vold_root */ -			if (ddi_copyout(rptr, STRUCT_FGETP(vd, data), -			    vold_root_len + 1, mode) != 0) { -				err = EFAULT; -			} -rootout: -			if (rptr != path) -				kmem_free(rptr, vold_root_len + 1); -			break; -		} - -		/* find a symname given a dev */ -		case VOLIOCSYMNAME: { -			STRUCT_DECL(vioc_symname, sn); -			dev_t	dev; -			char	*symname = NULL; -			int	symname_len = 0; - -			/* if there's no daemon then we can't check */ -			if (volctl.ctl_daemon_pid == 0) { -				err = ENXIO; -				break; -			} -			/* get the struct */ -			STRUCT_INIT(sn, get_udatamodel()); -			if (ddi_copyin((void *)arg, STRUCT_BUF(sn), -			    STRUCT_SIZE(sn), mode)) { -				err = EFAULT; -				break; -			} -			/* lock out others */ -			if ((err = vol_ioctl_enter(&volctl.ctl_symname)) != 0) -				break; -			/* tell the daemon that we want a symname */ -			if ((mode & FMODELS) == FNATIVE) -				dev = STRUCT_FGET(sn, sn_dev); -			else -				dev = expldev(STRUCT_FGET(sn, sn_dev)); -			vol_enqueue(VIE_SYMNAME, (void *)&dev); -			err = vol_ioctl_wait(&volctl.ctl_symname, -			    &symname_len, &symname); - -			/* return result (if not interrupted) */ -			if (err == 0) { -				/* is there enough room for the result ? */ -				if (symname_len >= -				    STRUCT_FGET(sn, sn_pathlen)) { -					DPRINTF( -				"volctl: no room for symname result\n"); -					err = EINVAL; -				} else if (symname_len == 0 || -				    symname == NULL) { -					DPRINTF( -					"volctl: no symname to copy out\n"); -					err = ENOENT; -				} else { -					if (ddi_copyout(symname, -					    STRUCT_FGETP(sn, sn_symname), -					    symname_len + 1, mode) != 0) { -						err = EFAULT; -					} -				} -			} -			/* -			 * vol_ioctl_wait() may have failed, but vold -			 * may have allocated symname. -			 */ -			if (symname_len != 0 && symname != NULL) -				kmem_free(symname, symname_len + 1); -			/* release lock */ -			vol_ioctl_exit(&volctl.ctl_symname); -			break; -		} - -		/* find a dev path given a symname */ -		case VOLIOCSYMDEV: { -			STRUCT_DECL(vioc_symdev, sd); -			struct ve_symdev	vesd; -			char	*symdev = NULL; -			int	symdev_len = 0; -			size_t	symname_len; - -			/* if there's no daemon then we can't check */ -			if (volctl.ctl_daemon_pid == 0) { -				err = ENXIO; -				break; -			} -			/* get the struct */ -			STRUCT_INIT(sd, get_udatamodel()); -			if (ddi_copyin((void *)arg, STRUCT_BUF(sd), -			    STRUCT_SIZE(sd), mode)) { -				err = EFAULT; -				break; -			} -			/* see if user is providing a length too long */ -			symname_len = STRUCT_FGET(sd, sd_symnamelen); -			if (symname_len == 0 || symname_len > VOL_SYMNAME_LEN) { -				err = EINVAL; -				break; -			} - -			/* don't copyout garbage */ -			bzero(&vesd, sizeof (vesd)); - -			/* get the symname */ -			if (ddi_copyin(STRUCT_FGETP(sd, sd_symname), -			    vesd.vied_symname, symname_len, mode) != 0) { -				err = EFAULT; -				break; -			} -			vesd.vied_symname[symname_len] = '\0'; - -			/* lock out others */ -			if ((err = vol_ioctl_enter(&volctl.ctl_symdev)) != 0) -				break; - -			/* tell the daemon that we want a symdev */ -			vol_enqueue(VIE_SYMDEV, (void *)&vesd); - -			/* wait for daemon to reply */ -			err = vol_ioctl_wait(&volctl.ctl_symdev, -			    &symdev_len, &symdev); - -			/* return result (if not interrupted) */ -			if (err == 0) { -				/* is there enough room for the result ? */ -				if (symdev_len >= STRUCT_FGET(sd, sd_pathlen)) { -					DPRINTF( -				"volctl: no room for symdev result\n"); -					err = EINVAL; -				} else if (symdev_len == 0 || -				    symdev == NULL) { -					DPRINTF( -					    "volctl: no symdev to copy out\n"); -					err = ENOENT; -				} else { -					if (ddi_copyout(symdev, -					    STRUCT_FGETP(sd, sd_symdevname), -					    symdev_len + 1, mode) != 0) { -						err = EFAULT; -					} -				} -			} -			/* free room */ -			if (symdev_len != 0 && symdev != NULL) -				kmem_free(symdev, symdev_len + 1); -			/* release lock */ -			vol_ioctl_exit(&volctl.ctl_symdev); -			break; -		} - -		/* -		 * Create minor name for unit -		 */ -		case VOLIOCCMINOR: { -			char	mname_chr[16]; -			char	mname_blk[16]; - -			if ((err = vol_daemon_check()) != 0) -				break; - -			if ((tunit = (minor_t)arg) == 0) { -				err = EINVAL; -				break; -			} -			ASSERT(volctl.ctl_dip); -			(void) snprintf(mname_blk, sizeof (mname_blk), -			    VOLUNITNAME_BLK, (int)tunit); -			(void) snprintf(mname_chr, sizeof (mname_chr), -			    VOLUNITNAME_CHR, tunit); - -			if (ddi_create_internal_pathname(volctl.ctl_dip, -			    mname_blk, S_IFBLK, tunit) != DDI_SUCCESS) -				err = ENODEV; -			else if (ddi_create_internal_pathname(volctl.ctl_dip, -			    mname_chr, S_IFCHR, tunit) != DDI_SUCCESS) { -				err = ENODEV; -				ddi_remove_minor_node(volctl.ctl_dip, -				    mname_blk); -			} -			break; -		} - -		/* -		 * Remove minor name for unit -		 */ -		case VOLIOCRMINOR: { -			char	mname[16]; - -			if ((err = vol_daemon_check()) != 0) -				break; - -			if ((tunit = (minor_t)arg) == 0) { -				err = EINVAL; -				break; -			} -			ASSERT(volctl.ctl_dip); -			(void) snprintf(mname, sizeof (mname), -			    VOLUNITNAME_BLK, (int)tunit); -			ddi_remove_minor_node(volctl.ctl_dip, mname); - -			(void) snprintf(mname, sizeof (mname), -			    VOLUNITNAME_CHR, (int)tunit); -			ddi_remove_minor_node(volctl.ctl_dip, mname); -			break; -		} - -		default: -			err = ENOTTY; -			break; -		} - -		if ((err != 0) && (err != EWOULDBLOCK)) { -			DPRINTF("vol: ioctl: err=%d (cmd=%x)\n", err, cmd); -		} - -		return (err); -		/*NOTREACHED*/ -	} - -	/* -	 * This set of ioctls are available to be executed without -	 * having the unit available. vol_gettab() can be interrupted -	 * by signal. -	 */ -	tp = vol_gettab(unit, VGT_NDELAY|VGT_NOWAIT|VGT_WAITSIG, &err); -	if (tp == NULL) -		return (err); -	err = 0; - -	switch (cmd) { -	case VOLIOCINFO: { -		/* -		 * Gather information about the unit.  This is specific to -		 * volume management. -		 * -		 * XXX: we should just return an error if the amount of space -		 * the user has allocated for our return value is too small, -		 * but instead we just truncate and return ... ?? -		 */ -		STRUCT_DECL(vioc_info, info); - -		STRUCT_INIT(info, get_udatamodel()); -		if (ddi_copyin((caddr_t)arg, STRUCT_BUF(info), -		    STRUCT_SIZE(info), mode) != 0) { -			vol_tab_unlock_and_rele(tp); -			return (EFAULT); -		} -		STRUCT_FSET(info, vii_inuse, tp->vol_bocnt + tp->vol_cocnt + -		    tp->vol_locnt); -		STRUCT_FSET(info, vii_id, tp->vol_id); - -		if (ddi_copyout(STRUCT_BUF(info), (caddr_t)arg, -		    STRUCT_SIZE(info), mode) != 0) { -			err = EFAULT; -		} -		if (err == 0 && -		    STRUCT_FGETP(info, vii_devpath) != NULL && -		    STRUCT_FGET(info, vii_pathlen) != 0 && -		    tp->vol_path != NULL) { -			if (ddi_copyout(tp->vol_path, STRUCT_FGETP(info, -			    vii_devpath), min(STRUCT_FGET(info, vii_pathlen), -			    tp->vol_pathlen) + 1, mode) != 0) { -				err = EFAULT; -			} -		} -		vol_tab_unlock_and_rele(tp); -		return (err); -	} - -	/* -	 * Cancel i/o pending (i.e. waiting in vol_gettab) on -	 * a device.  Cancel will persist until the last close. -	 */ -	case VOLIOCCANCEL: -		if (vol_tab_rwlock_upgrade_sig(tp)) { -			vol_tab_rele(tp); -			err = EINTR; -			break; -		} -		mutex_enter(&volctl.ctl_muxmutex); -		DPRINTF("vol: doing cancel on %d\n", unit); -		tp->vol_cancel = TRUE; -		cv_broadcast(&tp->vol_incv); -		vol_tab_unlock(tp); -		mutex_exit(&volctl.ctl_muxmutex); -		vol_tab_rele(tp); -		vol_enqueue(VIE_CANCEL, (void *)&unit); -		return (0); - -	case VOLIOCSATTR: { -		STRUCT_DECL(vioc_sattr, sa); -		int	attr_err; -		size_t	len; -		struct ve_attr vea, *attr_ptr; - -		if (volctl.ctl_daemon_pid == 0) { -			err = ENXIO; -			goto sattr_err; -		} -		STRUCT_INIT(sa, get_udatamodel()); -		if (ddi_copyin((caddr_t)arg, STRUCT_BUF(sa), STRUCT_SIZE(sa), -		    mode) != 0) { -			err = EFAULT; -			goto sattr_err; -		} - -		/* zero out, otherwise, copyout kernel stack */ -		bzero(&vea, sizeof (vea)); - -		len = STRUCT_FGET(sa, sa_attr_len); -		if (len > MAX_ATTR_LEN) { -			err = EINVAL; -			goto sattr_err; -		} -		if (ddi_copyin(STRUCT_FGETP(sa, sa_attr), -		    vea.viea_attr, len, mode) != 0) { -			err = EFAULT; -			goto sattr_err; -		} -		vea.viea_attr[len] = '\0'; - -		len = STRUCT_FGET(sa, sa_value_len); -		if (len > MAX_ATTR_LEN) { -			err = EINVAL; -			goto sattr_err; -		} -		if (ddi_copyin(STRUCT_FGETP(sa, sa_value), -		    vea.viea_value, len, mode) != 0) { -			err = EFAULT; -			goto sattr_err; -		} -		vea.viea_value[len] = '\0'; - -		vea.viea_unit = unit; - -		/* -		 * We need to release lock. Otherwise we fall into -		 * deadlock if VOLIOCMAP/UNMAP was acquiring WRITE lock. -		 * We are safe here; still tp is hold by refcnt, and -		 * also vol_attr is not used until we call vol_ioctl_exit(). -		 */ -		vol_tab_unlock(tp); - -		if ((err = vol_ioctl_enter(&tp->vol_attr)) != 0) { -			vol_tab_rele(tp); -			return (err); -		} -		vol_enqueue(VIE_SETATTR, &vea); -		attr_ptr = &vea; -		err = vol_ioctl_wait(&tp->vol_attr, &attr_err, &attr_ptr); -		if (err == 0) { -			err = attr_err; -			/* check response */ -			if (attr_ptr != &vea) -				err = EINVAL; -		} -		vol_ioctl_exit(&tp->vol_attr); -		vol_tab_rele(tp); -		return (err); -sattr_err: -		vol_tab_unlock_and_rele(tp); -		return (err); -	} - -	case VOLIOCGATTR: { -		STRUCT_DECL(vioc_gattr, ga); -		int	attr_err; -		size_t	len; -		struct ve_attr vea, *attr_ptr; - -		if (volctl.ctl_daemon_pid == 0) { -			err = ENXIO; -			goto gattr_dun; -		} -		STRUCT_INIT(ga, get_udatamodel()); -		if (ddi_copyin((caddr_t)arg, STRUCT_BUF(ga), STRUCT_SIZE(ga), -		    mode) != 0) { -			err = EFAULT; -			goto gattr_dun; -		} - -		bzero(&vea, sizeof (vea)); - -		len = STRUCT_FGET(ga, ga_attr_len); -		if (len > MAX_ATTR_LEN) { -			err = EINVAL; -			goto gattr_dun; -		} -		if (ddi_copyin(STRUCT_FGETP(ga, ga_attr), -		    vea.viea_attr, len, mode) != 0) { -			err = EFAULT; -			goto gattr_dun; -		} -		vea.viea_attr[len] = '\0'; - -		vea.viea_unit = unit; - -		/* -		 * do unlock, othewise deadlock. -		 */ -		vol_tab_unlock(tp); - -		if ((err = vol_ioctl_enter(&tp->vol_attr)) != 0) { -			vol_tab_rele(tp); -			return (err); -		} -		vol_enqueue(VIE_GETATTR, &vea); -		attr_ptr = &vea; -		err = vol_ioctl_wait(&tp->vol_attr, &attr_err, &attr_ptr); -		if (err == 0) { -			err = attr_err; -			if (attr_ptr != &vea) -				err = EINVAL; -		} -		vol_ioctl_exit(&tp->vol_attr); -		if (err == 0 && -		    (strlen(vea.viea_value) + 1) > -		    STRUCT_FGET(ga, ga_val_len)) { -			err = EINVAL; -		} -		if (err == 0) { -			if (ddi_copyout(vea.viea_value, -			    STRUCT_FGETP(ga, ga_value), -			    strlen(vea.viea_value) + 1, mode) != 0) { -				err = EFAULT; -			} -		} -		vol_tab_rele(tp); -		return (err); -gattr_dun: -		vol_tab_unlock_and_rele(tp); -		return (err); -	} - -	case VOLIOCREMOUNT:	/* the medium has a new partition structure */ -		vol_enqueue(VIE_REMOUNT, (void *)&unit); -		vol_tab_unlock_and_rele(tp); -		/* may return ENODEV, even though event was queued ?? */ -		return (err); -	case CDROMEJECT: -	case FDEJECT: -	case DKIOCEJECT: -		if (tp->vol_devops == NULL) { -			vol_tab_unlock_and_rele(tp); -			return (EAGAIN); -		} -		vol_tab_unlock_and_rele(tp); -		break; - -	default: -		vol_tab_unlock_and_rele(tp); -		break; -	} - -	/* -	 * This is the part that passes ioctls on to the lower -	 * level devices.  Some of these may have to be trapped -	 * and remapped. -	 */ -	if ((tp = vol_gettab(unit, VGT_WAITSIG, &err)) == NULL) { -		DPRINTF("vol: ioctl (to pass on): gettab on unit %d, err %d\n", -		    unit, err); -		return (err); -	} - -	/* -	 * this is almost certainly the ENXIO case for that special -	 * flag we set. -	 */ -	if (err) -		goto out; - -	if (!(tp->vol_flags & ST_OPEN)) { -		err = ENXIO; -		goto out; -	} - -	switch (cmd) { -	/* -	 * Here's where we watch for the eject ioctls.  Here, we enqueue -	 * a message for the daemon and wait around to hear the results. -	 */ -	case CDROMEJECT: -	case FDEJECT: -	case DKIOCEJECT: { -		dev_t savedev = tp->vol_dev; -		struct ve_eject	vej; -		int	status; - -		if (volctl.ctl_daemon_pid == 0) { -			vol_tab_unlock_and_rele(tp); -			return (ENXIO); -		} - -		vej.viej_unit = unit; -		vej.viej_force = 0; - -		vol_tab_unlock(tp); - -		if ((err = vol_ioctl_enter(&tp->vol_eject)) != 0) { -			vol_tab_rele(tp); -			return (err); -		} -		/* ask daemon for permission to eject */ -		vol_enqueue(VIE_EJECT, (void *)&vej); -		err = vol_ioctl_wait(&tp->vol_eject, &status, NULL); -		if (err == 0) { -			if (status == VEJ_NO) -				err = EBUSY; -		} -		vol_ioctl_exit(&tp->vol_eject); -		if (err != 0) { -			/* ioctl is either signalled or rejected by vold */ -			vol_tab_rele(tp); -			return (err); -		} - -		ASSERT(savedev != NODEV); -		err = cdev_ioctl(savedev, cmd, arg, -		    (mode & FMODELS) | FREAD, credp, rvalp); -		/* -		 * clean out the block device. -		 */ -		binval(savedev);	/* XXX: not DDI compliant */ - -		vol_tab_rele(tp); -		return (err); -	} - -	/* -	 * The following ioctls cause volume management to -	 * reread the label after last close.  The assumption is -	 * that these are only used during "format" operations -	 * and labels and stuff get written with these. -	 */ -	case DKIOCSVTOC:	/* set vtoc */ -	case DKIOCSGEOM:	/* set geometry */ -	case DKIOCSAPART:	/* set partitions */ -	case FDRAW:		/* "raw" command to floppy */ -		vol_enqueue(VIE_NEWLABEL, (void *)&unit); -		/* FALL THROUGH */ -	default: -		/* -		 * Pass the ioctl on down. -		 */ -		if (tp->vol_dev == NODEV) { -			err = EIO; - -			DPRINTF("vol: tp->vol_dev = NODEV\n"); -			DPRINTF("vol: ioctl: dev %u.%u cmd %x arg %lx " -			    "mode %x credp %p rvalp %p\n", -			    getmajor(dev), getminor(dev), -			    cmd, arg, mode, (void *)credp, (void *)rvalp); -			break; -		} -		err = cdev_ioctl(tp->vol_dev, cmd, arg, -		    mode & ~FWRITE, credp, rvalp); -		break; -	} -	/* release lock, return err */ -out: -	vol_tab_unlock_and_rele(tp); -	return (err); -} - - -static int -volpoll(dev_t dev, short events, int anyyet, short *reventsp, -    struct pollhead **phpp) -{ -	int		unit; -	struct vol_tab 	*tp; -	int		err = 0; - -	DPRINTF4( -	    "vol: poll: dev %u.%u events 0x%x anyyet 0x%x revents 0x%x\n", -	    getmajor(dev), getminor(dev), (int)events, anyyet, -	    (int)*reventsp); - -	unit = getminor(dev); -	if (unit == 0) { -		if (volctl.ctl_open == 0 || volctl.ctl_daemon_pid == 0) { -			*reventsp |= POLLNVAL; -			return (EINVAL); -		} -		if (events & POLLRDNORM) { -			DPRINTF4("vol: poll: got a POLLRDNORM\n"); -			mutex_enter(&volctl.ctl_evmutex); -			if (volctl.ctl_evcnt) { -				DPRINTF3("vol: poll: we have data\n"); -				*reventsp |= POLLRDNORM; -				mutex_exit(&volctl.ctl_evmutex); -				return (0); -			} -			mutex_exit(&volctl.ctl_evmutex); -		} -		if (!anyyet) { -			*phpp = &vol_pollhead; -			*reventsp = 0; -		} -		return (0); -	} - -	if ((tp = vol_gettab(unit, VGT_WAITSIG, &err)) == NULL) { -		*reventsp |= POLLERR; -		return (err); -	} - -	if ((tp->vol_flags & ST_OPEN) == 0) { -		*reventsp |= POLLERR; -		err = ENXIO; -		goto out; -	} -	ASSERT(tp->vol_dev != NODEV); -	err = cdev_poll(tp->vol_dev, events, anyyet, reventsp, phpp); - -out: -	vol_tab_unlock_and_rele(tp); -	return (err); -} - - -static void -vol_enqueue(enum vie_event type, void *data) -{ -	struct kvioc_event 	*kvie; -	cred_t			*c; -	proc_t			*p; -	uid_t			uid; -	gid_t			gid; -	dev_t			ctty; - - -	kvie = kmem_alloc(sizeof (*kvie), KM_SLEEP); -	kvie->kve_event.vie_type = type; - -	/* build our user friendly slop.  Probably not DDI compliant */ -	if (drv_getparm(UCRED, &c) != 0) { -		DPRINTF("vol: vol_enqueue: couldn't get ucred\n"); -		uid = -1; -		gid = -1; -	} else { -		uid = crgetuid(c); -		gid = crgetgid(c); -	} - -	if (drv_getparm(UPROCP, &p) != 0) { -		DPRINTF("vol: vol_enqueue: couldn't get uprocp\n"); -		ctty = NODEV; -	} else { -		ctty = cttydev(p); -	} - -	DPRINTF2("vol: vol_enqueue: uid=%d, gid=%d, ctty=0x%lx\n", uid, -	    gid, ctty); - -	switch (type) { -	case VIE_MISSING: -		kvie->kve_event.vie_missing = *(struct ve_missing *)data; -		kvie->kve_event.vie_missing.viem_user = uid; -		kvie->kve_event.vie_missing.viem_tty = ctty; -		break; -	case VIE_INSERT: -		kvie->kve_event.vie_insert.viei_dev = *(dev_t *)data; -		break; -	case VIE_CHECK: -		kvie->kve_event.vie_check.viec_dev = *(dev_t *)data; -		break; -	case VIE_INUSE: -		kvie->kve_event.vie_inuse.vieu_dev = *(dev_t *)data; -		break; -	case VIE_EJECT: -		kvie->kve_event.vie_eject = *(struct ve_eject *)data; -		kvie->kve_event.vie_eject.viej_user = uid; -		kvie->kve_event.vie_eject.viej_tty = ctty; -		break; -	case VIE_DEVERR: -		kvie->kve_event.vie_error = *(struct ve_error *)data; -		break; -	case VIE_CLOSE: -		kvie->kve_event.vie_close.viecl_unit = *(minor_t *)data; -		break; -	case VIE_REMOVED: -		kvie->kve_event.vie_rm.virm_unit = *(minor_t *)data; -		break; -	case VIE_CANCEL: -		kvie->kve_event.vie_cancel.viec_unit = *(minor_t *)data; -		break; -	case VIE_NEWLABEL: -		kvie->kve_event.vie_newlabel.vien_unit = *(minor_t *)data; -		break; -	case VIE_GETATTR: -	case VIE_SETATTR: -		kvie->kve_event.vie_attr = *(struct ve_attr *)data; -		kvie->kve_event.vie_attr.viea_uid = uid; -		kvie->kve_event.vie_attr.viea_gid = gid; -		break; -	case VIE_SYMNAME: -		kvie->kve_event.vie_symname.vies_dev = *(dev_t *)data; -		break; -	case VIE_SYMDEV: -		kvie->kve_event.vie_symdev = *(struct ve_symdev *)data; -		break; -	case VIE_REMOUNT: -		kvie->kve_event.vie_remount.vier_unit = *(minor_t *)data; -		break; -	default: -		cmn_err(CE_WARN, "vol_enqueue: bad type %d", type); -		kmem_free(kvie, sizeof (*kvie)); -		return; -	} - -	mutex_enter(&volctl.ctl_evmutex); -	if (volctl.ctl_evend) { -		insque(kvie, volctl.ctl_evend); -	} else { -		insque(kvie, &volctl.ctl_events); -	} -	volctl.ctl_evend = kvie; -	volctl.ctl_evcnt++; -	mutex_exit(&volctl.ctl_evmutex); -	pollwakeup(&vol_pollhead, POLLRDNORM); -} - -#ifdef _SYSCALL32_IMPL -static int -vol_event32(struct vioc_event32 *e32, struct vioc_event *e) -{ -	int err = 0; - -	bzero(e32, sizeof (*e32)); - -#define	E2E32(x) e32->x = e->x - -	E2E32(vie_type); -	switch (e->vie_type) { -	case VIE_MISSING: -		E2E32(vie_missing.viem_unit); -		E2E32(vie_missing.viem_ndelay); -		E2E32(vie_missing.viem_user); -		if (!cmpldev(&(e32->vie_missing.viem_tty), -		    e->vie_missing.viem_tty)) -			err = EOVERFLOW; -		break; -	case VIE_EJECT: -		E2E32(vie_eject.viej_unit); -		E2E32(vie_eject.viej_user); -		if (!cmpldev(&(e32->vie_eject.viej_tty), -		    e->vie_eject.viej_tty)) -			err = EOVERFLOW; -		E2E32(vie_eject.viej_force); -		break; -	case VIE_DEVERR: -		if (!cmpldev(&(e32->vie_error.viee_dev), -		    e->vie_error.viee_dev)) -			err = EOVERFLOW; -		E2E32(vie_error.viee_errno); -		break; -	case VIE_CLOSE: -		E2E32(vie_close.viecl_unit); -		break; -	case VIE_CANCEL: -		E2E32(vie_cancel.viec_unit); -		break; -	case VIE_NEWLABEL: -		E2E32(vie_newlabel.vien_unit); -		break; -	case VIE_INSERT: -		if (!cmpldev(&(e32->vie_insert.viei_dev), -		    e->vie_insert.viei_dev)) -			err = EOVERFLOW; -		break; -	case VIE_SETATTR: -	case VIE_GETATTR: -		E2E32(vie_attr.viea_unit); -		/* copy all the data including the null terminate */ -		bcopy(e->vie_attr.viea_attr, e32->vie_attr.viea_attr, -		    MAX_ATTR_LEN + 1); -		bcopy(e->vie_attr.viea_value, e32->vie_attr.viea_value, -		    MAX_ATTR_LEN + 1); -		E2E32(vie_attr.viea_uid); -		E2E32(vie_attr.viea_gid); -		break; -	case VIE_INUSE: -		if (!cmpldev(&(e32->vie_inuse.vieu_dev), -		    e->vie_inuse.vieu_dev)) -			err = EOVERFLOW; -		break; -	case VIE_CHECK: -		if (!cmpldev(&(e32->vie_check.viec_dev), -		    e->vie_check.viec_dev)) -			err = EOVERFLOW; -		break; -	case VIE_REMOVED: -		E2E32(vie_rm.virm_unit); -		break; -	case VIE_SYMNAME: -		if (!cmpldev(&(e32->vie_symname.vies_dev), -		    e->vie_symname.vies_dev)) -			err = EOVERFLOW; -		break; -	case VIE_SYMDEV: -		bcopy(e->vie_symdev.vied_symname, e32->vie_symdev.vied_symname, -		    VOL_SYMNAME_LEN + 1); -		break; -	case VIE_REMOUNT: -		E2E32(vie_remount.vier_unit); -		break; -	} -	return (err); -} -#endif /* _SYSCALL32_IMPL */ - -/* - * vol_gettab() returns a vol_tab_t * for the unit.  If the unit - * isn't mapped, we tell vold about it and wait around until - * a mapping occurs - * - * upon successful completion, the vol_tab for which the pointer is - * returned has the read/write lock held as a reader - */ -static struct vol_tab * -vol_gettab(int unit, uint_t flags, int *err) -{ -	struct vol_tab		*tp; -	int			rv; -	struct ve_missing	ve; - -	*err = 0; - -	mutex_enter(&volctl.ctl_muxmutex); - -	/* -	 * If unit#0 has not opened, VGT_OPEN can be used to forcibly -	 * grab the vol_tab. Similarly, if unit#0 was closing, VGT_CLOSE -	 * can be used. -	 */ -	if ((volctl.ctl_open == 0 && (flags & VGT_OPEN) == 0) || -	    (volctl.ctl_closing && (flags & VGT_CLOSE) == 0)) { -		mutex_exit(&volctl.ctl_muxmutex); -		*err = ENXIO; -		DPRINTF("vol: gettab: ctl unit not open (ENXIO)!\n"); -		return (NULL); -	} - -	ASSERT(unit >= 0); -	if (unit < 0) { -		mutex_exit(&volctl.ctl_muxmutex); -		*err = ENOTTY; -		DPRINTF("vol: vol_gettab: negative unit number!\n"); -		return (NULL); -	} - -	tp = (struct vol_tab *)ddi_get_soft_state(voltab, unit); -	if (tp == NULL) { -		/* this unit not yet created */ -		if (flags & VGT_NEW) { -			/* the "create" flag is set, so create it */ -			*err = ddi_soft_state_zalloc(voltab, unit); -			if (*err) { -				DPRINTF("vol: zalloc broke vol %d\n", unit); -				*err = ENODEV; -				mutex_exit(&volctl.ctl_muxmutex); -				goto out; -			} -			tp = (struct vol_tab *) -				ddi_get_soft_state(voltab, unit); -			if (tp == NULL) { -				DPRINTF("vol: soft state was null!\n"); -				*err = ENOTTY; -				mutex_exit(&volctl.ctl_muxmutex); -				goto out; -			} -			vol_tab_init(tp); -			tp->vol_unit = unit; -		} else { -			/* didn't build a new one and we don't have one */ -			DPRINTF("vol: vol_gettab: ENODEV\n"); -			*err = ENODEV; -			mutex_exit(&volctl.ctl_muxmutex); -			goto out; -		} -	} -	tp->vol_refcnt++; - -	/* now we know the unit exists */ - -	/* keep track of the largest unit number we've seen */ -	if (unit > volctl.ctl_maxunit) { -		volctl.ctl_maxunit = unit; -	} - -	mutex_exit(&volctl.ctl_muxmutex); - -	if (flags & VGT_WAITSIG) { -		if (vol_tab_rlock_sig(tp)) { -			vol_tab_rele(tp); -			*err = EINTR; -			return (NULL); -		} -	} else { -		vol_tab_rlock(tp); -	} - -	/* check for ops already gotten, or for /dev/volctl */ -	if ((tp->vol_devops != NULL) || (unit == 0)) { -		/* got it! */ -		goto out; -	} - -	/* no vol_devops yet (and unit not /dev/volctl) */ - -	if (flags & VGT_NOWAIT) { -		/* no ops, and they don't want to wait */ -		DPRINTF("vol: vol_gettab: no mapping for %d, no waiting\n", -		    unit); -		*err = ENODEV; -		goto out; -	} - -	/* no vol_devops yet, but caller is willing to wait */ - -#ifdef	DEBUG_ENXIO -	if (tp->vol_flags & ST_ENXIO) { -		DPRINTF("vol_gettab: no mapping for %d: doing ENXIO\n", unit); -	} else { -		DPRINTF("vol_gettab: no mapping for %d: it's MISSING " -		    "(flags=0x%x, tp=%p)\n", unit, tp->vol_flags, (void *)tp); -	} -#endif -	if (tp->vol_flags & ST_ENXIO) { -		/* -		 * It's been unmapped, but the requested behavior is to -		 * return ENXIO rather than waiting around.  The enxio -		 * behavior is cleared on close. -		 */ -		DPRINTF("vol: vol_gettab: no mapping for %d, doing ENXIO\n", -		    unit); -		vol_tab_unlock_and_rele(tp); -		tp = NULL; -		*err = ENXIO; -		goto out; -	} - -	/* -	 * there isn't a mapping -- enqueue a missing message to the -	 * daemon and wait around until it appears -	 */ -	ve.viem_unit = unit; -	ve.viem_ndelay = (flags & VGT_NDELAY) ? TRUE : FALSE; - -	/* -	 * hang around until a unit appears or we're cancelled. -	 */ -	while (tp->vol_devops == NULL) { -		if (tp->vol_cancel) { -			break;		/* a volcancel has been done */ -		} -		/* -		 * Due to the lock ordering between rwlock and muxmutex, we -		 * need to release muxmuex prior to releasing rlock after -		 * cv_wait is complete. Between those two calls, corresponding -		 * node can be unmapped. As a result, we will go into -		 * cv_wait() again without posting VIE_MISSING, and thus -		 * cv_wait sleeps forever. Therefore, we need to post -		 * VIE_MISSING every time before we go into cv_wait(). -		 */ -		DPRINTF("vol: vol_gettab: enqueing missing event, unit %d " -		    "(ndelay=%d)\n", unit, ve.viem_ndelay); -		vol_enqueue(VIE_MISSING, (void *)&ve); - -		/* -		 * We need to ensure that the thread is sleeping in the -		 * cond when it's signalled. If muxmutex was acquired after -		 * the vol_tab_unlock() below, it creates a race with -		 * VOLIOCMAP which would cause loss of signal. Therefore -		 * muxmutex should be held here before releasing rlock. -		 */ -		mutex_enter(&volctl.ctl_muxmutex); - -		/* release rlock so that VOLIOCMAP can update devops */ -		vol_tab_unlock(tp); - -		/* wait right here */ -		if (flags & VGT_WAITSIG) { -			rv = cv_wait_sig(&tp->vol_incv, &volctl.ctl_muxmutex); -			if (rv == 0) { -				DPRINTF("vol: vol_gettab: eintr -> cnx\n"); -				/* -				 * found pending signal. We don't cancel -				 * the request here, otherwise next open -				 * would fail with ENXIO until vold creates -				 * a new mapping, also media can be ejected -				 * by a Ctrl-C. -				 */ -				mutex_exit(&volctl.ctl_muxmutex); -				vol_tab_rele(tp); -				*err = EINTR; -				tp = NULL; -				break; -			} -		} else { -			/* can't be interrupted by a signal */ -			cv_wait(&tp->vol_incv, &volctl.ctl_muxmutex); -		} - -		/* we may have signalled from close(). */ -		if (volctl.ctl_daemon_pid == 0) { -			mutex_exit(&volctl.ctl_muxmutex); -			vol_tab_rele(tp); -			*err = ENXIO; -			tp = NULL; -			break; -		} - -		/* -		 * muxmutex is no longer necessary. It should be released -		 * before acquiring rlock, so that thread running VOLIOCMAP -		 * etc won't deadlock. -		 */ -		mutex_exit(&volctl.ctl_muxmutex); - -		/* here, node can be unmapped again. see comments above */ - -		/* rlock again as we will test vol_devops */ -		if (flags & VGT_WAITSIG) { -			if (vol_tab_rlock_sig(tp)) { -				vol_tab_rele(tp); -				*err = EINTR; -				tp = NULL; -				break; -			} -		} else { -			vol_tab_rlock(tp); -		} - -		DPRINTF2("vol: vol_gettab: insert cv wakeup rcvd\n"); - -		if ((flags & VGT_NDELAY) && (tp->vol_dev == NODEV)) -			break; -	} -out: -	/* -	 * If the device is "cancelled", don't return the tp unless -	 * the caller really wants it (nowait and ndelay). -	 */ -	if ((tp != NULL) && tp->vol_cancel && !(flags & VGT_NOWAIT) && -	    !(flags & VGT_NDELAY)) { -		DPRINTF("vol: vol_gettab: cancel (flags 0x%x)\n", flags); -		*err = EIO; -		vol_tab_unlock_and_rele(tp); -		tp = NULL; -	} -	if (*err != 0) { -		DPRINTF("vol: vol_gettab: err=%d unit=%d, tp=%p\n", -		    *err, unit, (void *)tp); -	} -	return (tp); -} - - -/* - * Unmap *tp.  Removes it from the ddi_soft_state list. - */ -static void -vol_unmap(struct vol_tab *tp) -{ -	char	mname[16]; - -	ASSERT(MUTEX_HELD(&volctl.ctl_muxmutex)); -	ASSERT(volctl.ctl_dip); - -	/* wait until everyone is done with it */ -	vol_tab_rele_wait(tp); - -	/* release underlying driver */ -	vol_release_driver(tp); - -	/* get rid of the thing */ -	vol_tab_fini(tp); - -	/* remove minor node */ -	(void) snprintf(mname, sizeof (mname), VOLUNITNAME_BLK, tp->vol_unit); -	ddi_remove_minor_node(volctl.ctl_dip, mname); - -	(void) snprintf(mname, sizeof (mname), VOLUNITNAME_CHR, tp->vol_unit); -	ddi_remove_minor_node(volctl.ctl_dip, mname); - -	/* done */ -	ddi_soft_state_free(voltab, tp->vol_unit); -} - - -/* - * This is called when the volume daemon closes its connection. - * It cleans out our mux. - */ -static void -vol_cleanup(void) -{ -	int		i; -	int		err; -	struct vol_tab	*tp; -	struct kvioc_event *kve; - -	DPRINTF("vol_cleanup: entering (daemon dead?)\n"); - -	/* -	 * We need to grab muxmutex to make sure that all threads -	 * opening unit>0 are aware of closing, and ctl_muxunit will -	 * never be changed. -	 */ -	mutex_enter(&volctl.ctl_muxmutex); -	volctl.ctl_closing = 1; -	mutex_exit(&volctl.ctl_muxmutex); - -	for (i = 1; i < (volctl.ctl_maxunit + 1); i++) { - -		tp = vol_gettab(i, VGT_NOWAIT|VGT_CLOSE, &err); -		if (tp == NULL) -			continue; - -		DPRINTF("vol_cleanup: unit %d\n", i); - -		vol_ioctl_fail(&tp->vol_attr); -		/* cancel pending eject requests */ -		vol_ioctl_fail(&tp->vol_eject); - -		/* -		 * acquire muxmutex, to make sure that all the threads -		 * are aware of ctl_closing flag, and running threads have -		 * either failed or already acquired rlock in vol_gettab(). -		 * write lock is required as we will touch vol_cancel. -		 */ -		vol_tab_rwlock_upgrade(tp); -		mutex_enter(&volctl.ctl_muxmutex); - -		/* send a "cancel" for pending missing events */ -		tp->vol_cancel = TRUE; -		cv_broadcast(&tp->vol_incv); - -		vol_unmap(tp); -		/* tp is no longer valid after a vol_umnap() */ - -		mutex_exit(&volctl.ctl_muxmutex); -	} - -	DPRINTF("vol: vol_cleanup: cleared from 0 to %d\n", -	    volctl.ctl_maxunit); - -	volctl.ctl_maxunit = 0; - -	/* -	 * handle threads waiting for replies from the daemon -	 */ -	vol_ioctl_fail(&volctl.ctl_inuse); -	vol_ioctl_fail(&volctl.ctl_insert); -	vol_ioctl_fail(&volctl.ctl_symname); -	vol_ioctl_fail(&volctl.ctl_symdev); - -	/* -	 * Free up anything lurking on the event queue. -	 */ -	mutex_enter(&volctl.ctl_evmutex); -	while (volctl.ctl_evcnt != 0) { -		kve = volctl.ctl_events.kve_next; -		volctl.ctl_evcnt--; -		remque(kve); -		kmem_free(kve, sizeof (*kve)); -	} -	volctl.ctl_evend = NULL; -	mutex_exit(&volctl.ctl_evmutex); - -	/* wake up threads if sleeping in poll() */ -	pollwakeup(&vol_pollhead, POLLERR); - -	/* -	 * release memory only needed while the daemon is running -	 */ -	mutex_enter(&volctl.ctl_volrmutex); -	if (vold_root != NULL) { -		kmem_free(vold_root, vold_root_len + 1); -		vold_root = NULL; -		vold_root_len = 0; -	} -	mutex_exit(&volctl.ctl_volrmutex); - -	/* re-enable the ioctls */ -	vol_ioctl_enable(&volctl.ctl_inuse); -	vol_ioctl_enable(&volctl.ctl_insert); -	vol_ioctl_enable(&volctl.ctl_symname); -	vol_ioctl_enable(&volctl.ctl_symdev); - -	volctl.ctl_closing = 0; -} - - -/* - * Check the floppy drive to see if there's a floppy still in the - * drive.  If there isn't this function will block until the floppy - * is either back in the drive or the i/o is cancelled.  If found_media - * is supplied the status will be returned through it. - */ -static int -vol_checkmedia(struct vol_tab *tp, int *found_media) -{ -	int 		err = 0; -	int		badnews = 0; -	struct vol_tab	*tp0; - -	DPRINTF2("vol: checkmedia\n"); - -	/* do the grotty stuff to get the answer */ -	badnews = vol_checkmedia_machdep(tp); - -	/* check to see if there's no media in the drive */ -	if (badnews) { -		/* there's no media in the drive */ - -		if (found_media) { -			*found_media = FALSE;	/* return result */ -		} - -		if (vol_tab_rwlock_upgrade_sig(tp)) -			return (EINTR); - -		/* unmap the device */ -		vol_release_driver(tp); -		vol_tab_unlock(tp); - -		vol_enqueue(VIE_REMOVED, (void *)&tp->vol_unit); - -		/* get the mapping for this device, waiting if needed */ -		DPRINTF("vol: checkmedia: calling gettab\n"); -		tp0 = vol_gettab(tp->vol_unit, VGT_WAITSIG, &err); -		if (tp0 == NULL && err == EINTR) -			return (EINTR); -		if (tp0 != NULL) -			vol_tab_unlock_and_rele(tp0); - -		if (vol_tab_rlock_sig(tp)) -			return (EINTR); - -		DPRINTF("vol: checkmedia: gettab has returned\n"); -	} else { -		/* there is media in the drive */ - -		if (found_media) { -			*found_media = TRUE;	/* return results */ -		} -	} -	/* all done */ -	return (err); -} - - -/* - * return the bad news: media there (0) or not (1). - */ -static int -vol_checkmedia_machdep(struct vol_tab *tp) -{ -	int	err; -	int	fl_rval = 0;	/* bitmap word: all bits clear initially */ - - -	switch (tp->vol_mtype) { -	case MT_FLOPPY: -		/* check for a floppy disk in the drive */ - -		/* ensure we have a dev to do the ioctl on */ -		if (tp->vol_dev == NODEV) { -			/* it's been unmapped (so probably not there) */ -			DPRINTF("vol: checkmedia: volume unmapped\n"); -			return (1); -		} - -		/* -		 * XXX this mutex make sure that we're only doing one of -		 * XXX these ioctl's at a time.  this avoids a deadlock -		 * XXX in the floppy driver. -		 */ -		mutex_enter(&floppy_chk_mutex); -		err = cdev_ioctl(tp->vol_dev, FDGETCHANGE, -		    (intptr_t)&fl_rval, FNATIVE | FKIOCTL, kcred, NULL); -		mutex_exit(&floppy_chk_mutex); - -		if (err != 0) { -			DPRINTF("vol: checkmedia: FDGETCHANGE failed %d\n", -			    err); -			/* if we got an error, assume the worst */ -			return (1); -		} - -		/* is media present ?? */ -		if (fl_rval & FDGC_CURRENT) { -			DPRINTF("vol: checkmedia: no media! (fl_rval = 0x%x)\n", -			    fl_rval); -			return (1);	/* no media in the drive */ -		} - -		return (0);		/* media in the drive */ - -	default: -		DPRINTF("vol: checkmedia: bad mtype %d\n", tp->vol_mtype); -		return (1); -	} -	/*NOTREACHED*/ -} - -/* - * Release the driver and cleanup unnecessary stuff in vol_tab. - */ -static void -vol_release_driver(struct vol_tab *tp) -{ -	if (tp->vol_dev != NODEV && tp->vol_devops != NULL) { -		ddi_rele_driver(getmajor(tp->vol_dev)); -		DPRINTF3("vol: released driver %u\n", getmajor(tp->vol_dev)); -	} -	tp->vol_dev = NODEV; -	tp->vol_devops = NULL; -	/* drop media related flags */ -	tp->vol_flags &= ~(ST_CHKMEDIA|ST_RDONLY); -	if (tp->vol_path != NULL) -		kmem_free(tp->vol_path, tp->vol_pathlen + 1); -	tp->vol_path = NULL; -	tp->vol_pathlen = 0; -} - -/* - * return 0 if you are vold. - */ -static int -vol_daemon_check(void) -{ -	pid_t pid; - -	if (volctl.ctl_daemon_pid == 0) -		return (ENXIO); -	(void) drv_getparm(PPID, &pid); -	if (volctl.ctl_daemon_pid != pid) -		return (EPERM); -	else -		return (0); -} - -/* - * client side functions can be used to interface ioctls to vold. - * vold is responding for the ioctls by using vold_xx functions. - * - * vol_ioctl_init() - * vol_ioctl_fini() - *	initialize/destroy mutex, condvar etc. - * - * vol_ioctl_enter() - *	serialize ioctl request to make sure only one thread - *	is reqeusting a response from vold for particular uni/ioctl. - * - * vol_ioctl_wait() - * 	set argument in argp which will be used by by vold ioctl, and - *	wait for vold's response. value/ptr from vold are also returned - * 	via rval/rptr arguments. - * - * vol_ioctl_exit() - *	exit from critical section and let the next thread go into - *	the ioctl. - * - * vol_ioctl_fail() - *	wakes up threads either waiting for entering ioctl or waiting - *	for a response from vold. This will make those ioctls fail. - */ -static void -vol_ioctl_init(struct vol_ioctl *vic) -{ -	mutex_init(&vic->mutex, NULL, MUTEX_DRIVER, NULL); -	cv_init(&vic->cv, NULL, CV_DRIVER, NULL); -	cv_init(&vic->s_cv, NULL, CV_DRIVER, NULL); -	cv_init(&vic->close_cv, NULL, CV_DRIVER, NULL); -	vic->nwait = 0; -	vic->active = 0; -	vic->closing = 0; -} - -static void -vol_ioctl_fini(struct vol_ioctl *vic) -{ -	mutex_destroy(&vic->mutex); -	cv_destroy(&vic->cv); -	cv_destroy(&vic->s_cv); -	cv_destroy(&vic->close_cv); -} - -static int -vol_ioctl_enter(struct vol_ioctl *vic) -{ -	int r; - -	mutex_enter(&vic->mutex); -	if (vic->closing) { -		mutex_exit(&vic->mutex); -		return (ENXIO); -	} -	while (vic->active) { -		vic->nwait++; -		r = cv_wait_sig(&vic->s_cv, &vic->mutex); -		vic->nwait--; -		if (vic->closing) { -			if (vic->closewait && vic->nwait == 0) { -				/* I'm the last */ -				cv_signal(&vic->close_cv); -			} -			mutex_exit(&vic->mutex); -			if (r == 0) -				return (EINTR); -			else -				return (ENXIO); -		} -		if (r == 0) { -			/* signal pending */ -			mutex_exit(&vic->mutex); -			return (EINTR); -		} -	} -	vic->active = 1; -	return (0); -} - -static int -vol_ioctl_wait(struct vol_ioctl *vic, int *rvalp, void *rptrp) -{ -	int err = 0; - -	vic->rval = -1; -	vic->rptr = NULL;	/* clear return pointer in case of error */ -	if (rptrp != NULL) -		vic->argp = *(uintptr_t *)rptrp; -	while (vic->rval == -1) { -		if (cv_wait_sig(&vic->cv, &vic->mutex) == 0) { -			/* we are interrupted */ -			vic->rval = 0; -			err = EINTR; -			break; -		} -	} -	if (vic->closing || volctl.ctl_daemon_pid == 0) { -		/* the daemon is dying, or has already died */ -		err = ENXIO; -	} -	/* return data from vold */ -	if (rptrp != NULL) -		*(uintptr_t *)rptrp = vic->rptr; /* set return pointer */ -	*rvalp = vic->rval; -	return (err); -} - -static void -vol_ioctl_exit(struct vol_ioctl *vic) -{ -	vic->active = 0; -	if (vic->nwait != 0) { -		cv_broadcast(&vic->s_cv); -	} else if (vic->closewait) { -		/* -		 * I'm the last one. wake up the thread sleeping -		 * in vol_ioctl_fail. -		 */ -		cv_signal(&vic->close_cv); -	} -	mutex_exit(&vic->mutex); -} - -static void -vol_ioctl_fail(struct vol_ioctl *vic) -{ - -	mutex_enter(&vic->mutex); -	if (vic->active) { -		/* -		 * client is waiting for response. -		 * vold may or may not have responded to the request. -		 * If vold has already responded, rval has been set. -		 * We don't reset rval in such case. If vold has not -		 * yet responded, we set rval to pull thread out from -		 * loop in ioctl_wait. vold will see vic->closing, so -		 * it never reset rval again. -		 */ -		if (vic->rval == -1) { -			vic->rval = 0; -			vic->rptr = NULL; -		} -	} -	vic->closing = 1; -	vic->closewait = 0; -	if (vic->nwait) -		cv_broadcast(&vic->s_cv); -	if (vic->active) -		cv_broadcast(&vic->cv); -	/* -	 * If ioctl is active, or someone is waiting for ioctl. -	 */ -	while (vic->active || vic->nwait > 0) { -		vic->closewait = 1; -		cv_wait(&vic->close_cv, &vic->mutex); -		vic->closewait = 0; -	} -	mutex_exit(&vic->mutex); -} - -static void -vol_ioctl_enable(struct vol_ioctl *vic) -{ -	mutex_enter(&vic->mutex); -	vic->closing = 0; -	mutex_exit(&vic->mutex); -} - -/* - * vold side ioctl functions to interface with client side. - * - * vold_ioctl_enter() - *	double check to see if there is a request and vold can - *	respond. Retrieve data passed by vol_ioctl_wait(). - * - * vold_ioctl_respond() - *	set return values, and signal thread waiting for a - *	response. - * - * vold_ioctl_exit() - *	just exit. release lock. - */ - -static int -vold_ioctl_enter(struct vol_ioctl *vic, void *rptrp) -{ -	mutex_enter(&vic->mutex); -	if (vic->closing) { -		/* should not happen, but */ -		mutex_exit(&vic->mutex); -		return (ENXIO); -	} -	if (!vic->active) { -		mutex_exit(&vic->mutex); -		return (EAGAIN); -	} -	if (rptrp != NULL) -		*(uintptr_t *)rptrp = vic->argp; -	return (0); -} - -static void -vold_ioctl_respond(struct vol_ioctl *vic, int rval, void *rptr) -{ -	ASSERT(rval != -1); -	vic->rval = rval; -	vic->rptr = (uintptr_t)rptr; -	cv_signal(&vic->cv); -} - -static void -vold_ioctl_exit(struct vol_ioctl *vic) -{ -	mutex_exit(&vic->mutex); -} - -/* - * vol_tab lock/unlock functions. It used to be reader/writer lock, - * but need vol specific version which could prevent deadlock and race - * condition mainly created by lock upgrade sequence. - * - * vol_tab_init(), vol_tab_fini() - *	initialize/destroy the mutex/condvars. - * - * vol_tab_rlock_unlocked() - * vol_tab_rlock()/vol_tab_rlock_sig() - *	acquire reader lock. If write locked, just sleep. If read locked, - * 	increment reader count. If not yet read/write locked, set lock word, - *	and set reader count to 1. - * - * vol_tab_unlock()/vol_tab_unlock_unlocked() - *	release lock. If read locked, decrement reader count. If reader - *	count becomes 0, clear lock word. If write locked, just clear lock - *	flag. If anyone waiting for lock, wake up the threads sleeping - *	in either rlock or upgrade. - * - * vol_tab_rwlock_upgrade() - *	upgrades the acquired reader lock to writer lock. - *	If there is no other thread holding rlock, then straight upgrade - *	to write lock. If no, unlock the read lock, and wait until lock - *	is released. - * - * vol_tab_rele() - *	decrement the reference count. reference count is incremented - *	in vol_gettab(). If thread calling close() is waiting for - *	vol_tab to be released(no reference), wake up the thread. - * - * vol_tab_unlock_and_rele() - *	release lock, and decrement the reference count. - * - * vol_tab_rele_wait() - *	waiting until no other thread has referece to the vol_tab. - */ - -static void -vol_tab_init(struct vol_tab *tp) -{ -	vol_ioctl_init(&tp->vol_eject); -	vol_ioctl_init(&tp->vol_attr); -	mutex_init(&tp->vol_rwlck_mutex, NULL, MUTEX_DRIVER, NULL); -	cv_init(&tp->vol_incv, NULL, CV_DRIVER, NULL); -	cv_init(&tp->vol_rwlck_cv, NULL, CV_DRIVER, NULL); -	cv_init(&tp->vol_rele_cv, NULL, CV_DRIVER, NULL); -} - -static void -vol_tab_fini(struct vol_tab *tp) -{ -	vol_ioctl_fini(&tp->vol_eject); -	vol_ioctl_fini(&tp->vol_attr); -	mutex_destroy(&tp->vol_rwlck_mutex); -	cv_destroy(&tp->vol_incv); -	cv_destroy(&tp->vol_rwlck_cv); -	cv_destroy(&tp->vol_rele_cv); -} - -static int -vol_tab_rlock_unlocked(struct vol_tab *tp, boolean_t waitsig) -{ -	ASSERT(!MUTEX_HELD(&volctl.ctl_muxmutex)); -	/* wait until wlock is released */ -	while (tp->vol_locked == VOL_TAB_WR_LOCKED) { -		tp->vol_lckwaiter++; -		if (waitsig) { -			if (cv_wait_sig(&tp->vol_rwlck_cv, -			    &tp->vol_rwlck_mutex) == 0) { -				tp->vol_lckwaiter--; -				return (EINTR); -			} -		} else { -			cv_wait(&tp->vol_rwlck_cv, &tp->vol_rwlck_mutex); -		} -		tp->vol_lckwaiter--; -	} -	tp->vol_locked = VOL_TAB_RD_LOCKED; -	tp->vol_nreader++; -	return (0); -} - -static void -vol_tab_rlock(struct vol_tab *tp) -{ -	mutex_enter(&tp->vol_rwlck_mutex); -	(void) vol_tab_rlock_unlocked(tp, B_FALSE); -	mutex_exit(&tp->vol_rwlck_mutex); -} - -static int -vol_tab_rlock_sig(struct vol_tab *tp) -{ -	int r; - -	mutex_enter(&tp->vol_rwlck_mutex); -	r = vol_tab_rlock_unlocked(tp, B_TRUE); -	mutex_exit(&tp->vol_rwlck_mutex); -	return (r); -} - -static void -vol_tab_unlock_unlocked(struct vol_tab *tp) -{ -	ASSERT(tp->vol_locked != VOL_TAB_UNLOCKED); - -	if (tp->vol_locked == VOL_TAB_RD_LOCKED) { -		ASSERT(tp->vol_nreader != 0); -		if (--tp->vol_nreader == 0) { -			tp->vol_locked = VOL_TAB_UNLOCKED; -		} -	} else if (tp->vol_locked == VOL_TAB_WR_LOCKED) { -		tp->vol_locked = VOL_TAB_UNLOCKED; -	} -	if (tp->vol_locked == VOL_TAB_UNLOCKED && tp->vol_lckwaiter != 0) { -		cv_broadcast(&tp->vol_rwlck_cv); -	} -} - -static void -vol_tab_unlock(struct vol_tab *tp) -{ -	mutex_enter(&tp->vol_rwlck_mutex); -	vol_tab_unlock_unlocked(tp); -	mutex_exit(&tp->vol_rwlck_mutex); -} - -static int -vol_tab_rwlock_upgrade_unlocked(struct vol_tab *tp, boolean_t waitsig) -{ -	ASSERT(!MUTEX_HELD(&volctl.ctl_muxmutex)); -	ASSERT(tp->vol_locked == VOL_TAB_RD_LOCKED && tp->vol_nreader > 0); - -	if (tp->vol_nreader == 1) { -		tp->vol_nreader = 0; -		tp->vol_locked = VOL_TAB_WR_LOCKED; -		return (0); -	} -	vol_tab_unlock_unlocked(tp);	/* release READ lock */ -	while (tp->vol_locked != VOL_TAB_UNLOCKED) { -		tp->vol_lckwaiter++; -		if (waitsig) { -			if (cv_wait_sig(&tp->vol_rwlck_cv, -			    &tp->vol_rwlck_mutex) == 0) { -				tp->vol_lckwaiter--; -				return (EINTR); -			} -		} else { -			cv_wait(&tp->vol_rwlck_cv, &tp->vol_rwlck_mutex); -		} -		tp->vol_lckwaiter--; -	} -	ASSERT(tp->vol_nreader == 0); -	tp->vol_locked = VOL_TAB_WR_LOCKED; -	return (0); -} - -static void -vol_tab_rwlock_upgrade(struct vol_tab *tp) -{ -	mutex_enter(&tp->vol_rwlck_mutex); -	(void) vol_tab_rwlock_upgrade_unlocked(tp, B_FALSE); -	mutex_exit(&tp->vol_rwlck_mutex); -} - -static int -vol_tab_rwlock_upgrade_sig(struct vol_tab *tp) -{ -	int r; - -	mutex_enter(&tp->vol_rwlck_mutex); -	r = vol_tab_rwlock_upgrade_unlocked(tp, B_TRUE); -	mutex_exit(&tp->vol_rwlck_mutex); -	return (r); -} - -static void -vol_tab_rele(struct vol_tab *tp) -{ -	mutex_enter(&volctl.ctl_muxmutex); -	ASSERT(tp->vol_refcnt != 0); -	tp->vol_refcnt--; -	if (tp->vol_relewait && tp->vol_refcnt == 0) { -		/* I'm the last */ -		cv_broadcast(&tp->vol_rele_cv); -	} -	mutex_exit(&volctl.ctl_muxmutex); -} - -static void -vol_tab_unlock_and_rele(struct vol_tab *tp) -{ -	ASSERT(!MUTEX_HELD(&volctl.ctl_muxmutex)); -	vol_tab_unlock(tp); -	vol_tab_rele(tp); -} - -static void -vol_tab_rele_wait(struct vol_tab *tp) -{ -	ASSERT(MUTEX_HELD(&volctl.ctl_muxmutex)); -	vol_tab_unlock(tp); -	tp->vol_refcnt--; -	while (tp->vol_refcnt > 0) { -		tp->vol_relewait = 1; -		cv_wait(&tp->vol_rele_cv, &volctl.ctl_muxmutex); -		tp->vol_relewait = 0; -	} -} | 
