simple_lock(&uvm.swap_data_lock); if (swaplist_find(vp, 0) != NULL) { error = EBUSY; simple_unlock(&uvm.swap_data_lock); free(sdp, M_VMSWAP); free(spp, M_VMSWAP); break; }
sys_swapctl(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_swapctl_args /* {		syscallarg(int) cmd;		syscallarg(void *) arg;		syscallarg(int) misc;	} */ *uap = (struct sys_swapctl_args *)v;	struct vnode *vp;	struct nameidata nd;	struct swappri *spp;	struct swapdev *sdp;	struct swapent *sep;	char	userpath[MAXPATHLEN];	size_t	len;	int	count, error, misc;	int	priority;	UVMHIST_FUNC("sys_swapctl"); UVMHIST_CALLED(pdhist);	misc = SCARG(uap, misc);	/*	 * ensure serialized syscall access by grabbing the swap_syscall_lock	 */	lockmgr(&swap_syscall_lock, LK_EXCLUSIVE, NULL, p);		/*	 * we handle the non-priv NSWAP and STATS request first.	 *	 * SWAP_NSWAP: return number of config'd swap devices	 * [can also be obtained with uvmexp sysctl]	 */	if (SCARG(uap, cmd) == SWAP_NSWAP) {		UVMHIST_LOG(pdhist, "<- done SWAP_NSWAP=%d", uvmexp.nswapdev,		    0, 0, 0);		*retval = uvmexp.nswapdev;		error = 0;		goto out;	}	/*	 * SWAP_STATS: get stats on current # of configured swap devs	 *	 * note that the swap_priority list can't change as long	 * as we are holding the swap_syscall_lock.  we don't want	 * to grab the uvm.swap_data_lock because we may fault&sleep during	 * copyout() and we don't want to be holding that lock then!	 */	if (SCARG(uap, cmd) == SWAP_STATS#if defined(COMPAT_13)	    || SCARG(uap, cmd) == SWAP_OSTATS#endif	    ) {		sep = (struct swapent *)SCARG(uap, arg);		count = 0;		for (spp = LIST_FIRST(&swap_priority); spp != NULL;		    spp = LIST_NEXT(spp, spi_swappri)) {			for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev);			     sdp != (void *)&spp->spi_swapdev && misc-- > 0;			     sdp = CIRCLEQ_NEXT(sdp, swd_next)) {				sdp->swd_inuse =				    btodb((u_int64_t)sdp->swd_npginuse <<				    PAGE_SHIFT);				error = copyout(&sdp->swd_se, sep,				    sizeof(struct swapent));				/* now copy out the path if necessary */#if defined(COMPAT_13)				if (error == 0 && SCARG(uap, cmd) == SWAP_STATS)#else				if (error == 0)#endif					error = copyout(sdp->swd_path,					    &sep->se_path, sdp->swd_pathlen);				if (error)					goto out;				count++;#if defined(COMPAT_13)				if (SCARG(uap, cmd) == SWAP_OSTATS)					sep = (struct swapent *)					    ((struct oswapent *)sep + 1);				else#endif					sep++;			}		}		UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0);		*retval = count;		error = 0;		goto out;	}	/*	 * all other requests require superuser privs.   verify.	 */	if ((error = suser(p->p_ucred, &p->p_acflag)))		goto out;	/*	 * at this point we expect a path name in arg.   we will	 * use namei() to gain a vnode reference (vref), and lock	 * the vnode (VOP_LOCK).	 *	 * XXX: a NULL arg means use the root vnode pointer (e.g. for	 * miniroot)	 */	if (SCARG(uap, arg) == NULL) {		vp = rootvp;		/* miniroot */		if (vget(vp, LK_EXCLUSIVE, p)) {			error = EBUSY;			goto out;		}		if (SCARG(uap, cmd) == SWAP_ON &&		    copystr("miniroot", userpath, sizeof userpath, &len))			panic("swapctl: miniroot copy failed");	} else {		int	space;		char	*where;		if (SCARG(uap, cmd) == SWAP_ON) {			if ((error = copyinstr(SCARG(uap, arg), userpath,			    sizeof userpath, &len)))				goto out;			space = UIO_SYSSPACE;			where = userpath;		} else {			space = UIO_USERSPACE;			where = (char *)SCARG(uap, arg);		}		NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, space, where, p);		if ((error = namei(&nd)))			goto out;		vp = nd.ni_vp;	}	/* note: "vp" is referenced and locked */	error = 0;		/* assume no error */	switch(SCARG(uap, cmd)) {	case SWAP_DUMPDEV:		if (vp->v_type != VBLK) {			error = ENOTBLK;			break;		}		dumpdev = vp->v_rdev;		break;	case SWAP_CTL:		/*		 * get new priority, remove old entry (if any) and then		 * reinsert it in the correct place.  finally, prune out		 * any empty priority structures.		 */		priority = SCARG(uap, misc);		spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK);		simple_lock(&uvm.swap_data_lock);		if ((sdp = swaplist_find(vp, 1)) == NULL) {			error = ENOENT;		} else {			swaplist_insert(sdp, spp, priority);			swaplist_trim();		}		simple_unlock(&uvm.swap_data_lock);		if (error)			free(spp, M_VMSWAP);		break;	case SWAP_ON:		/*		 * check for duplicates.   if none found, then insert a		 * dummy entry on the list to prevent someone else from		 * trying to enable this device while we are working on		 * it.		 */		priority = SCARG(uap, misc);		sdp = malloc(sizeof *sdp, M_VMSWAP, M_WAITOK);		spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK);		simple_lock(&uvm.swap_data_lock);		if (swaplist_find(vp, 0) != NULL) {			error = EBUSY;			simple_unlock(&uvm.swap_data_lock);			free(sdp, M_VMSWAP);			free(spp, M_VMSWAP);			break;		}		memset(sdp, 0, sizeof(*sdp));		sdp->swd_flags = SWF_FAKE;	/* placeholder only */		sdp->swd_vp = vp;		sdp->swd_dev = (vp->v_type == VBLK) ? vp->v_rdev : NODEV;		/*		 * XXX Is NFS elaboration necessary?		 */		if (vp->v_type == VREG) {			sdp->swd_cred = crdup(p->p_ucred);		}		swaplist_insert(sdp, spp, priority);		simple_unlock(&uvm.swap_data_lock);		sdp->swd_pathlen = len;		sdp->swd_path = malloc(sdp->swd_pathlen, M_VMSWAP, M_WAITOK);		if (copystr(userpath, sdp->swd_path, sdp->swd_pathlen, 0) != 0)			panic("swapctl: copystr");		/*		 * we've now got a FAKE placeholder in the swap list.		 * now attempt to enable swap on it.  if we fail, undo		 * what we've done and kill the fake entry we just inserted.		 * if swap_on is a success, it will clear the SWF_FAKE flag		 */		if ((error = swap_on(p, sdp)) != 0) {			simple_lock(&uvm.swap_data_lock);			(void) swaplist_find(vp, 1);  /* kill fake entry */			swaplist_trim();			simple_unlock(&uvm.swap_data_lock);			if (vp->v_type == VREG) {				crfree(sdp->swd_cred);			}			free(sdp->swd_path, M_VMSWAP);			free(sdp, M_VMSWAP);			break;		}		break;	case SWAP_OFF:		simple_lock(&uvm.swap_data_lock);		if ((sdp = swaplist_find(vp, 0)) == NULL) {			simple_unlock(&uvm.swap_data_lock);			error = ENXIO;			break;		}		/*		 * If a device isn't in use or enabled, we		 * can't stop swapping from it (again).		 */		if ((sdp->swd_flags & (SWF_INUSE|SWF_ENABLE)) == 0) {			simple_unlock(&uvm.swap_data_lock);			error = EBUSY;			break;		}		/*		 * do the real work.		 */		error = swap_off(p, sdp);		break;	default:		error = EINVAL;	}	/*	 * done!  release the ref gained by namei() and unlock.	 */	vput(vp);out:	lockmgr(&swap_syscall_lock, LK_RELEASE, NULL, p);	UVMHIST_LOG(pdhist, "<- done!  error=%d", error, 0, 0, 0);	return (error);}