11848286aSEdward Tomasz Napierala /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
41848286aSEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation
51848286aSEdward Tomasz Napierala *
61848286aSEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship
71848286aSEdward Tomasz Napierala * from the FreeBSD Foundation.
81848286aSEdward Tomasz Napierala *
91848286aSEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without
101848286aSEdward Tomasz Napierala * modification, are permitted provided that the following conditions
111848286aSEdward Tomasz Napierala * are met:
121848286aSEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright
131848286aSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer.
141848286aSEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright
151848286aSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the
161848286aSEdward Tomasz Napierala * documentation and/or other materials provided with the distribution.
171848286aSEdward Tomasz Napierala *
181848286aSEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
191848286aSEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201848286aSEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211848286aSEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
221848286aSEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231848286aSEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241848286aSEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251848286aSEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261848286aSEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271848286aSEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281848286aSEdward Tomasz Napierala * SUCH DAMAGE.
291848286aSEdward Tomasz Napierala */
301848286aSEdward Tomasz Napierala
311848286aSEdward Tomasz Napierala #include <sys/cdefs.h>
321848286aSEdward Tomasz Napierala #include <sys/systm.h>
338c7f0b92SGleb Smirnoff #include <sys/buf.h>
341848286aSEdward Tomasz Napierala #include <sys/conf.h>
35701b3696SKonstantin Belousov #include <sys/filedesc.h>
3668912701SKonstantin Belousov #include <sys/ioccom.h>
371848286aSEdward Tomasz Napierala #include <sys/jail.h>
3868912701SKonstantin Belousov #include <sys/mount.h>
391848286aSEdward Tomasz Napierala #include <sys/sx.h>
4068912701SKonstantin Belousov #include <sys/vnode.h>
411848286aSEdward Tomasz Napierala
421848286aSEdward Tomasz Napierala #include <security/mac/mac_framework.h>
431848286aSEdward Tomasz Napierala
441848286aSEdward Tomasz Napierala #include <ufs/ufs/extattr.h>
451848286aSEdward Tomasz Napierala #include <ufs/ufs/quota.h>
461848286aSEdward Tomasz Napierala #include <ufs/ufs/ufsmount.h>
471848286aSEdward Tomasz Napierala #include <ufs/ufs/inode.h>
481848286aSEdward Tomasz Napierala
491848286aSEdward Tomasz Napierala #include <ufs/ffs/fs.h>
501848286aSEdward Tomasz Napierala #include <ufs/ffs/ffs_extern.h>
511848286aSEdward Tomasz Napierala
521848286aSEdward Tomasz Napierala static d_open_t ffs_susp_open;
531848286aSEdward Tomasz Napierala static d_write_t ffs_susp_rdwr;
541848286aSEdward Tomasz Napierala static d_ioctl_t ffs_susp_ioctl;
551848286aSEdward Tomasz Napierala
561848286aSEdward Tomasz Napierala static struct cdevsw ffs_susp_cdevsw = {
571848286aSEdward Tomasz Napierala .d_version = D_VERSION,
581848286aSEdward Tomasz Napierala .d_open = ffs_susp_open,
591848286aSEdward Tomasz Napierala .d_read = ffs_susp_rdwr,
601848286aSEdward Tomasz Napierala .d_write = ffs_susp_rdwr,
611848286aSEdward Tomasz Napierala .d_ioctl = ffs_susp_ioctl,
621848286aSEdward Tomasz Napierala .d_name = "ffs_susp",
631848286aSEdward Tomasz Napierala };
641848286aSEdward Tomasz Napierala
651848286aSEdward Tomasz Napierala static struct cdev *ffs_susp_dev;
661848286aSEdward Tomasz Napierala static struct sx ffs_susp_lock;
671848286aSEdward Tomasz Napierala
681848286aSEdward Tomasz Napierala static int
ffs_susp_suspended(struct mount * mp)691848286aSEdward Tomasz Napierala ffs_susp_suspended(struct mount *mp)
701848286aSEdward Tomasz Napierala {
711848286aSEdward Tomasz Napierala struct ufsmount *ump;
721848286aSEdward Tomasz Napierala
731848286aSEdward Tomasz Napierala sx_assert(&ffs_susp_lock, SA_LOCKED);
741848286aSEdward Tomasz Napierala
751848286aSEdward Tomasz Napierala ump = VFSTOUFS(mp);
76ab0bcb60SKirk McKusick if ((ump->um_flags & UM_WRITESUSPENDED) != 0)
771848286aSEdward Tomasz Napierala return (1);
781848286aSEdward Tomasz Napierala return (0);
791848286aSEdward Tomasz Napierala }
801848286aSEdward Tomasz Napierala
811848286aSEdward Tomasz Napierala static int
ffs_susp_open(struct cdev * dev __unused,int flags __unused,int fmt __unused,struct thread * td __unused)821848286aSEdward Tomasz Napierala ffs_susp_open(struct cdev *dev __unused, int flags __unused,
831848286aSEdward Tomasz Napierala int fmt __unused, struct thread *td __unused)
841848286aSEdward Tomasz Napierala {
851848286aSEdward Tomasz Napierala
861848286aSEdward Tomasz Napierala return (0);
871848286aSEdward Tomasz Napierala }
881848286aSEdward Tomasz Napierala
891848286aSEdward Tomasz Napierala static int
ffs_susp_rdwr(struct cdev * dev,struct uio * uio,int ioflag)901848286aSEdward Tomasz Napierala ffs_susp_rdwr(struct cdev *dev, struct uio *uio, int ioflag)
911848286aSEdward Tomasz Napierala {
921848286aSEdward Tomasz Napierala int error, i;
931848286aSEdward Tomasz Napierala struct vnode *devvp;
941848286aSEdward Tomasz Napierala struct mount *mp;
951848286aSEdward Tomasz Napierala struct ufsmount *ump;
961848286aSEdward Tomasz Napierala struct buf *bp;
971848286aSEdward Tomasz Napierala void *base;
981848286aSEdward Tomasz Napierala size_t len;
991848286aSEdward Tomasz Napierala ssize_t cnt;
1001848286aSEdward Tomasz Napierala struct fs *fs;
1011848286aSEdward Tomasz Napierala
1021848286aSEdward Tomasz Napierala sx_slock(&ffs_susp_lock);
1031848286aSEdward Tomasz Napierala
1041848286aSEdward Tomasz Napierala error = devfs_get_cdevpriv((void **)&mp);
1051848286aSEdward Tomasz Napierala if (error != 0) {
1061848286aSEdward Tomasz Napierala sx_sunlock(&ffs_susp_lock);
1071848286aSEdward Tomasz Napierala return (ENXIO);
1081848286aSEdward Tomasz Napierala }
1091848286aSEdward Tomasz Napierala
1101848286aSEdward Tomasz Napierala ump = VFSTOUFS(mp);
1111848286aSEdward Tomasz Napierala devvp = ump->um_devvp;
1121848286aSEdward Tomasz Napierala fs = ump->um_fs;
1131848286aSEdward Tomasz Napierala
1141848286aSEdward Tomasz Napierala if (ffs_susp_suspended(mp) == 0) {
1151848286aSEdward Tomasz Napierala sx_sunlock(&ffs_susp_lock);
1161848286aSEdward Tomasz Napierala return (ENXIO);
1171848286aSEdward Tomasz Napierala }
1181848286aSEdward Tomasz Napierala
1191848286aSEdward Tomasz Napierala KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
1201848286aSEdward Tomasz Napierala ("neither UIO_READ or UIO_WRITE"));
1211848286aSEdward Tomasz Napierala KASSERT(uio->uio_segflg == UIO_USERSPACE,
1221848286aSEdward Tomasz Napierala ("uio->uio_segflg != UIO_USERSPACE"));
1231848286aSEdward Tomasz Napierala
1241848286aSEdward Tomasz Napierala cnt = uio->uio_resid;
1251848286aSEdward Tomasz Napierala
1261848286aSEdward Tomasz Napierala for (i = 0; i < uio->uio_iovcnt; i++) {
1271848286aSEdward Tomasz Napierala while (uio->uio_iov[i].iov_len) {
1281848286aSEdward Tomasz Napierala base = uio->uio_iov[i].iov_base;
1291848286aSEdward Tomasz Napierala len = uio->uio_iov[i].iov_len;
1301848286aSEdward Tomasz Napierala if (len > fs->fs_bsize)
1311848286aSEdward Tomasz Napierala len = fs->fs_bsize;
1321848286aSEdward Tomasz Napierala if (fragoff(fs, uio->uio_offset) != 0 ||
1331848286aSEdward Tomasz Napierala fragoff(fs, len) != 0) {
1341848286aSEdward Tomasz Napierala error = EINVAL;
1351848286aSEdward Tomasz Napierala goto out;
1361848286aSEdward Tomasz Napierala }
1371848286aSEdward Tomasz Napierala error = bread(devvp, btodb(uio->uio_offset), len,
1381848286aSEdward Tomasz Napierala NOCRED, &bp);
1391848286aSEdward Tomasz Napierala if (error != 0)
1401848286aSEdward Tomasz Napierala goto out;
141473c90acSJohn Baldwin switch (uio->uio_rw) {
142473c90acSJohn Baldwin case UIO_WRITE:
1431848286aSEdward Tomasz Napierala error = copyin(base, bp->b_data, len);
1441848286aSEdward Tomasz Napierala if (error != 0) {
1451848286aSEdward Tomasz Napierala bp->b_flags |= B_INVAL | B_NOCACHE;
1461848286aSEdward Tomasz Napierala brelse(bp);
1471848286aSEdward Tomasz Napierala goto out;
1481848286aSEdward Tomasz Napierala }
1491848286aSEdward Tomasz Napierala error = bwrite(bp);
1501848286aSEdward Tomasz Napierala if (error != 0)
1511848286aSEdward Tomasz Napierala goto out;
152473c90acSJohn Baldwin break;
153473c90acSJohn Baldwin case UIO_READ:
1541848286aSEdward Tomasz Napierala error = copyout(bp->b_data, base, len);
1551848286aSEdward Tomasz Napierala brelse(bp);
1561848286aSEdward Tomasz Napierala if (error != 0)
1571848286aSEdward Tomasz Napierala goto out;
158473c90acSJohn Baldwin break;
1591848286aSEdward Tomasz Napierala }
1601848286aSEdward Tomasz Napierala uio->uio_iov[i].iov_base =
1611848286aSEdward Tomasz Napierala (char *)uio->uio_iov[i].iov_base + len;
1621848286aSEdward Tomasz Napierala uio->uio_iov[i].iov_len -= len;
1631848286aSEdward Tomasz Napierala uio->uio_resid -= len;
1641848286aSEdward Tomasz Napierala uio->uio_offset += len;
1651848286aSEdward Tomasz Napierala }
1661848286aSEdward Tomasz Napierala }
1671848286aSEdward Tomasz Napierala
1681848286aSEdward Tomasz Napierala out:
1691848286aSEdward Tomasz Napierala sx_sunlock(&ffs_susp_lock);
1701848286aSEdward Tomasz Napierala
1711848286aSEdward Tomasz Napierala if (uio->uio_resid < cnt)
1721848286aSEdward Tomasz Napierala return (0);
1731848286aSEdward Tomasz Napierala
1741848286aSEdward Tomasz Napierala return (error);
1751848286aSEdward Tomasz Napierala }
1761848286aSEdward Tomasz Napierala
1771848286aSEdward Tomasz Napierala static int
ffs_susp_suspend(struct mount * mp)1781848286aSEdward Tomasz Napierala ffs_susp_suspend(struct mount *mp)
1791848286aSEdward Tomasz Napierala {
1801848286aSEdward Tomasz Napierala struct ufsmount *ump;
1811848286aSEdward Tomasz Napierala int error;
1821848286aSEdward Tomasz Napierala
1831848286aSEdward Tomasz Napierala sx_assert(&ffs_susp_lock, SA_XLOCKED);
1841848286aSEdward Tomasz Napierala
1851848286aSEdward Tomasz Napierala if (!ffs_own_mount(mp))
1861848286aSEdward Tomasz Napierala return (EINVAL);
1871848286aSEdward Tomasz Napierala if (ffs_susp_suspended(mp))
1881848286aSEdward Tomasz Napierala return (EBUSY);
1891848286aSEdward Tomasz Napierala
1901848286aSEdward Tomasz Napierala ump = VFSTOUFS(mp);
1911848286aSEdward Tomasz Napierala
1921848286aSEdward Tomasz Napierala /*
1931848286aSEdward Tomasz Napierala * Make sure the calling thread is permitted to access the mounted
1941848286aSEdward Tomasz Napierala * device. The permissions can change after we unlock the vnode;
1951848286aSEdward Tomasz Napierala * it's harmless.
1961848286aSEdward Tomasz Napierala */
19769b3fdfaSChuck Silvers vn_lock(ump->um_odevvp, LK_EXCLUSIVE | LK_RETRY);
19869b3fdfaSChuck Silvers error = VOP_ACCESS(ump->um_odevvp, VREAD | VWRITE,
1991848286aSEdward Tomasz Napierala curthread->td_ucred, curthread);
20069b3fdfaSChuck Silvers VOP_UNLOCK(ump->um_odevvp);
2011848286aSEdward Tomasz Napierala if (error != 0)
2021848286aSEdward Tomasz Napierala return (error);
2031848286aSEdward Tomasz Napierala #ifdef MAC
2041848286aSEdward Tomasz Napierala if (mac_mount_check_stat(curthread->td_ucred, mp) != 0)
2051848286aSEdward Tomasz Napierala return (EPERM);
2061848286aSEdward Tomasz Napierala #endif
2071848286aSEdward Tomasz Napierala
208cc3d8c35SKonstantin Belousov if ((error = vfs_write_suspend(mp, VS_SKIP_UNMOUNT)) != 0)
2091848286aSEdward Tomasz Napierala return (error);
2101848286aSEdward Tomasz Napierala
21115430057SKirk McKusick UFS_LOCK(ump);
212ab0bcb60SKirk McKusick ump->um_flags |= UM_WRITESUSPENDED;
21315430057SKirk McKusick UFS_UNLOCK(ump);
2141848286aSEdward Tomasz Napierala
2151848286aSEdward Tomasz Napierala return (0);
2161848286aSEdward Tomasz Napierala }
2171848286aSEdward Tomasz Napierala
2181848286aSEdward Tomasz Napierala static void
ffs_susp_unsuspend(struct mount * mp)21961b285acSKonstantin Belousov ffs_susp_unsuspend(struct mount *mp)
22061b285acSKonstantin Belousov {
22161b285acSKonstantin Belousov struct ufsmount *ump;
22261b285acSKonstantin Belousov
22361b285acSKonstantin Belousov sx_assert(&ffs_susp_lock, SA_XLOCKED);
22461b285acSKonstantin Belousov
22561b285acSKonstantin Belousov /*
22661b285acSKonstantin Belousov * XXX: The status is kept per-process; the vfs_write_resume() routine
22761b285acSKonstantin Belousov * asserts that the resuming thread is the same one that called
22861b285acSKonstantin Belousov * vfs_write_suspend(). The cdevpriv data, however, is attached
22961b285acSKonstantin Belousov * to the file descriptor, e.g. is inherited during fork. Thus,
23061b285acSKonstantin Belousov * it's possible that the resuming process will be different from
23161b285acSKonstantin Belousov * the one that started the suspension.
23261b285acSKonstantin Belousov *
23361b285acSKonstantin Belousov * Work around by fooling the check in vfs_write_resume().
23461b285acSKonstantin Belousov */
23561b285acSKonstantin Belousov mp->mnt_susp_owner = curthread;
23661b285acSKonstantin Belousov
23761b285acSKonstantin Belousov vfs_write_resume(mp, 0);
23861b285acSKonstantin Belousov ump = VFSTOUFS(mp);
23961b285acSKonstantin Belousov UFS_LOCK(ump);
24061b285acSKonstantin Belousov ump->um_flags &= ~UM_WRITESUSPENDED;
24161b285acSKonstantin Belousov UFS_UNLOCK(ump);
24261b285acSKonstantin Belousov vfs_unbusy(mp);
24361b285acSKonstantin Belousov }
24461b285acSKonstantin Belousov
24561b285acSKonstantin Belousov static void
ffs_susp_dtor(void * data)2461848286aSEdward Tomasz Napierala ffs_susp_dtor(void *data)
2471848286aSEdward Tomasz Napierala {
2481848286aSEdward Tomasz Napierala struct mount *mp;
2491848286aSEdward Tomasz Napierala int error;
2501848286aSEdward Tomasz Napierala
2511848286aSEdward Tomasz Napierala sx_xlock(&ffs_susp_lock);
2521848286aSEdward Tomasz Napierala
2531848286aSEdward Tomasz Napierala mp = (struct mount *)data;
2541848286aSEdward Tomasz Napierala
2551848286aSEdward Tomasz Napierala if (ffs_susp_suspended(mp) == 0) {
2561848286aSEdward Tomasz Napierala sx_xunlock(&ffs_susp_lock);
2571848286aSEdward Tomasz Napierala return;
2581848286aSEdward Tomasz Napierala }
2591848286aSEdward Tomasz Napierala
2601848286aSEdward Tomasz Napierala KASSERT((mp->mnt_kern_flag & MNTK_SUSPEND) != 0,
2611848286aSEdward Tomasz Napierala ("MNTK_SUSPEND not set"));
2621848286aSEdward Tomasz Napierala
263440320b6SRobert Wing error = ffs_reload(mp, FFSR_FORCE | FFSR_UNSUSPEND);
2641848286aSEdward Tomasz Napierala if (error != 0)
265*df48361eSKirk McKusick panic("failed to unsuspend writes on %s",
266*df48361eSKirk McKusick VFSTOUFS(mp)->um_fs->fs_fsmnt);
2671848286aSEdward Tomasz Napierala
26861b285acSKonstantin Belousov ffs_susp_unsuspend(mp);
2691848286aSEdward Tomasz Napierala sx_xunlock(&ffs_susp_lock);
2701848286aSEdward Tomasz Napierala }
2711848286aSEdward Tomasz Napierala
2721848286aSEdward Tomasz Napierala static int
ffs_susp_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)2731848286aSEdward Tomasz Napierala ffs_susp_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
2741848286aSEdward Tomasz Napierala struct thread *td)
2751848286aSEdward Tomasz Napierala {
2761848286aSEdward Tomasz Napierala struct mount *mp;
2771848286aSEdward Tomasz Napierala fsid_t *fsidp;
2781848286aSEdward Tomasz Napierala int error;
2791848286aSEdward Tomasz Napierala
2801848286aSEdward Tomasz Napierala /*
2811848286aSEdward Tomasz Napierala * No suspend inside the jail. Allowing it would require making
2821848286aSEdward Tomasz Napierala * sure that e.g. the devfs ruleset for that jail permits access
2831848286aSEdward Tomasz Napierala * to the devvp.
2841848286aSEdward Tomasz Napierala */
2851848286aSEdward Tomasz Napierala if (jailed(td->td_ucred))
2861848286aSEdward Tomasz Napierala return (EPERM);
2871848286aSEdward Tomasz Napierala
2881848286aSEdward Tomasz Napierala sx_xlock(&ffs_susp_lock);
2891848286aSEdward Tomasz Napierala
2901848286aSEdward Tomasz Napierala switch (cmd) {
2911848286aSEdward Tomasz Napierala case UFSSUSPEND:
2921848286aSEdward Tomasz Napierala fsidp = (fsid_t *)addr;
2931848286aSEdward Tomasz Napierala mp = vfs_getvfs(fsidp);
2941848286aSEdward Tomasz Napierala if (mp == NULL) {
2951848286aSEdward Tomasz Napierala error = ENOENT;
2961848286aSEdward Tomasz Napierala break;
2971848286aSEdward Tomasz Napierala }
2981848286aSEdward Tomasz Napierala error = vfs_busy(mp, 0);
2991848286aSEdward Tomasz Napierala vfs_rel(mp);
3001848286aSEdward Tomasz Napierala if (error != 0)
3011848286aSEdward Tomasz Napierala break;
302701b3696SKonstantin Belousov
303701b3696SKonstantin Belousov /*
304701b3696SKonstantin Belousov * Require single-thread curproc so that the check is not racey.
305701b3696SKonstantin Belousov * XXXKIB: might consider to singlethread curproc instead.
306701b3696SKonstantin Belousov */
307701b3696SKonstantin Belousov error = curproc->p_numthreads > 1 ? EDEADLK :
308701b3696SKonstantin Belousov descrip_check_write_mp(curproc->p_fd, mp);
309a5ff8664SKonstantin Belousov if (error != 0) {
310a5ff8664SKonstantin Belousov vfs_unbusy(mp);
311701b3696SKonstantin Belousov break;
312a5ff8664SKonstantin Belousov }
313701b3696SKonstantin Belousov
3141848286aSEdward Tomasz Napierala error = ffs_susp_suspend(mp);
3151848286aSEdward Tomasz Napierala if (error != 0) {
3161848286aSEdward Tomasz Napierala vfs_unbusy(mp);
3171848286aSEdward Tomasz Napierala break;
3181848286aSEdward Tomasz Napierala }
3191848286aSEdward Tomasz Napierala error = devfs_set_cdevpriv(mp, ffs_susp_dtor);
32061b285acSKonstantin Belousov if (error != 0)
32161b285acSKonstantin Belousov ffs_susp_unsuspend(mp);
3221848286aSEdward Tomasz Napierala break;
3231848286aSEdward Tomasz Napierala case UFSRESUME:
3241848286aSEdward Tomasz Napierala error = devfs_get_cdevpriv((void **)&mp);
3251848286aSEdward Tomasz Napierala if (error != 0)
3261848286aSEdward Tomasz Napierala break;
3271848286aSEdward Tomasz Napierala /*
3281848286aSEdward Tomasz Napierala * This calls ffs_susp_dtor, which in turn unsuspends the fs.
3291848286aSEdward Tomasz Napierala * The dtor expects to be called without lock held, because
3301848286aSEdward Tomasz Napierala * sometimes it's called from here, and sometimes due to the
3311848286aSEdward Tomasz Napierala * file being closed or process exiting.
3321848286aSEdward Tomasz Napierala */
3331848286aSEdward Tomasz Napierala sx_xunlock(&ffs_susp_lock);
3341848286aSEdward Tomasz Napierala devfs_clear_cdevpriv();
3351848286aSEdward Tomasz Napierala return (0);
3361848286aSEdward Tomasz Napierala default:
3371848286aSEdward Tomasz Napierala error = ENXIO;
3381848286aSEdward Tomasz Napierala break;
3391848286aSEdward Tomasz Napierala }
3401848286aSEdward Tomasz Napierala
3411848286aSEdward Tomasz Napierala sx_xunlock(&ffs_susp_lock);
3421848286aSEdward Tomasz Napierala
3431848286aSEdward Tomasz Napierala return (error);
3441848286aSEdward Tomasz Napierala }
3451848286aSEdward Tomasz Napierala
3461848286aSEdward Tomasz Napierala void
ffs_susp_initialize(void)3471848286aSEdward Tomasz Napierala ffs_susp_initialize(void)
3481848286aSEdward Tomasz Napierala {
3491848286aSEdward Tomasz Napierala
3501848286aSEdward Tomasz Napierala sx_init(&ffs_susp_lock, "ffs_susp");
3511848286aSEdward Tomasz Napierala ffs_susp_dev = make_dev(&ffs_susp_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
3521848286aSEdward Tomasz Napierala "ufssuspend");
3531848286aSEdward Tomasz Napierala }
3541848286aSEdward Tomasz Napierala
3551848286aSEdward Tomasz Napierala void
ffs_susp_uninitialize(void)3561848286aSEdward Tomasz Napierala ffs_susp_uninitialize(void)
3571848286aSEdward Tomasz Napierala {
3581848286aSEdward Tomasz Napierala
3591848286aSEdward Tomasz Napierala destroy_dev(ffs_susp_dev);
3601848286aSEdward Tomasz Napierala sx_destroy(&ffs_susp_lock);
3611848286aSEdward Tomasz Napierala }
362