1 1.291 andvar /* $NetBSD: vnd.c,v 1.291 2025/09/07 21:31:21 andvar Exp $ */ 2 1.41 thorpej 3 1.41 thorpej /*- 4 1.274 ad * Copyright (c) 1996, 1997, 1998, 2008, 2020 The NetBSD Foundation, Inc. 5 1.41 thorpej * All rights reserved. 6 1.41 thorpej * 7 1.41 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.41 thorpej * by Jason R. Thorpe. 9 1.41 thorpej * 10 1.41 thorpej * Redistribution and use in source and binary forms, with or without 11 1.41 thorpej * modification, are permitted provided that the following conditions 12 1.41 thorpej * are met: 13 1.41 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.41 thorpej * notice, this list of conditions and the following disclaimer. 15 1.41 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.41 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.41 thorpej * documentation and/or other materials provided with the distribution. 18 1.41 thorpej * 19 1.41 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.41 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.41 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.48 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.48 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.41 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.41 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.41 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.41 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.41 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.41 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.41 thorpej */ 31 1.11 cgd 32 1.1 brezak /* 33 1.215 rmind * Copyright (c) 1988 University of Utah. 34 1.1 brezak * Copyright (c) 1990, 1993 35 1.1 brezak * The Regents of the University of California. All rights reserved. 36 1.1 brezak * 37 1.1 brezak * This code is derived from software contributed to Berkeley by 38 1.1 brezak * the Systems Programming Group of the University of Utah Computer 39 1.1 brezak * Science Department. 40 1.1 brezak * 41 1.1 brezak * Redistribution and use in source and binary forms, with or without 42 1.1 brezak * modification, are permitted provided that the following conditions 43 1.1 brezak * are met: 44 1.1 brezak * 1. Redistributions of source code must retain the above copyright 45 1.1 brezak * notice, this list of conditions and the following disclaimer. 46 1.1 brezak * 2. Redistributions in binary form must reproduce the above copyright 47 1.1 brezak * notice, this list of conditions and the following disclaimer in the 48 1.1 brezak * documentation and/or other materials provided with the distribution. 49 1.102 agc * 3. Neither the name of the University nor the names of its contributors 50 1.102 agc * may be used to endorse or promote products derived from this software 51 1.102 agc * without specific prior written permission. 52 1.102 agc * 53 1.102 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 1.102 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 1.102 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 1.102 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 1.102 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 1.102 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 1.102 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 1.102 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 1.102 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 1.102 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 1.102 agc * SUCH DAMAGE. 64 1.102 agc * 65 1.102 agc * from: Utah $Hdr: vn.c 1.13 94/04/02$ 66 1.102 agc * 67 1.102 agc * @(#)vn.c 8.9 (Berkeley) 5/14/95 68 1.102 agc */ 69 1.102 agc 70 1.102 agc /* 71 1.1 brezak * Vnode disk driver. 72 1.1 brezak * 73 1.1 brezak * Block/character interface to a vnode. Allows one to treat a file 74 1.1 brezak * as a disk (e.g. build a filesystem in it, mount it, etc.). 75 1.1 brezak * 76 1.157 jmmv * NOTE 1: If the vnode supports the VOP_BMAP and VOP_STRATEGY operations, 77 1.157 jmmv * this uses them to avoid distorting the local buffer cache. If those 78 1.157 jmmv * block-level operations are not available, this falls back to the regular 79 1.157 jmmv * read and write calls. Using these may distort the cache in some cases 80 1.157 jmmv * but better have the driver working than preventing it to work on file 81 1.157 jmmv * systems where the block-level operations are not implemented for 82 1.157 jmmv * whatever reason. 83 1.1 brezak * 84 1.1 brezak * NOTE 2: There is a security issue involved with this driver. 85 1.1 brezak * Once mounted all access to the contents of the "mapped" file via 86 1.1 brezak * the special file is controlled by the permissions on the special 87 1.1 brezak * file, the protection of the mapped file is ignored (effectively, 88 1.1 brezak * by using root credentials in all transactions). 89 1.1 brezak * 90 1.1 brezak * NOTE 3: Doesn't interact with leases, should it? 91 1.1 brezak */ 92 1.75 lukem 93 1.75 lukem #include <sys/cdefs.h> 94 1.291 andvar __KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.291 2025/09/07 21:31:21 andvar Exp $"); 95 1.55 thorpej 96 1.74 mrg #if defined(_KERNEL_OPT) 97 1.115 hubertf #include "opt_vnd.h" 98 1.211 mrg #include "opt_compat_netbsd.h" 99 1.74 mrg #endif 100 1.1 brezak 101 1.1 brezak #include <sys/param.h> 102 1.1 brezak #include <sys/systm.h> 103 1.1 brezak #include <sys/namei.h> 104 1.1 brezak #include <sys/proc.h> 105 1.112 bouyer #include <sys/kthread.h> 106 1.1 brezak #include <sys/errno.h> 107 1.1 brezak #include <sys/buf.h> 108 1.111 yamt #include <sys/bufq.h> 109 1.1 brezak #include <sys/malloc.h> 110 1.1 brezak #include <sys/ioctl.h> 111 1.16 cgd #include <sys/disklabel.h> 112 1.22 thorpej #include <sys/device.h> 113 1.22 thorpej #include <sys/disk.h> 114 1.22 thorpej #include <sys/stat.h> 115 1.1 brezak #include <sys/mount.h> 116 1.1 brezak #include <sys/vnode.h> 117 1.266 hannken #include <sys/fstrans.h> 118 1.1 brezak #include <sys/file.h> 119 1.1 brezak #include <sys/uio.h> 120 1.26 christos #include <sys/conf.h> 121 1.147 elad #include <sys/kauth.h> 122 1.257 pgoyette #include <sys/module.h> 123 1.271 pgoyette #include <sys/compat_stub.h> 124 1.274 ad #include <sys/atomic.h> 125 1.181 ad 126 1.289 mlelstv #include <uvm/uvm.h> 127 1.289 mlelstv 128 1.181 ad #include <net/zlib.h> 129 1.1 brezak 130 1.157 jmmv #include <miscfs/genfs/genfs.h> 131 1.1 brezak #include <miscfs/specfs/specdev.h> 132 1.1 brezak 133 1.204 dyoung #include <dev/dkvar.h> 134 1.41 thorpej #include <dev/vndvar.h> 135 1.41 thorpej 136 1.248 christos #include "ioconf.h" 137 1.248 christos 138 1.41 thorpej #if defined(VNDDEBUG) && !defined(DEBUG) 139 1.116 christos #define DEBUG 140 1.41 thorpej #endif 141 1.1 brezak 142 1.1 brezak #ifdef DEBUG 143 1.17 cgd int dovndcluster = 1; 144 1.116 christos #define VDB_FOLLOW 0x01 145 1.116 christos #define VDB_INIT 0x02 146 1.116 christos #define VDB_IO 0x04 147 1.116 christos #define VDB_LABEL 0x08 148 1.250 christos int vnddebug = 0; 149 1.1 brezak #endif 150 1.1 brezak 151 1.116 christos #define vndunit(x) DISKUNIT(x) 152 1.18 cgd 153 1.36 pk struct vndxfer { 154 1.129 yamt struct buf vx_buf; 155 1.129 yamt struct vnd_softc *vx_vnd; 156 1.18 cgd }; 157 1.129 yamt #define VND_BUFTOXFER(bp) ((struct vndxfer *)(void *)bp) 158 1.1 brezak 159 1.116 christos #define VND_GETXFER(vnd) pool_get(&(vnd)->sc_vxpool, PR_WAITOK) 160 1.116 christos #define VND_PUTXFER(vnd, vx) pool_put(&(vnd)->sc_vxpool, (vx)) 161 1.59 thorpej 162 1.116 christos #define VNDLABELDEV(dev) \ 163 1.116 christos (MAKEDISKDEV(major((dev)), vndunit((dev)), RAW_PART)) 164 1.41 thorpej 165 1.220 hannken #define VND_MAXPENDING(vnd) ((vnd)->sc_maxactive * 4) 166 1.269 mlelstv #define VND_MAXPAGES(vnd) (1024 * 1024 / PAGE_SIZE) 167 1.220 hannken 168 1.1 brezak 169 1.108 thorpej static void vndclear(struct vnd_softc *, int); 170 1.199 dyoung static int vnddoclear(struct vnd_softc *, int, int, bool); 171 1.147 elad static int vndsetcred(struct vnd_softc *, kauth_cred_t); 172 1.108 thorpej static void vndthrottle(struct vnd_softc *, struct vnode *); 173 1.108 thorpej static void vndiodone(struct buf *); 174 1.95 drochner #if 0 175 1.108 thorpej static void vndshutdown(void); 176 1.95 drochner #endif 177 1.16 cgd 178 1.108 thorpej static void vndgetdefaultlabel(struct vnd_softc *, struct disklabel *); 179 1.131 cube static void vndgetdisklabel(dev_t, struct vnd_softc *); 180 1.41 thorpej 181 1.108 thorpej static int vndlock(struct vnd_softc *); 182 1.108 thorpej static void vndunlock(struct vnd_softc *); 183 1.115 hubertf #ifdef VND_COMPRESSION 184 1.115 hubertf static void compstrategy(struct buf *, off_t); 185 1.115 hubertf static void *vnd_alloc(void *, u_int, u_int); 186 1.115 hubertf static void vnd_free(void *, void *); 187 1.115 hubertf #endif /* VND_COMPRESSION */ 188 1.86 gehenna 189 1.157 jmmv static void vndthread(void *); 190 1.162 thorpej static bool vnode_has_op(const struct vnode *, int); 191 1.157 jmmv static void handle_with_rdwr(struct vnd_softc *, const struct buf *, 192 1.157 jmmv struct buf *); 193 1.157 jmmv static void handle_with_strategy(struct vnd_softc *, const struct buf *, 194 1.157 jmmv struct buf *); 195 1.222 christos static void vnd_set_geometry(struct vnd_softc *); 196 1.112 bouyer 197 1.108 thorpej static dev_type_open(vndopen); 198 1.108 thorpej static dev_type_close(vndclose); 199 1.108 thorpej static dev_type_read(vndread); 200 1.108 thorpej static dev_type_write(vndwrite); 201 1.108 thorpej static dev_type_ioctl(vndioctl); 202 1.108 thorpej static dev_type_strategy(vndstrategy); 203 1.108 thorpej static dev_type_dump(vnddump); 204 1.108 thorpej static dev_type_size(vndsize); 205 1.86 gehenna 206 1.86 gehenna const struct bdevsw vnd_bdevsw = { 207 1.228 dholland .d_open = vndopen, 208 1.228 dholland .d_close = vndclose, 209 1.228 dholland .d_strategy = vndstrategy, 210 1.228 dholland .d_ioctl = vndioctl, 211 1.228 dholland .d_dump = vnddump, 212 1.228 dholland .d_psize = vndsize, 213 1.231 dholland .d_discard = nodiscard, 214 1.228 dholland .d_flag = D_DISK 215 1.86 gehenna }; 216 1.86 gehenna 217 1.86 gehenna const struct cdevsw vnd_cdevsw = { 218 1.228 dholland .d_open = vndopen, 219 1.228 dholland .d_close = vndclose, 220 1.228 dholland .d_read = vndread, 221 1.228 dholland .d_write = vndwrite, 222 1.228 dholland .d_ioctl = vndioctl, 223 1.228 dholland .d_stop = nostop, 224 1.228 dholland .d_tty = notty, 225 1.228 dholland .d_poll = nopoll, 226 1.228 dholland .d_mmap = nommap, 227 1.228 dholland .d_kqfilter = nokqfilter, 228 1.232 dholland .d_discard = nodiscard, 229 1.228 dholland .d_flag = D_DISK 230 1.86 gehenna }; 231 1.22 thorpej 232 1.176 cube static int vnd_match(device_t, cfdata_t, void *); 233 1.176 cube static void vnd_attach(device_t, device_t, void *); 234 1.176 cube static int vnd_detach(device_t, int); 235 1.131 cube 236 1.199 dyoung CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc), 237 1.199 dyoung vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); 238 1.131 cube 239 1.131 cube static struct vnd_softc *vnd_spawn(int); 240 1.276 maxv static int vnd_destroy(device_t); 241 1.89 mrg 242 1.276 maxv static const struct dkdriver vnddkdriver = { 243 1.243 mlelstv .d_strategy = vndstrategy, 244 1.243 mlelstv .d_minphys = minphys 245 1.243 mlelstv }; 246 1.210 riz 247 1.1 brezak void 248 1.160 christos vndattach(int num) 249 1.1 brezak { 250 1.131 cube int error; 251 1.131 cube 252 1.131 cube error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 253 1.131 cube if (error) 254 1.246 prlw1 aprint_error("%s: unable to register cfattach, error = %d\n", 255 1.246 prlw1 vnd_cd.cd_name, error); 256 1.131 cube } 257 1.1 brezak 258 1.131 cube static int 259 1.176 cube vnd_match(device_t self, cfdata_t cfdata, void *aux) 260 1.131 cube { 261 1.176 cube 262 1.131 cube return 1; 263 1.76 mrg } 264 1.76 mrg 265 1.131 cube static void 266 1.176 cube vnd_attach(device_t parent, device_t self, void *aux) 267 1.76 mrg { 268 1.176 cube struct vnd_softc *sc = device_private(self); 269 1.131 cube 270 1.176 cube sc->sc_dev = self; 271 1.131 cube sc->sc_comp_offsets = NULL; 272 1.131 cube sc->sc_comp_buff = NULL; 273 1.131 cube sc->sc_comp_decombuf = NULL; 274 1.131 cube bufq_alloc(&sc->sc_tab, "disksort", BUFQ_SORT_RAWBLOCK); 275 1.210 riz disk_init(&sc->sc_dkdev, device_xname(self), &vnddkdriver); 276 1.173 smb if (!pmf_device_register(self, NULL, NULL)) 277 1.173 smb aprint_error_dev(self, "couldn't establish power handler\n"); 278 1.131 cube } 279 1.82 hannken 280 1.131 cube static int 281 1.176 cube vnd_detach(device_t self, int flags) 282 1.131 cube { 283 1.199 dyoung int error; 284 1.176 cube struct vnd_softc *sc = device_private(self); 285 1.199 dyoung 286 1.199 dyoung if (sc->sc_flags & VNF_INITED) { 287 1.199 dyoung error = vnddoclear(sc, 0, -1, (flags & DETACH_FORCE) != 0); 288 1.199 dyoung if (error != 0) 289 1.199 dyoung return error; 290 1.199 dyoung } 291 1.132 cube 292 1.173 smb pmf_device_deregister(self); 293 1.132 cube bufq_free(sc->sc_tab); 294 1.170 ad disk_destroy(&sc->sc_dkdev); 295 1.132 cube 296 1.131 cube return 0; 297 1.131 cube } 298 1.89 mrg 299 1.131 cube static struct vnd_softc * 300 1.131 cube vnd_spawn(int unit) 301 1.131 cube { 302 1.201 cegger cfdata_t cf; 303 1.76 mrg 304 1.131 cube cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK); 305 1.131 cube cf->cf_name = vnd_cd.cd_name; 306 1.131 cube cf->cf_atname = vnd_cd.cd_name; 307 1.131 cube cf->cf_unit = unit; 308 1.131 cube cf->cf_fstate = FSTATE_STAR; 309 1.89 mrg 310 1.176 cube return device_private(config_attach_pseudo(cf)); 311 1.1 brezak } 312 1.1 brezak 313 1.276 maxv static int 314 1.176 cube vnd_destroy(device_t dev) 315 1.133 cube { 316 1.133 cube int error; 317 1.176 cube cfdata_t cf; 318 1.133 cube 319 1.145 thorpej cf = device_cfdata(dev); 320 1.146 cube error = config_detach(dev, DETACH_QUIET); 321 1.133 cube if (error) 322 1.133 cube return error; 323 1.136 yamt free(cf, M_DEVBUF); 324 1.133 cube return 0; 325 1.133 cube } 326 1.133 cube 327 1.108 thorpej static int 328 1.160 christos vndopen(dev_t dev, int flags, int mode, struct lwp *l) 329 1.1 brezak { 330 1.17 cgd int unit = vndunit(dev); 331 1.22 thorpej struct vnd_softc *sc; 332 1.22 thorpej int error = 0, part, pmask; 333 1.41 thorpej struct disklabel *lp; 334 1.1 brezak 335 1.1 brezak #ifdef DEBUG 336 1.17 cgd if (vnddebug & VDB_FOLLOW) 337 1.191 cegger printf("vndopen(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l); 338 1.1 brezak #endif 339 1.182 cegger sc = device_lookup_private(&vnd_cd, unit); 340 1.131 cube if (sc == NULL) { 341 1.131 cube sc = vnd_spawn(unit); 342 1.131 cube if (sc == NULL) 343 1.131 cube return ENOMEM; 344 1.242 mlelstv 345 1.242 mlelstv /* compatibility, keep disklabel after close */ 346 1.242 mlelstv sc->sc_flags = VNF_KLABEL; 347 1.131 cube } 348 1.22 thorpej 349 1.24 christos if ((error = vndlock(sc)) != 0) 350 1.197 dyoung return error; 351 1.22 thorpej 352 1.247 mlelstv mutex_enter(&sc->sc_dkdev.dk_openlock); 353 1.247 mlelstv 354 1.202 dyoung if ((sc->sc_flags & VNF_CLEARING) != 0) { 355 1.202 dyoung error = ENXIO; 356 1.202 dyoung goto done; 357 1.202 dyoung } 358 1.199 dyoung 359 1.41 thorpej lp = sc->sc_dkdev.dk_label; 360 1.41 thorpej 361 1.22 thorpej part = DISKPART(dev); 362 1.22 thorpej pmask = (1 << part); 363 1.22 thorpej 364 1.221 mlelstv if (sc->sc_dkdev.dk_nwedges != 0 && part != RAW_PART) { 365 1.221 mlelstv error = EBUSY; 366 1.221 mlelstv goto done; 367 1.221 mlelstv } 368 1.221 mlelstv 369 1.221 mlelstv if (sc->sc_flags & VNF_INITED) { 370 1.221 mlelstv if ((sc->sc_dkdev.dk_openmask & ~(1<<RAW_PART)) != 0) { 371 1.221 mlelstv /* 372 1.221 mlelstv * If any non-raw partition is open, but the disk 373 1.221 mlelstv * has been invalidated, disallow further opens. 374 1.221 mlelstv */ 375 1.221 mlelstv if ((sc->sc_flags & VNF_VLABEL) == 0) { 376 1.221 mlelstv error = EIO; 377 1.221 mlelstv goto done; 378 1.221 mlelstv } 379 1.221 mlelstv } else { 380 1.221 mlelstv /* 381 1.221 mlelstv * Load the partition info if not already loaded. 382 1.221 mlelstv */ 383 1.221 mlelstv if ((sc->sc_flags & VNF_VLABEL) == 0) { 384 1.221 mlelstv sc->sc_flags |= VNF_VLABEL; 385 1.221 mlelstv vndgetdisklabel(dev, sc); 386 1.221 mlelstv } 387 1.221 mlelstv } 388 1.221 mlelstv } 389 1.41 thorpej 390 1.41 thorpej /* Check that the partitions exists. */ 391 1.41 thorpej if (part != RAW_PART) { 392 1.41 thorpej if (((sc->sc_flags & VNF_INITED) == 0) || 393 1.41 thorpej ((part >= lp->d_npartitions) || 394 1.41 thorpej (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 395 1.41 thorpej error = ENXIO; 396 1.41 thorpej goto done; 397 1.41 thorpej } 398 1.41 thorpej } 399 1.41 thorpej 400 1.22 thorpej /* Prevent our unit from being unconfigured while open. */ 401 1.22 thorpej switch (mode) { 402 1.22 thorpej case S_IFCHR: 403 1.22 thorpej sc->sc_dkdev.dk_copenmask |= pmask; 404 1.22 thorpej break; 405 1.22 thorpej 406 1.22 thorpej case S_IFBLK: 407 1.22 thorpej sc->sc_dkdev.dk_bopenmask |= pmask; 408 1.22 thorpej break; 409 1.22 thorpej } 410 1.22 thorpej sc->sc_dkdev.dk_openmask = 411 1.22 thorpej sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; 412 1.22 thorpej 413 1.41 thorpej done: 414 1.247 mlelstv mutex_exit(&sc->sc_dkdev.dk_openlock); 415 1.22 thorpej vndunlock(sc); 416 1.197 dyoung return error; 417 1.1 brezak } 418 1.1 brezak 419 1.108 thorpej static int 420 1.160 christos vndclose(dev_t dev, int flags, int mode, struct lwp *l) 421 1.4 deraadt { 422 1.22 thorpej int unit = vndunit(dev); 423 1.22 thorpej struct vnd_softc *sc; 424 1.22 thorpej int error = 0, part; 425 1.22 thorpej 426 1.4 deraadt #ifdef DEBUG 427 1.17 cgd if (vnddebug & VDB_FOLLOW) 428 1.191 cegger printf("vndclose(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l); 429 1.4 deraadt #endif 430 1.182 cegger sc = device_lookup_private(&vnd_cd, unit); 431 1.131 cube if (sc == NULL) 432 1.131 cube return ENXIO; 433 1.22 thorpej 434 1.24 christos if ((error = vndlock(sc)) != 0) 435 1.197 dyoung return error; 436 1.22 thorpej 437 1.247 mlelstv mutex_enter(&sc->sc_dkdev.dk_openlock); 438 1.247 mlelstv 439 1.22 thorpej part = DISKPART(dev); 440 1.22 thorpej 441 1.22 thorpej /* ...that much closer to allowing unconfiguration... */ 442 1.22 thorpej switch (mode) { 443 1.22 thorpej case S_IFCHR: 444 1.22 thorpej sc->sc_dkdev.dk_copenmask &= ~(1 << part); 445 1.22 thorpej break; 446 1.22 thorpej 447 1.22 thorpej case S_IFBLK: 448 1.22 thorpej sc->sc_dkdev.dk_bopenmask &= ~(1 << part); 449 1.22 thorpej break; 450 1.22 thorpej } 451 1.22 thorpej sc->sc_dkdev.dk_openmask = 452 1.22 thorpej sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; 453 1.22 thorpej 454 1.242 mlelstv /* are we last opener ? */ 455 1.242 mlelstv if (sc->sc_dkdev.dk_openmask == 0) { 456 1.242 mlelstv if ((sc->sc_flags & VNF_KLABEL) == 0) 457 1.242 mlelstv sc->sc_flags &= ~VNF_VLABEL; 458 1.242 mlelstv } 459 1.242 mlelstv 460 1.247 mlelstv mutex_exit(&sc->sc_dkdev.dk_openlock); 461 1.247 mlelstv 462 1.22 thorpej vndunlock(sc); 463 1.134 cube 464 1.134 cube if ((sc->sc_flags & VNF_INITED) == 0) { 465 1.176 cube if ((error = vnd_destroy(sc->sc_dev)) != 0) { 466 1.176 cube aprint_error_dev(sc->sc_dev, 467 1.176 cube "unable to detach instance\n"); 468 1.134 cube return error; 469 1.134 cube } 470 1.134 cube } 471 1.134 cube 472 1.197 dyoung return 0; 473 1.4 deraadt } 474 1.4 deraadt 475 1.1 brezak /* 476 1.135 cube * Queue the request, and wakeup the kernel thread to handle it. 477 1.1 brezak */ 478 1.108 thorpej static void 479 1.108 thorpej vndstrategy(struct buf *bp) 480 1.1 brezak { 481 1.17 cgd int unit = vndunit(bp->b_dev); 482 1.131 cube struct vnd_softc *vnd = 483 1.182 cegger device_lookup_private(&vnd_cd, unit); 484 1.189 bouyer struct disklabel *lp; 485 1.127 yamt daddr_t blkno; 486 1.112 bouyer int s = splbio(); 487 1.112 bouyer 488 1.189 bouyer if (vnd == NULL) { 489 1.189 bouyer bp->b_error = ENXIO; 490 1.189 bouyer goto done; 491 1.189 bouyer } 492 1.189 bouyer lp = vnd->sc_dkdev.dk_label; 493 1.189 bouyer 494 1.17 cgd if ((vnd->sc_flags & VNF_INITED) == 0) { 495 1.1 brezak bp->b_error = ENXIO; 496 1.169 ad goto done; 497 1.41 thorpej } 498 1.41 thorpej 499 1.41 thorpej /* 500 1.41 thorpej * The transfer must be a whole number of blocks. 501 1.41 thorpej */ 502 1.41 thorpej if ((bp->b_bcount % lp->d_secsize) != 0) { 503 1.41 thorpej bp->b_error = EINVAL; 504 1.169 ad goto done; 505 1.1 brezak } 506 1.41 thorpej 507 1.41 thorpej /* 508 1.94 yamt * check if we're read-only. 509 1.94 yamt */ 510 1.94 yamt if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) { 511 1.94 yamt bp->b_error = EACCES; 512 1.169 ad goto done; 513 1.165 yamt } 514 1.165 yamt 515 1.165 yamt /* If it's a nil transfer, wake up the top half now. */ 516 1.165 yamt if (bp->b_bcount == 0) { 517 1.94 yamt goto done; 518 1.94 yamt } 519 1.94 yamt 520 1.41 thorpej /* 521 1.112 bouyer * Do bounds checking and adjust transfer. If there's an error, 522 1.112 bouyer * the bounds check will flag that for us. 523 1.41 thorpej */ 524 1.139 yamt if (DISKPART(bp->b_dev) == RAW_PART) { 525 1.139 yamt if (bounds_check_with_mediasize(bp, DEV_BSIZE, 526 1.139 yamt vnd->sc_size) <= 0) 527 1.139 yamt goto done; 528 1.139 yamt } else { 529 1.112 bouyer if (bounds_check_with_label(&vnd->sc_dkdev, 530 1.112 bouyer bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0) 531 1.112 bouyer goto done; 532 1.1 brezak } 533 1.127 yamt 534 1.127 yamt /* 535 1.127 yamt * Put the block number in terms of the logical blocksize 536 1.127 yamt * of the "device". 537 1.127 yamt */ 538 1.127 yamt 539 1.127 yamt blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 540 1.127 yamt 541 1.127 yamt /* 542 1.127 yamt * Translate the partition-relative block number to an absolute. 543 1.127 yamt */ 544 1.127 yamt if (DISKPART(bp->b_dev) != RAW_PART) { 545 1.127 yamt struct partition *pp; 546 1.127 yamt 547 1.127 yamt pp = &vnd->sc_dkdev.dk_label->d_partitions[ 548 1.127 yamt DISKPART(bp->b_dev)]; 549 1.127 yamt blkno += pp->p_offset; 550 1.127 yamt } 551 1.127 yamt bp->b_rawblkno = blkno; 552 1.127 yamt 553 1.112 bouyer #ifdef DEBUG 554 1.112 bouyer if (vnddebug & VDB_FOLLOW) 555 1.112 bouyer printf("vndstrategy(%p): unit %d\n", bp, unit); 556 1.112 bouyer #endif 557 1.220 hannken if ((vnd->sc_flags & VNF_USE_VN_RDWR)) { 558 1.288 hannken /* 559 1.288 hannken * Limit the number of pending requests to not exhaust 560 1.288 hannken * resources needed for I/O but always allow the worker 561 1.288 hannken * thread to add requests, as a wedge on vnd queues 562 1.288 hannken * requests with biodone() -> dkstart() -> vndstrategy(). 563 1.288 hannken */ 564 1.289 mlelstv if (curlwp != vnd->sc_kthread && curlwp != uvm.pagedaemon_lwp) { 565 1.288 hannken while (vnd->sc_pending >= VND_MAXPENDING(vnd)) 566 1.288 hannken tsleep(&vnd->sc_pending, PRIBIO, "vndpc", 0); 567 1.288 hannken } 568 1.220 hannken vnd->sc_pending++; 569 1.288 hannken KASSERT(vnd->sc_pending > 0); 570 1.220 hannken } 571 1.192 yamt bufq_put(vnd->sc_tab, bp); 572 1.112 bouyer wakeup(&vnd->sc_tab); 573 1.112 bouyer splx(s); 574 1.112 bouyer return; 575 1.165 yamt 576 1.112 bouyer done: 577 1.165 yamt bp->b_resid = bp->b_bcount; 578 1.112 bouyer biodone(bp); 579 1.112 bouyer splx(s); 580 1.112 bouyer } 581 1.41 thorpej 582 1.184 cegger static bool 583 1.184 cegger vnode_has_strategy(struct vnd_softc *vnd) 584 1.184 cegger { 585 1.184 cegger return vnode_has_op(vnd->sc_vp, VOFFSET(vop_bmap)) && 586 1.184 cegger vnode_has_op(vnd->sc_vp, VOFFSET(vop_strategy)); 587 1.184 cegger } 588 1.184 cegger 589 1.265 mlelstv /* Verify that I/O requests cannot be smaller than the 590 1.265 mlelstv * smallest I/O size supported by the backend. 591 1.265 mlelstv */ 592 1.255 mlelstv static bool 593 1.255 mlelstv vnode_has_large_blocks(struct vnd_softc *vnd) 594 1.255 mlelstv { 595 1.265 mlelstv u_int32_t vnd_secsize, iosize; 596 1.255 mlelstv 597 1.265 mlelstv iosize = vnd->sc_iosize; 598 1.255 mlelstv vnd_secsize = vnd->sc_geom.vng_secsize; 599 1.255 mlelstv 600 1.265 mlelstv return vnd_secsize % iosize != 0; 601 1.255 mlelstv } 602 1.255 mlelstv 603 1.185 cegger /* XXX this function needs a reliable check to detect 604 1.185 cegger * sparse files. Otherwise, bmap/strategy may be used 605 1.185 cegger * and fail on non-allocated blocks. VOP_READ/VOP_WRITE 606 1.185 cegger * works on sparse files. 607 1.185 cegger */ 608 1.185 cegger #if notyet 609 1.184 cegger static bool 610 1.184 cegger vnode_strategy_probe(struct vnd_softc *vnd) 611 1.184 cegger { 612 1.184 cegger int error; 613 1.184 cegger daddr_t nbn; 614 1.184 cegger 615 1.184 cegger if (!vnode_has_strategy(vnd)) 616 1.184 cegger return false; 617 1.184 cegger 618 1.255 mlelstv if (vnode_has_large_blocks(vnd)) 619 1.255 mlelstv return false; 620 1.255 mlelstv 621 1.184 cegger /* Convert the first logical block number to its 622 1.184 cegger * physical block number. 623 1.184 cegger */ 624 1.184 cegger error = 0; 625 1.200 ad vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 626 1.184 cegger error = VOP_BMAP(vnd->sc_vp, 0, NULL, &nbn, NULL); 627 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 628 1.184 cegger 629 1.184 cegger /* Test if that worked. */ 630 1.184 cegger if (error == 0 && (long)nbn == -1) 631 1.184 cegger return false; 632 1.184 cegger 633 1.184 cegger return true; 634 1.184 cegger } 635 1.185 cegger #endif 636 1.184 cegger 637 1.126 yamt static void 638 1.112 bouyer vndthread(void *arg) 639 1.112 bouyer { 640 1.112 bouyer struct vnd_softc *vnd = arg; 641 1.157 jmmv int s; 642 1.157 jmmv 643 1.184 cegger /* Determine whether we can *use* VOP_BMAP and VOP_STRATEGY to 644 1.157 jmmv * directly access the backing vnode. If we can, use these two 645 1.157 jmmv * operations to avoid messing with the local buffer cache. 646 1.157 jmmv * Otherwise fall back to regular VOP_READ/VOP_WRITE operations 647 1.157 jmmv * which are guaranteed to work with any file system. */ 648 1.218 hannken if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0 && 649 1.218 hannken ! vnode_has_strategy(vnd)) 650 1.218 hannken vnd->sc_flags |= VNF_USE_VN_RDWR; 651 1.157 jmmv 652 1.255 mlelstv /* VOP_STRATEGY can only be used if the backing vnode allows 653 1.255 mlelstv * to access blocks as small as defined by the vnd geometry. 654 1.255 mlelstv */ 655 1.255 mlelstv if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0 && 656 1.255 mlelstv vnode_has_large_blocks(vnd)) 657 1.255 mlelstv vnd->sc_flags |= VNF_USE_VN_RDWR; 658 1.255 mlelstv 659 1.157 jmmv #ifdef DEBUG 660 1.157 jmmv if (vnddebug & VDB_INIT) 661 1.157 jmmv printf("vndthread: vp %p, %s\n", vnd->sc_vp, 662 1.218 hannken (vnd->sc_flags & VNF_USE_VN_RDWR) == 0 ? 663 1.157 jmmv "using bmap/strategy operations" : 664 1.157 jmmv "using read/write operations"); 665 1.157 jmmv #endif 666 1.36 pk 667 1.61 thorpej s = splbio(); 668 1.112 bouyer vnd->sc_flags |= VNF_KTHREAD; 669 1.112 bouyer wakeup(&vnd->sc_kthread); 670 1.37 pk 671 1.112 bouyer /* 672 1.157 jmmv * Dequeue requests and serve them depending on the available 673 1.157 jmmv * vnode operations. 674 1.112 bouyer */ 675 1.112 bouyer while ((vnd->sc_flags & VNF_VUNCONF) == 0) { 676 1.129 yamt struct vndxfer *vnx; 677 1.129 yamt struct buf *obp; 678 1.129 yamt struct buf *bp; 679 1.129 yamt 680 1.192 yamt obp = bufq_get(vnd->sc_tab); 681 1.129 yamt if (obp == NULL) { 682 1.112 bouyer tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0); 683 1.112 bouyer continue; 684 1.112 bouyer }; 685 1.220 hannken if ((vnd->sc_flags & VNF_USE_VN_RDWR)) { 686 1.288 hannken KASSERT(vnd->sc_pending > 0); 687 1.220 hannken if (vnd->sc_pending-- == VND_MAXPENDING(vnd)) 688 1.220 hannken wakeup(&vnd->sc_pending); 689 1.220 hannken } 690 1.112 bouyer splx(s); 691 1.5 cgd #ifdef DEBUG 692 1.112 bouyer if (vnddebug & VDB_FOLLOW) 693 1.183 cegger printf("vndthread(%p)\n", obp); 694 1.1 brezak #endif 695 1.18 cgd 696 1.112 bouyer if (vnd->sc_vp->v_mount == NULL) { 697 1.129 yamt obp->b_error = ENXIO; 698 1.112 bouyer goto done; 699 1.112 bouyer } 700 1.115 hubertf #ifdef VND_COMPRESSION 701 1.115 hubertf /* handle a compressed read */ 702 1.226 martin if ((obp->b_flags & B_READ) != 0 && (vnd->sc_flags & VNF_COMP)) { 703 1.157 jmmv off_t bn; 704 1.244 prlw1 705 1.157 jmmv /* Convert to a byte offset within the file. */ 706 1.157 jmmv bn = obp->b_rawblkno * 707 1.157 jmmv vnd->sc_dkdev.dk_label->d_secsize; 708 1.157 jmmv 709 1.129 yamt compstrategy(obp, bn); 710 1.115 hubertf goto done; 711 1.115 hubertf } 712 1.115 hubertf #endif /* VND_COMPRESSION */ 713 1.244 prlw1 714 1.1 brezak /* 715 1.112 bouyer * Allocate a header for this transfer and link it to the 716 1.112 bouyer * buffer 717 1.1 brezak */ 718 1.1 brezak s = splbio(); 719 1.112 bouyer vnx = VND_GETXFER(vnd); 720 1.1 brezak splx(s); 721 1.129 yamt vnx->vx_vnd = vnd; 722 1.129 yamt 723 1.157 jmmv s = splbio(); 724 1.157 jmmv while (vnd->sc_active >= vnd->sc_maxactive) { 725 1.157 jmmv tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0); 726 1.157 jmmv } 727 1.157 jmmv vnd->sc_active++; 728 1.157 jmmv splx(s); 729 1.157 jmmv 730 1.157 jmmv /* Instrumentation. */ 731 1.157 jmmv disk_busy(&vnd->sc_dkdev); 732 1.157 jmmv 733 1.129 yamt bp = &vnx->vx_buf; 734 1.175 ad buf_init(bp); 735 1.277 jdolecek bp->b_flags = (obp->b_flags & (B_READ | B_PHYS | B_RAW)); 736 1.175 ad bp->b_oflags = obp->b_oflags; 737 1.175 ad bp->b_cflags = obp->b_cflags; 738 1.129 yamt bp->b_iodone = vndiodone; 739 1.129 yamt bp->b_private = obp; 740 1.138 yamt bp->b_vp = vnd->sc_vp; 741 1.217 rmind bp->b_objlock = bp->b_vp->v_interlock; 742 1.129 yamt bp->b_data = obp->b_data; 743 1.165 yamt bp->b_bcount = obp->b_bcount; 744 1.129 yamt BIO_COPYPRIO(bp, obp); 745 1.129 yamt 746 1.270 hannken /* Make sure the request succeeds while suspending this fs. */ 747 1.270 hannken fstrans_start_lazy(vnd->sc_vp->v_mount); 748 1.270 hannken 749 1.157 jmmv /* Handle the request using the appropriate operations. */ 750 1.218 hannken if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0) 751 1.157 jmmv handle_with_strategy(vnd, obp, bp); 752 1.157 jmmv else 753 1.157 jmmv handle_with_rdwr(vnd, obp, bp); 754 1.157 jmmv 755 1.270 hannken fstrans_done(vnd->sc_vp->v_mount); 756 1.270 hannken 757 1.157 jmmv s = splbio(); 758 1.157 jmmv continue; 759 1.157 jmmv 760 1.157 jmmv done: 761 1.157 jmmv biodone(obp); 762 1.129 yamt s = splbio(); 763 1.157 jmmv } 764 1.157 jmmv 765 1.157 jmmv vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF); 766 1.157 jmmv wakeup(&vnd->sc_kthread); 767 1.157 jmmv splx(s); 768 1.157 jmmv kthread_exit(0); 769 1.157 jmmv } 770 1.157 jmmv 771 1.157 jmmv /* 772 1.157 jmmv * Checks if the given vnode supports the requested operation. 773 1.157 jmmv * The operation is specified the offset returned by VOFFSET. 774 1.157 jmmv * 775 1.157 jmmv * XXX The test below used to determine this is quite fragile 776 1.157 jmmv * because it relies on the file system to use genfs to specify 777 1.157 jmmv * unimplemented operations. There might be another way to do 778 1.157 jmmv * it more cleanly. 779 1.157 jmmv */ 780 1.162 thorpej static bool 781 1.157 jmmv vnode_has_op(const struct vnode *vp, int opoffset) 782 1.157 jmmv { 783 1.157 jmmv int (*defaultp)(void *); 784 1.157 jmmv int (*opp)(void *); 785 1.157 jmmv 786 1.157 jmmv defaultp = vp->v_op[VOFFSET(vop_default)]; 787 1.157 jmmv opp = vp->v_op[opoffset]; 788 1.157 jmmv 789 1.157 jmmv return opp != defaultp && opp != genfs_eopnotsupp && 790 1.157 jmmv opp != genfs_badop && opp != genfs_nullop; 791 1.157 jmmv } 792 1.157 jmmv 793 1.157 jmmv /* 794 1.245 prlw1 * Handles the read/write request given in 'bp' using the vnode's VOP_READ 795 1.157 jmmv * and VOP_WRITE operations. 796 1.157 jmmv * 797 1.157 jmmv * 'obp' is a pointer to the original request fed to the vnd device. 798 1.157 jmmv */ 799 1.157 jmmv static void 800 1.157 jmmv handle_with_rdwr(struct vnd_softc *vnd, const struct buf *obp, struct buf *bp) 801 1.157 jmmv { 802 1.162 thorpej bool doread; 803 1.157 jmmv off_t offset; 804 1.218 hannken size_t len, resid; 805 1.157 jmmv struct vnode *vp; 806 1.274 ad int npages; 807 1.157 jmmv 808 1.157 jmmv doread = bp->b_flags & B_READ; 809 1.157 jmmv offset = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize; 810 1.218 hannken len = bp->b_bcount; 811 1.157 jmmv vp = vnd->sc_vp; 812 1.157 jmmv 813 1.157 jmmv #if defined(DEBUG) 814 1.157 jmmv if (vnddebug & VDB_IO) 815 1.157 jmmv printf("vnd (rdwr): vp %p, %s, rawblkno 0x%" PRIx64 816 1.157 jmmv ", secsize %d, offset %" PRIu64 817 1.161 chs ", bcount %d\n", 818 1.157 jmmv vp, doread ? "read" : "write", obp->b_rawblkno, 819 1.157 jmmv vnd->sc_dkdev.dk_label->d_secsize, offset, 820 1.161 chs bp->b_bcount); 821 1.157 jmmv #endif 822 1.157 jmmv 823 1.157 jmmv /* Issue the read or write operation. */ 824 1.157 jmmv bp->b_error = 825 1.157 jmmv vn_rdwr(doread ? UIO_READ : UIO_WRITE, 826 1.218 hannken vp, bp->b_data, len, offset, UIO_SYSSPACE, 827 1.269 mlelstv IO_ADV_ENCODE(POSIX_FADV_NOREUSE) | IO_DIRECT, 828 1.269 mlelstv vnd->sc_cred, &resid, NULL); 829 1.158 martin bp->b_resid = resid; 830 1.157 jmmv 831 1.269 mlelstv /* 832 1.269 mlelstv * Avoid caching too many pages, the vnd user 833 1.269 mlelstv * is usually a filesystem and caches itself. 834 1.269 mlelstv * We need some amount of caching to not hinder 835 1.269 mlelstv * read-ahead and write-behind operations. 836 1.269 mlelstv */ 837 1.274 ad npages = atomic_load_relaxed(&vp->v_uobj.uo_npages); 838 1.274 ad if (npages > VND_MAXPAGES(vnd)) { 839 1.274 ad rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 840 1.269 mlelstv (void) VOP_PUTPAGES(vp, 0, 0, 841 1.269 mlelstv PGO_ALLPAGES | PGO_CLEANIT | PGO_FREE); 842 1.274 ad } 843 1.218 hannken 844 1.157 jmmv /* We need to increase the number of outputs on the vnode if 845 1.159 jmmv * there was any write to it. */ 846 1.175 ad if (!doread) { 847 1.217 rmind mutex_enter(vp->v_interlock); 848 1.175 ad vp->v_numoutput++; 849 1.217 rmind mutex_exit(vp->v_interlock); 850 1.175 ad } 851 1.157 jmmv 852 1.157 jmmv biodone(bp); 853 1.157 jmmv } 854 1.157 jmmv 855 1.157 jmmv /* 856 1.291 andvar * Handles the read/write request given in 'bp' using the vnode's VOP_BMAP 857 1.157 jmmv * and VOP_STRATEGY operations. 858 1.157 jmmv * 859 1.157 jmmv * 'obp' is a pointer to the original request fed to the vnd device. 860 1.157 jmmv */ 861 1.157 jmmv static void 862 1.157 jmmv handle_with_strategy(struct vnd_softc *vnd, const struct buf *obp, 863 1.157 jmmv struct buf *bp) 864 1.157 jmmv { 865 1.157 jmmv int bsize, error, flags, skipped; 866 1.157 jmmv size_t resid, sz; 867 1.157 jmmv off_t bn, offset; 868 1.175 ad struct vnode *vp; 869 1.240 bouyer struct buf *nbp = NULL; 870 1.157 jmmv 871 1.157 jmmv flags = obp->b_flags; 872 1.157 jmmv 873 1.157 jmmv 874 1.157 jmmv /* convert to a byte offset within the file. */ 875 1.157 jmmv bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize; 876 1.157 jmmv 877 1.157 jmmv bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize; 878 1.290 mlelstv /* use default if the filesystem didn't specify a block size */ 879 1.290 mlelstv if (bsize <= 0) 880 1.290 mlelstv bsize = BLKDEV_IOSIZE; 881 1.157 jmmv skipped = 0; 882 1.138 yamt 883 1.157 jmmv /* 884 1.157 jmmv * Break the request into bsize pieces and feed them 885 1.157 jmmv * sequentially using VOP_BMAP/VOP_STRATEGY. 886 1.157 jmmv * We do it this way to keep from flooding NFS servers if we 887 1.157 jmmv * are connected to an NFS file. This places the burden on 888 1.157 jmmv * the client rather than the server. 889 1.157 jmmv */ 890 1.157 jmmv error = 0; 891 1.165 yamt bp->b_resid = bp->b_bcount; 892 1.240 bouyer for (offset = 0, resid = bp->b_resid; /* true */; 893 1.157 jmmv resid -= sz, offset += sz) { 894 1.157 jmmv daddr_t nbn; 895 1.157 jmmv int off, nra; 896 1.157 jmmv 897 1.157 jmmv nra = 0; 898 1.200 ad vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 899 1.157 jmmv error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra); 900 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 901 1.51 pk 902 1.157 jmmv if (error == 0 && (long)nbn == -1) 903 1.157 jmmv error = EIO; 904 1.126 yamt 905 1.112 bouyer /* 906 1.157 jmmv * If there was an error or a hole in the file...punt. 907 1.157 jmmv * Note that we may have to wait for any operations 908 1.157 jmmv * that we have already fired off before releasing 909 1.157 jmmv * the buffer. 910 1.157 jmmv * 911 1.157 jmmv * XXX we could deal with holes here but it would be 912 1.157 jmmv * a hassle (in the write case). 913 1.112 bouyer */ 914 1.157 jmmv if (error) { 915 1.157 jmmv skipped += resid; 916 1.157 jmmv break; 917 1.157 jmmv } 918 1.41 thorpej 919 1.157 jmmv #ifdef DEBUG 920 1.157 jmmv if (!dovndcluster) 921 1.112 bouyer nra = 0; 922 1.112 bouyer #endif 923 1.51 pk 924 1.157 jmmv off = bn % bsize; 925 1.157 jmmv sz = MIN(((off_t)1 + nra) * bsize - off, resid); 926 1.116 christos #ifdef DEBUG 927 1.157 jmmv if (vnddebug & VDB_IO) 928 1.157 jmmv printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64 929 1.175 ad " sz 0x%zx\n", vnd->sc_vp, vp, (long long)bn, 930 1.175 ad nbn, sz); 931 1.112 bouyer #endif 932 1.51 pk 933 1.175 ad nbp = getiobuf(vp, true); 934 1.157 jmmv nestiobuf_setup(bp, nbp, offset, sz); 935 1.157 jmmv nbp->b_blkno = nbn + btodb(off); 936 1.51 pk 937 1.129 yamt #if 0 /* XXX #ifdef DEBUG */ 938 1.157 jmmv if (vnddebug & VDB_IO) 939 1.157 jmmv printf("vndstart(%ld): bp %p vp %p blkno " 940 1.157 jmmv "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n", 941 1.157 jmmv (long) (vnd-vnd_softc), &nbp->vb_buf, 942 1.157 jmmv nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno, 943 1.157 jmmv nbp->vb_buf.b_flags, nbp->vb_buf.b_data, 944 1.157 jmmv nbp->vb_buf.b_bcount); 945 1.157 jmmv #endif 946 1.240 bouyer if (resid == sz) { 947 1.240 bouyer break; 948 1.240 bouyer } 949 1.157 jmmv VOP_STRATEGY(vp, nbp); 950 1.157 jmmv bn += sz; 951 1.157 jmmv } 952 1.240 bouyer if (!(flags & B_READ)) { 953 1.240 bouyer struct vnode *w_vp; 954 1.240 bouyer /* 955 1.240 bouyer * this is the last nested buf, account for 956 1.240 bouyer * the parent buf write too. 957 1.240 bouyer * This has to be done last, so that 958 1.240 bouyer * fsync won't wait for this write which 959 1.241 bouyer * has no chance to complete before all nested bufs 960 1.240 bouyer * have been queued. But it has to be done 961 1.244 prlw1 * before the last VOP_STRATEGY() 962 1.240 bouyer * or the call to nestiobuf_done(). 963 1.240 bouyer */ 964 1.240 bouyer w_vp = bp->b_vp; 965 1.240 bouyer mutex_enter(w_vp->v_interlock); 966 1.240 bouyer w_vp->v_numoutput++; 967 1.240 bouyer mutex_exit(w_vp->v_interlock); 968 1.240 bouyer } 969 1.240 bouyer KASSERT(skipped != 0 || nbp != NULL); 970 1.244 prlw1 if (skipped) 971 1.240 bouyer nestiobuf_done(bp, skipped, error); 972 1.244 prlw1 else 973 1.240 bouyer VOP_STRATEGY(vp, nbp); 974 1.1 brezak } 975 1.1 brezak 976 1.126 yamt static void 977 1.129 yamt vndiodone(struct buf *bp) 978 1.126 yamt { 979 1.129 yamt struct vndxfer *vnx = VND_BUFTOXFER(bp); 980 1.129 yamt struct vnd_softc *vnd = vnx->vx_vnd; 981 1.129 yamt struct buf *obp = bp->b_private; 982 1.206 bouyer int s = splbio(); 983 1.126 yamt 984 1.273 ad KERNEL_LOCK(1, NULL); /* XXXSMP */ 985 1.129 yamt KASSERT(&vnx->vx_buf == bp); 986 1.129 yamt KASSERT(vnd->sc_active > 0); 987 1.126 yamt #ifdef DEBUG 988 1.126 yamt if (vnddebug & VDB_IO) { 989 1.126 yamt printf("vndiodone1: bp %p iodone: error %d\n", 990 1.169 ad bp, bp->b_error); 991 1.126 yamt } 992 1.126 yamt #endif 993 1.126 yamt disk_unbusy(&vnd->sc_dkdev, bp->b_bcount - bp->b_resid, 994 1.126 yamt (bp->b_flags & B_READ)); 995 1.129 yamt vnd->sc_active--; 996 1.129 yamt if (vnd->sc_active == 0) { 997 1.129 yamt wakeup(&vnd->sc_tab); 998 1.1 brezak } 999 1.273 ad KERNEL_UNLOCK_ONE(NULL); /* XXXSMP */ 1000 1.206 bouyer splx(s); 1001 1.129 yamt obp->b_error = bp->b_error; 1002 1.129 yamt obp->b_resid = bp->b_resid; 1003 1.186 kardel buf_destroy(bp); 1004 1.129 yamt VND_PUTXFER(vnd, vnx); 1005 1.129 yamt biodone(obp); 1006 1.20 mycroft } 1007 1.20 mycroft 1008 1.22 thorpej /* ARGSUSED */ 1009 1.108 thorpej static int 1010 1.160 christos vndread(dev_t dev, struct uio *uio, int flags) 1011 1.20 mycroft { 1012 1.22 thorpej int unit = vndunit(dev); 1013 1.22 thorpej struct vnd_softc *sc; 1014 1.20 mycroft 1015 1.20 mycroft #ifdef DEBUG 1016 1.20 mycroft if (vnddebug & VDB_FOLLOW) 1017 1.191 cegger printf("vndread(0x%"PRIx64", %p)\n", dev, uio); 1018 1.20 mycroft #endif 1019 1.22 thorpej 1020 1.182 cegger sc = device_lookup_private(&vnd_cd, unit); 1021 1.131 cube if (sc == NULL) 1022 1.131 cube return ENXIO; 1023 1.22 thorpej 1024 1.22 thorpej if ((sc->sc_flags & VNF_INITED) == 0) 1025 1.197 dyoung return ENXIO; 1026 1.22 thorpej 1027 1.197 dyoung return physio(vndstrategy, NULL, dev, B_READ, minphys, uio); 1028 1.20 mycroft } 1029 1.20 mycroft 1030 1.22 thorpej /* ARGSUSED */ 1031 1.108 thorpej static int 1032 1.160 christos vndwrite(dev_t dev, struct uio *uio, int flags) 1033 1.20 mycroft { 1034 1.22 thorpej int unit = vndunit(dev); 1035 1.22 thorpej struct vnd_softc *sc; 1036 1.20 mycroft 1037 1.20 mycroft #ifdef DEBUG 1038 1.20 mycroft if (vnddebug & VDB_FOLLOW) 1039 1.191 cegger printf("vndwrite(0x%"PRIx64", %p)\n", dev, uio); 1040 1.20 mycroft #endif 1041 1.22 thorpej 1042 1.182 cegger sc = device_lookup_private(&vnd_cd, unit); 1043 1.131 cube if (sc == NULL) 1044 1.131 cube return ENXIO; 1045 1.22 thorpej 1046 1.22 thorpej if ((sc->sc_flags & VNF_INITED) == 0) 1047 1.197 dyoung return ENXIO; 1048 1.22 thorpej 1049 1.197 dyoung return physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio); 1050 1.1 brezak } 1051 1.1 brezak 1052 1.120 christos static int 1053 1.124 christos vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va) 1054 1.120 christos { 1055 1.219 hannken int error; 1056 1.120 christos struct vnd_softc *vnd; 1057 1.120 christos 1058 1.120 christos if (*un == -1) 1059 1.120 christos *un = unit; 1060 1.120 christos if (*un < 0) 1061 1.120 christos return EINVAL; 1062 1.120 christos 1063 1.182 cegger vnd = device_lookup_private(&vnd_cd, *un); 1064 1.131 cube if (vnd == NULL) 1065 1.225 christos return -1; 1066 1.120 christos 1067 1.120 christos if ((vnd->sc_flags & VNF_INITED) == 0) 1068 1.122 christos return -1; 1069 1.120 christos 1070 1.219 hannken vn_lock(vnd->sc_vp, LK_SHARED | LK_RETRY); 1071 1.219 hannken error = VOP_GETATTR(vnd->sc_vp, va, l->l_cred); 1072 1.219 hannken VOP_UNLOCK(vnd->sc_vp); 1073 1.219 hannken return error; 1074 1.120 christos } 1075 1.120 christos 1076 1.199 dyoung static int 1077 1.199 dyoung vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force) 1078 1.199 dyoung { 1079 1.199 dyoung int error; 1080 1.199 dyoung 1081 1.199 dyoung if ((error = vndlock(vnd)) != 0) 1082 1.199 dyoung return error; 1083 1.199 dyoung 1084 1.199 dyoung /* 1085 1.199 dyoung * Don't unconfigure if any other partitions are open 1086 1.199 dyoung * or if both the character and block flavors of this 1087 1.199 dyoung * partition are open. 1088 1.199 dyoung */ 1089 1.204 dyoung if (DK_BUSY(vnd, pmask) && !force) { 1090 1.199 dyoung vndunlock(vnd); 1091 1.199 dyoung return EBUSY; 1092 1.199 dyoung } 1093 1.199 dyoung 1094 1.221 mlelstv /* Delete all of our wedges */ 1095 1.221 mlelstv dkwedge_delall(&vnd->sc_dkdev); 1096 1.221 mlelstv 1097 1.199 dyoung /* 1098 1.199 dyoung * XXX vndclear() might call vndclose() implicitly; 1099 1.199 dyoung * release lock to avoid recursion 1100 1.199 dyoung * 1101 1.199 dyoung * Set VNF_CLEARING to prevent vndopen() from 1102 1.199 dyoung * sneaking in after we vndunlock(). 1103 1.199 dyoung */ 1104 1.199 dyoung vnd->sc_flags |= VNF_CLEARING; 1105 1.199 dyoung vndunlock(vnd); 1106 1.199 dyoung vndclear(vnd, minor); 1107 1.199 dyoung #ifdef DEBUG 1108 1.199 dyoung if (vnddebug & VDB_INIT) 1109 1.249 christos printf("%s: CLRed\n", __func__); 1110 1.199 dyoung #endif 1111 1.199 dyoung 1112 1.199 dyoung /* Destroy the xfer and buffer pools. */ 1113 1.199 dyoung pool_destroy(&vnd->sc_vxpool); 1114 1.199 dyoung 1115 1.199 dyoung /* Detach the disk. */ 1116 1.199 dyoung disk_detach(&vnd->sc_dkdev); 1117 1.199 dyoung 1118 1.199 dyoung return 0; 1119 1.199 dyoung } 1120 1.199 dyoung 1121 1.249 christos static int 1122 1.249 christos vndioctl_get(struct lwp *l, void *data, int unit, struct vattr *va) 1123 1.249 christos { 1124 1.249 christos int error; 1125 1.249 christos 1126 1.249 christos KASSERT(l); 1127 1.251 christos 1128 1.252 christos /* the first member is always int vnd_unit in all the versions */ 1129 1.249 christos if (*(int *)data >= vnd_cd.cd_ndevs) 1130 1.249 christos return ENXIO; 1131 1.249 christos 1132 1.249 christos switch (error = vnd_cget(l, unit, (int *)data, va)) { 1133 1.249 christos case -1: 1134 1.249 christos /* unused is not an error */ 1135 1.253 christos memset(va, 0, sizeof(*va)); 1136 1.249 christos /*FALLTHROUGH*/ 1137 1.249 christos case 0: 1138 1.249 christos return 0; 1139 1.249 christos default: 1140 1.249 christos return error; 1141 1.249 christos } 1142 1.249 christos } 1143 1.249 christos 1144 1.1 brezak /* ARGSUSED */ 1145 1.108 thorpej static int 1146 1.163 christos vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1147 1.1 brezak { 1148 1.199 dyoung bool force; 1149 1.17 cgd int unit = vndunit(dev); 1150 1.65 augustss struct vnd_softc *vnd; 1151 1.17 cgd struct vnd_ioctl *vio; 1152 1.1 brezak struct vattr vattr; 1153 1.214 dholland struct pathbuf *pb; 1154 1.282 dholland struct vnode *vp; 1155 1.32 mycroft int error, part, pmask; 1156 1.223 christos uint64_t geomsize; 1157 1.94 yamt int fflags; 1158 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1159 1.70 fvdl struct disklabel newlabel; 1160 1.70 fvdl #endif 1161 1.1 brezak 1162 1.1 brezak #ifdef DEBUG 1163 1.17 cgd if (vnddebug & VDB_FOLLOW) 1164 1.191 cegger printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n", 1165 1.148 ad dev, cmd, data, flag, l->l_proc, unit); 1166 1.1 brezak #endif 1167 1.249 christos /* Do the get's first; they don't need initialization or verification */ 1168 1.249 christos switch (cmd) { 1169 1.271 pgoyette case VNDIOCGET: 1170 1.249 christos if ((error = vndioctl_get(l, data, unit, &vattr)) != 0) 1171 1.249 christos return error; 1172 1.249 christos 1173 1.271 pgoyette struct vnd_user *vnu = data; 1174 1.249 christos vnu->vnu_dev = vattr.va_fsid; 1175 1.249 christos vnu->vnu_ino = vattr.va_fileid; 1176 1.249 christos return 0; 1177 1.249 christos 1178 1.271 pgoyette default: 1179 1.271 pgoyette /* First check for COMPAT_50 hook */ 1180 1.272 pgoyette MODULE_HOOK_CALL(compat_vndioctl_50_hook, 1181 1.271 pgoyette (cmd, l, data, unit, &vattr, vndioctl_get), 1182 1.271 pgoyette enosys(), error); 1183 1.249 christos 1184 1.271 pgoyette /* 1185 1.271 pgoyette * If not present, then COMPAT_30 hook also not 1186 1.271 pgoyette * present, so just continue with checks for the 1187 1.271 pgoyette * "write" commands 1188 1.271 pgoyette */ 1189 1.271 pgoyette if (error == ENOSYS) { 1190 1.271 pgoyette error = 0; 1191 1.271 pgoyette break; 1192 1.271 pgoyette } 1193 1.249 christos 1194 1.271 pgoyette /* If not already handled, try the COMPAT_30 hook */ 1195 1.271 pgoyette if (error == EPASSTHROUGH) 1196 1.272 pgoyette MODULE_HOOK_CALL(compat_vndioctl_30_hook, 1197 1.271 pgoyette (cmd, l, data, unit, &vattr, vndioctl_get), 1198 1.271 pgoyette enosys(), error); 1199 1.271 pgoyette 1200 1.271 pgoyette /* If no COMPAT_30 module, or not handled, check writes */ 1201 1.271 pgoyette if (error == ENOSYS || error == EPASSTHROUGH) { 1202 1.271 pgoyette error = 0; 1203 1.271 pgoyette break; 1204 1.271 pgoyette } 1205 1.271 pgoyette return error; 1206 1.249 christos } 1207 1.249 christos 1208 1.249 christos vnd = device_lookup_private(&vnd_cd, unit); 1209 1.249 christos if (vnd == NULL) 1210 1.131 cube return ENXIO; 1211 1.17 cgd vio = (struct vnd_ioctl *)data; 1212 1.43 thorpej 1213 1.43 thorpej /* Must be open for writes for these commands... */ 1214 1.43 thorpej switch (cmd) { 1215 1.271 pgoyette case VNDIOCSET50: 1216 1.271 pgoyette case VNDIOCCLR50: 1217 1.271 pgoyette if (!compat_vndioctl_50_hook.hooked) 1218 1.271 pgoyette return EINVAL; 1219 1.271 pgoyette /* FALLTHROUGH */ 1220 1.43 thorpej case VNDIOCSET: 1221 1.43 thorpej case VNDIOCCLR: 1222 1.43 thorpej case DIOCSDINFO: 1223 1.43 thorpej case DIOCWDINFO: 1224 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1225 1.70 fvdl case ODIOCSDINFO: 1226 1.70 fvdl case ODIOCWDINFO: 1227 1.70 fvdl #endif 1228 1.99 thorpej case DIOCKLABEL: 1229 1.43 thorpej case DIOCWLABEL: 1230 1.275 jdolecek case DIOCCACHESYNC: 1231 1.43 thorpej if ((flag & FWRITE) == 0) 1232 1.197 dyoung return EBADF; 1233 1.43 thorpej } 1234 1.43 thorpej 1235 1.1 brezak switch (cmd) { 1236 1.284 mlelstv case VNDIOCSET50: 1237 1.284 mlelstv case VNDIOCSET: 1238 1.284 mlelstv /* Must not be initialized */ 1239 1.284 mlelstv if (vnd->sc_flags & VNF_INITED) 1240 1.284 mlelstv return EBUSY; 1241 1.284 mlelstv break; 1242 1.284 mlelstv default: 1243 1.284 mlelstv /* Must be initialized */ 1244 1.43 thorpej if ((vnd->sc_flags & VNF_INITED) == 0) 1245 1.197 dyoung return ENXIO; 1246 1.284 mlelstv break; 1247 1.43 thorpej } 1248 1.1 brezak 1249 1.238 christos error = disk_ioctl(&vnd->sc_dkdev, dev, cmd, data, flag, l); 1250 1.238 christos if (error != EPASSTHROUGH) 1251 1.238 christos return error; 1252 1.238 christos 1253 1.43 thorpej switch (cmd) { 1254 1.212 mrg case VNDIOCSET50: 1255 1.17 cgd case VNDIOCSET: 1256 1.24 christos if ((error = vndlock(vnd)) != 0) 1257 1.197 dyoung return error; 1258 1.22 thorpej 1259 1.94 yamt fflags = FREAD; 1260 1.94 yamt if ((vio->vnd_flags & VNDIOF_READONLY) == 0) 1261 1.94 yamt fflags |= FWRITE; 1262 1.267 mlelstv if ((vio->vnd_flags & VNDIOF_FILEIO) != 0) 1263 1.267 mlelstv vnd->sc_flags |= VNF_USE_VN_RDWR; 1264 1.214 dholland error = pathbuf_copyin(vio->vnd_file, &pb); 1265 1.214 dholland if (error) { 1266 1.214 dholland goto unlock_and_exit; 1267 1.214 dholland } 1268 1.282 dholland error = vn_open(NULL, pb, 0, fflags, 0, &vp, NULL, NULL); 1269 1.282 dholland if (error != 0) { 1270 1.214 dholland pathbuf_destroy(pb); 1271 1.83 enami goto unlock_and_exit; 1272 1.214 dholland } 1273 1.143 dogcow KASSERT(l); 1274 1.282 dholland error = VOP_GETATTR(vp, &vattr, l->l_cred); 1275 1.282 dholland if (!error && vp->v_type != VREG) 1276 1.94 yamt error = EOPNOTSUPP; 1277 1.205 dsl if (!error && vattr.va_bytes < vattr.va_size) 1278 1.218 hannken /* File is definitely sparse, use vn_rdwr() */ 1279 1.218 hannken vnd->sc_flags |= VNF_USE_VN_RDWR; 1280 1.115 hubertf if (error) { 1281 1.282 dholland VOP_UNLOCK(vp); 1282 1.115 hubertf goto close_and_exit; 1283 1.115 hubertf } 1284 1.115 hubertf 1285 1.116 christos /* If using a compressed file, initialize its info */ 1286 1.115 hubertf /* (or abort with an error if kernel has no compression) */ 1287 1.267 mlelstv if (vio->vnd_flags & VNDIOF_COMP) { 1288 1.115 hubertf #ifdef VND_COMPRESSION 1289 1.116 christos struct vnd_comp_header *ch; 1290 1.116 christos int i; 1291 1.261 riastrad uint32_t comp_size; 1292 1.261 riastrad uint32_t comp_maxsize; 1293 1.244 prlw1 1294 1.283 andvar /* allocate space for compressed file header */ 1295 1.116 christos ch = malloc(sizeof(struct vnd_comp_header), 1296 1.261 riastrad M_TEMP, M_WAITOK); 1297 1.244 prlw1 1298 1.116 christos /* read compressed file header */ 1299 1.282 dholland error = vn_rdwr(UIO_READ, vp, (void *)ch, 1300 1.261 riastrad sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE, 1301 1.261 riastrad IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1302 1.198 dyoung if (error) { 1303 1.116 christos free(ch, M_TEMP); 1304 1.282 dholland VOP_UNLOCK(vp); 1305 1.116 christos goto close_and_exit; 1306 1.116 christos } 1307 1.244 prlw1 1308 1.261 riastrad if (be32toh(ch->block_size) == 0 || 1309 1.261 riastrad be32toh(ch->num_blocks) > UINT32_MAX - 1) { 1310 1.260 riastrad free(ch, M_TEMP); 1311 1.282 dholland VOP_UNLOCK(vp); 1312 1.260 riastrad goto close_and_exit; 1313 1.260 riastrad } 1314 1.260 riastrad 1315 1.116 christos /* save some header info */ 1316 1.261 riastrad vnd->sc_comp_blksz = be32toh(ch->block_size); 1317 1.116 christos /* note last offset is the file byte size */ 1318 1.261 riastrad vnd->sc_comp_numoffs = be32toh(ch->num_blocks) + 1; 1319 1.116 christos free(ch, M_TEMP); 1320 1.254 christos if (!DK_DEV_BSIZE_OK(vnd->sc_comp_blksz)) { 1321 1.282 dholland VOP_UNLOCK(vp); 1322 1.116 christos error = EINVAL; 1323 1.116 christos goto close_and_exit; 1324 1.116 christos } 1325 1.260 riastrad KASSERT(0 < vnd->sc_comp_blksz); 1326 1.260 riastrad KASSERT(0 < vnd->sc_comp_numoffs); 1327 1.262 riastrad /* 1328 1.262 riastrad * @#^@!$& gcc -Wtype-limits refuses to let me 1329 1.262 riastrad * write SIZE_MAX/sizeof(uint64_t) < numoffs, 1330 1.262 riastrad * because the range of the type on amd64 makes 1331 1.262 riastrad * the comparisons always false. 1332 1.262 riastrad */ 1333 1.262 riastrad #if SIZE_MAX <= UINT32_MAX*(64/CHAR_BIT) 1334 1.262 riastrad if (SIZE_MAX/sizeof(uint64_t) < vnd->sc_comp_numoffs) { 1335 1.282 dholland VOP_UNLOCK(vp); 1336 1.262 riastrad error = EINVAL; 1337 1.262 riastrad goto close_and_exit; 1338 1.262 riastrad } 1339 1.262 riastrad #endif 1340 1.262 riastrad if ((vattr.va_size < sizeof(struct vnd_comp_header)) || 1341 1.260 riastrad (vattr.va_size - sizeof(struct vnd_comp_header) < 1342 1.260 riastrad sizeof(uint64_t)*vnd->sc_comp_numoffs) || 1343 1.260 riastrad (UQUAD_MAX/vnd->sc_comp_blksz < 1344 1.260 riastrad vnd->sc_comp_numoffs - 1)) { 1345 1.282 dholland VOP_UNLOCK(vp); 1346 1.116 christos error = EINVAL; 1347 1.116 christos goto close_and_exit; 1348 1.116 christos } 1349 1.244 prlw1 1350 1.116 christos /* set decompressed file size */ 1351 1.260 riastrad KASSERT(vnd->sc_comp_numoffs - 1 <= 1352 1.260 riastrad UQUAD_MAX/vnd->sc_comp_blksz); 1353 1.116 christos vattr.va_size = 1354 1.152 elad ((u_quad_t)vnd->sc_comp_numoffs - 1) * 1355 1.152 elad (u_quad_t)vnd->sc_comp_blksz; 1356 1.244 prlw1 1357 1.116 christos /* allocate space for all the compressed offsets */ 1358 1.260 riastrad __CTASSERT(UINT32_MAX <= UQUAD_MAX/sizeof(uint64_t)); 1359 1.116 christos vnd->sc_comp_offsets = 1360 1.261 riastrad malloc(sizeof(uint64_t) * vnd->sc_comp_numoffs, 1361 1.261 riastrad M_DEVBUF, M_WAITOK); 1362 1.244 prlw1 1363 1.116 christos /* read in the offsets */ 1364 1.282 dholland error = vn_rdwr(UIO_READ, vp, 1365 1.261 riastrad (void *)vnd->sc_comp_offsets, 1366 1.261 riastrad sizeof(uint64_t) * vnd->sc_comp_numoffs, 1367 1.261 riastrad sizeof(struct vnd_comp_header), UIO_SYSSPACE, 1368 1.148 ad IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1369 1.198 dyoung if (error) { 1370 1.282 dholland VOP_UNLOCK(vp); 1371 1.116 christos goto close_and_exit; 1372 1.116 christos } 1373 1.116 christos /* 1374 1.116 christos * find largest block size (used for allocation limit). 1375 1.116 christos * Also convert offset to native byte order. 1376 1.116 christos */ 1377 1.116 christos comp_maxsize = 0; 1378 1.116 christos for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) { 1379 1.116 christos vnd->sc_comp_offsets[i] = 1380 1.261 riastrad be64toh(vnd->sc_comp_offsets[i]); 1381 1.261 riastrad comp_size = 1382 1.261 riastrad be64toh(vnd->sc_comp_offsets[i + 1]) 1383 1.261 riastrad - vnd->sc_comp_offsets[i]; 1384 1.116 christos if (comp_size > comp_maxsize) 1385 1.116 christos comp_maxsize = comp_size; 1386 1.116 christos } 1387 1.116 christos vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] = 1388 1.261 riastrad be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs 1389 1.261 riastrad - 1]); 1390 1.244 prlw1 1391 1.116 christos /* create compressed data buffer */ 1392 1.116 christos vnd->sc_comp_buff = malloc(comp_maxsize, 1393 1.261 riastrad M_DEVBUF, M_WAITOK); 1394 1.244 prlw1 1395 1.116 christos /* create decompressed buffer */ 1396 1.116 christos vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz, 1397 1.261 riastrad M_DEVBUF, M_WAITOK); 1398 1.116 christos vnd->sc_comp_buffblk = -1; 1399 1.244 prlw1 1400 1.116 christos /* Initialize decompress stream */ 1401 1.196 cegger memset(&vnd->sc_comp_stream, 0, sizeof(z_stream)); 1402 1.116 christos vnd->sc_comp_stream.zalloc = vnd_alloc; 1403 1.116 christos vnd->sc_comp_stream.zfree = vnd_free; 1404 1.116 christos error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS); 1405 1.198 dyoung if (error) { 1406 1.198 dyoung if (vnd->sc_comp_stream.msg) 1407 1.116 christos printf("vnd%d: compressed file, %s\n", 1408 1.261 riastrad unit, vnd->sc_comp_stream.msg); 1409 1.282 dholland VOP_UNLOCK(vp); 1410 1.116 christos error = EINVAL; 1411 1.116 christos goto close_and_exit; 1412 1.116 christos } 1413 1.244 prlw1 1414 1.116 christos vnd->sc_flags |= VNF_COMP | VNF_READONLY; 1415 1.115 hubertf #else /* !VND_COMPRESSION */ 1416 1.282 dholland VOP_UNLOCK(vp); 1417 1.115 hubertf error = EOPNOTSUPP; 1418 1.83 enami goto close_and_exit; 1419 1.115 hubertf #endif /* VND_COMPRESSION */ 1420 1.116 christos } 1421 1.244 prlw1 1422 1.282 dholland VOP_UNLOCK(vp); 1423 1.282 dholland vnd->sc_vp = vp; 1424 1.17 cgd vnd->sc_size = btodb(vattr.va_size); /* note truncation */ 1425 1.41 thorpej 1426 1.265 mlelstv /* get smallest I/O size for underlying device, fall back to 1427 1.265 mlelstv * fundamental I/O size of underlying filesystem 1428 1.265 mlelstv */ 1429 1.265 mlelstv error = bdev_ioctl(vattr.va_fsid, DIOCGSECTORSIZE, &vnd->sc_iosize, FKIOCTL, l); 1430 1.265 mlelstv if (error) 1431 1.265 mlelstv vnd->sc_iosize = vnd->sc_vp->v_mount->mnt_stat.f_frsize; 1432 1.265 mlelstv 1433 1.280 mlelstv /* Default I/O size to DEV_BSIZE */ 1434 1.280 mlelstv if (vnd->sc_iosize == 0) 1435 1.280 mlelstv vnd->sc_iosize = DEV_BSIZE; 1436 1.280 mlelstv 1437 1.41 thorpej /* 1438 1.41 thorpej * Use pseudo-geometry specified. If none was provided, 1439 1.41 thorpej * use "standard" Adaptec fictitious geometry. 1440 1.41 thorpej */ 1441 1.41 thorpej if (vio->vnd_flags & VNDIOF_HASGEOM) { 1442 1.41 thorpej 1443 1.72 thorpej memcpy(&vnd->sc_geom, &vio->vnd_geom, 1444 1.41 thorpej sizeof(vio->vnd_geom)); 1445 1.41 thorpej 1446 1.41 thorpej /* 1447 1.41 thorpej * Sanity-check the sector size. 1448 1.41 thorpej */ 1449 1.254 christos if (!DK_DEV_BSIZE_OK(vnd->sc_geom.vng_secsize) || 1450 1.254 christos vnd->sc_geom.vng_ntracks == 0 || 1451 1.254 christos vnd->sc_geom.vng_nsectors == 0) { 1452 1.83 enami error = EINVAL; 1453 1.83 enami goto close_and_exit; 1454 1.41 thorpej } 1455 1.41 thorpej 1456 1.41 thorpej /* 1457 1.268 mlelstv * Compute missing cylinder count from size 1458 1.268 mlelstv */ 1459 1.268 mlelstv if (vnd->sc_geom.vng_ncylinders == 0) 1460 1.278 mlelstv vnd->sc_geom.vng_ncylinders = vnd->sc_size / ( 1461 1.278 mlelstv (vnd->sc_geom.vng_secsize / DEV_BSIZE) * 1462 1.278 mlelstv vnd->sc_geom.vng_ntracks * 1463 1.268 mlelstv vnd->sc_geom.vng_nsectors); 1464 1.268 mlelstv 1465 1.268 mlelstv /* 1466 1.41 thorpej * Compute the size (in DEV_BSIZE blocks) specified 1467 1.41 thorpej * by the geometry. 1468 1.41 thorpej */ 1469 1.235 mlelstv geomsize = (int64_t)vnd->sc_geom.vng_nsectors * 1470 1.41 thorpej vnd->sc_geom.vng_ntracks * 1471 1.235 mlelstv vnd->sc_geom.vng_ncylinders * 1472 1.41 thorpej (vnd->sc_geom.vng_secsize / DEV_BSIZE); 1473 1.41 thorpej 1474 1.41 thorpej /* 1475 1.41 thorpej * Sanity-check the size against the specified 1476 1.41 thorpej * geometry. 1477 1.41 thorpej */ 1478 1.41 thorpej if (vnd->sc_size < geomsize) { 1479 1.83 enami error = EINVAL; 1480 1.83 enami goto close_and_exit; 1481 1.41 thorpej } 1482 1.118 drochner } else if (vnd->sc_size >= (32 * 64)) { 1483 1.41 thorpej /* 1484 1.41 thorpej * Size must be at least 2048 DEV_BSIZE blocks 1485 1.41 thorpej * (1M) in order to use this geometry. 1486 1.41 thorpej */ 1487 1.41 thorpej vnd->sc_geom.vng_secsize = DEV_BSIZE; 1488 1.41 thorpej vnd->sc_geom.vng_nsectors = 32; 1489 1.41 thorpej vnd->sc_geom.vng_ntracks = 64; 1490 1.41 thorpej vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); 1491 1.118 drochner } else { 1492 1.118 drochner vnd->sc_geom.vng_secsize = DEV_BSIZE; 1493 1.118 drochner vnd->sc_geom.vng_nsectors = 1; 1494 1.118 drochner vnd->sc_geom.vng_ntracks = 1; 1495 1.118 drochner vnd->sc_geom.vng_ncylinders = vnd->sc_size; 1496 1.41 thorpej } 1497 1.41 thorpej 1498 1.222 christos vnd_set_geometry(vnd); 1499 1.174 riz 1500 1.94 yamt if (vio->vnd_flags & VNDIOF_READONLY) { 1501 1.94 yamt vnd->sc_flags |= VNF_READONLY; 1502 1.94 yamt } 1503 1.94 yamt 1504 1.148 ad if ((error = vndsetcred(vnd, l->l_cred)) != 0) 1505 1.83 enami goto close_and_exit; 1506 1.112 bouyer 1507 1.17 cgd vndthrottle(vnd, vnd->sc_vp); 1508 1.205 dsl vio->vnd_osize = dbtob(vnd->sc_size); 1509 1.212 mrg if (cmd != VNDIOCSET50) 1510 1.205 dsl vio->vnd_size = dbtob(vnd->sc_size); 1511 1.17 cgd vnd->sc_flags |= VNF_INITED; 1512 1.112 bouyer 1513 1.112 bouyer /* create the kernel thread, wait for it to be up */ 1514 1.168 ad error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd, 1515 1.216 joerg &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev)); 1516 1.112 bouyer if (error) 1517 1.112 bouyer goto close_and_exit; 1518 1.112 bouyer while ((vnd->sc_flags & VNF_KTHREAD) == 0) { 1519 1.112 bouyer tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); 1520 1.112 bouyer } 1521 1.17 cgd #ifdef DEBUG 1522 1.17 cgd if (vnddebug & VDB_INIT) 1523 1.45 fair printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", 1524 1.41 thorpej vnd->sc_vp, (unsigned long) vnd->sc_size, 1525 1.41 thorpej vnd->sc_geom.vng_secsize, 1526 1.41 thorpej vnd->sc_geom.vng_nsectors, 1527 1.41 thorpej vnd->sc_geom.vng_ntracks, 1528 1.41 thorpej vnd->sc_geom.vng_ncylinders); 1529 1.1 brezak #endif 1530 1.22 thorpej 1531 1.23 thorpej /* Attach the disk. */ 1532 1.170 ad disk_attach(&vnd->sc_dkdev); 1533 1.23 thorpej 1534 1.59 thorpej /* Initialize the xfer and buffer pools. */ 1535 1.59 thorpej pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 1536 1.166 ad 0, 0, "vndxpl", NULL, IPL_BIO); 1537 1.59 thorpej 1538 1.22 thorpej vndunlock(vnd); 1539 1.22 thorpej 1540 1.214 dholland pathbuf_destroy(pb); 1541 1.221 mlelstv 1542 1.221 mlelstv /* Discover wedges on this disk */ 1543 1.221 mlelstv dkwedge_discover(&vnd->sc_dkdev); 1544 1.221 mlelstv 1545 1.1 brezak break; 1546 1.83 enami 1547 1.83 enami close_and_exit: 1548 1.282 dholland (void) vn_close(vp, fflags, l->l_cred); 1549 1.214 dholland pathbuf_destroy(pb); 1550 1.83 enami unlock_and_exit: 1551 1.115 hubertf #ifdef VND_COMPRESSION 1552 1.116 christos /* free any allocated memory (for compressed file) */ 1553 1.198 dyoung if (vnd->sc_comp_offsets) { 1554 1.116 christos free(vnd->sc_comp_offsets, M_DEVBUF); 1555 1.116 christos vnd->sc_comp_offsets = NULL; 1556 1.116 christos } 1557 1.198 dyoung if (vnd->sc_comp_buff) { 1558 1.116 christos free(vnd->sc_comp_buff, M_DEVBUF); 1559 1.116 christos vnd->sc_comp_buff = NULL; 1560 1.116 christos } 1561 1.198 dyoung if (vnd->sc_comp_decombuf) { 1562 1.116 christos free(vnd->sc_comp_decombuf, M_DEVBUF); 1563 1.116 christos vnd->sc_comp_decombuf = NULL; 1564 1.116 christos } 1565 1.115 hubertf #endif /* VND_COMPRESSION */ 1566 1.83 enami vndunlock(vnd); 1567 1.197 dyoung return error; 1568 1.1 brezak 1569 1.212 mrg case VNDIOCCLR50: 1570 1.17 cgd case VNDIOCCLR: 1571 1.22 thorpej part = DISKPART(dev); 1572 1.22 thorpej pmask = (1 << part); 1573 1.199 dyoung force = (vio->vnd_flags & VNDIOF_FORCE) != 0; 1574 1.22 thorpej 1575 1.199 dyoung if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) 1576 1.199 dyoung return error; 1577 1.23 thorpej 1578 1.1 brezak break; 1579 1.80 atatat 1580 1.1 brezak 1581 1.41 thorpej case DIOCWDINFO: 1582 1.41 thorpej case DIOCSDINFO: 1583 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1584 1.70 fvdl case ODIOCWDINFO: 1585 1.70 fvdl case ODIOCSDINFO: 1586 1.70 fvdl #endif 1587 1.70 fvdl { 1588 1.70 fvdl struct disklabel *lp; 1589 1.70 fvdl 1590 1.41 thorpej if ((error = vndlock(vnd)) != 0) 1591 1.197 dyoung return error; 1592 1.41 thorpej 1593 1.41 thorpej vnd->sc_flags |= VNF_LABELLING; 1594 1.41 thorpej 1595 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1596 1.70 fvdl if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1597 1.70 fvdl memset(&newlabel, 0, sizeof newlabel); 1598 1.70 fvdl memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1599 1.70 fvdl lp = &newlabel; 1600 1.70 fvdl } else 1601 1.70 fvdl #endif 1602 1.70 fvdl lp = (struct disklabel *)data; 1603 1.70 fvdl 1604 1.41 thorpej error = setdisklabel(vnd->sc_dkdev.dk_label, 1605 1.70 fvdl lp, 0, vnd->sc_dkdev.dk_cpulabel); 1606 1.41 thorpej if (error == 0) { 1607 1.70 fvdl if (cmd == DIOCWDINFO 1608 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1609 1.70 fvdl || cmd == ODIOCWDINFO 1610 1.70 fvdl #endif 1611 1.70 fvdl ) 1612 1.41 thorpej error = writedisklabel(VNDLABELDEV(dev), 1613 1.41 thorpej vndstrategy, vnd->sc_dkdev.dk_label, 1614 1.41 thorpej vnd->sc_dkdev.dk_cpulabel); 1615 1.41 thorpej } 1616 1.41 thorpej 1617 1.41 thorpej vnd->sc_flags &= ~VNF_LABELLING; 1618 1.41 thorpej 1619 1.41 thorpej vndunlock(vnd); 1620 1.41 thorpej 1621 1.41 thorpej if (error) 1622 1.197 dyoung return error; 1623 1.41 thorpej break; 1624 1.70 fvdl } 1625 1.41 thorpej 1626 1.99 thorpej case DIOCKLABEL: 1627 1.99 thorpej if (*(int *)data != 0) 1628 1.99 thorpej vnd->sc_flags |= VNF_KLABEL; 1629 1.99 thorpej else 1630 1.99 thorpej vnd->sc_flags &= ~VNF_KLABEL; 1631 1.99 thorpej break; 1632 1.99 thorpej 1633 1.41 thorpej case DIOCWLABEL: 1634 1.41 thorpej if (*(int *)data != 0) 1635 1.41 thorpej vnd->sc_flags |= VNF_WLABEL; 1636 1.41 thorpej else 1637 1.41 thorpej vnd->sc_flags &= ~VNF_WLABEL; 1638 1.41 thorpej break; 1639 1.22 thorpej 1640 1.47 thorpej case DIOCGDEFLABEL: 1641 1.47 thorpej vndgetdefaultlabel(vnd, (struct disklabel *)data); 1642 1.47 thorpej break; 1643 1.70 fvdl 1644 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1645 1.70 fvdl case ODIOCGDEFLABEL: 1646 1.70 fvdl vndgetdefaultlabel(vnd, &newlabel); 1647 1.70 fvdl if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1648 1.71 fvdl return ENOTTY; 1649 1.70 fvdl memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1650 1.70 fvdl break; 1651 1.70 fvdl #endif 1652 1.195 apb 1653 1.275 jdolecek case DIOCGSTRATEGY: 1654 1.275 jdolecek { 1655 1.275 jdolecek struct disk_strategy *dks = (void *)data; 1656 1.275 jdolecek 1657 1.275 jdolecek /* No lock needed, never changed */ 1658 1.275 jdolecek strlcpy(dks->dks_name, 1659 1.275 jdolecek bufq_getstrategyname(vnd->sc_tab), 1660 1.275 jdolecek sizeof(dks->dks_name)); 1661 1.275 jdolecek dks->dks_paramlen = 0; 1662 1.275 jdolecek break; 1663 1.275 jdolecek } 1664 1.275 jdolecek case DIOCGCACHE: 1665 1.275 jdolecek { 1666 1.275 jdolecek int *bits = (int *)data; 1667 1.275 jdolecek *bits |= DKCACHE_READ | DKCACHE_WRITE; 1668 1.275 jdolecek break; 1669 1.275 jdolecek } 1670 1.194 christos case DIOCCACHESYNC: 1671 1.194 christos vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1672 1.194 christos error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred, 1673 1.195 apb FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0); 1674 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 1675 1.194 christos return error; 1676 1.47 thorpej 1677 1.1 brezak default: 1678 1.197 dyoung return ENOTTY; 1679 1.1 brezak } 1680 1.22 thorpej 1681 1.197 dyoung return 0; 1682 1.1 brezak } 1683 1.1 brezak 1684 1.1 brezak /* 1685 1.1 brezak * Duplicate the current processes' credentials. Since we are called only 1686 1.1 brezak * as the result of a SET ioctl and only root can do that, any future access 1687 1.1 brezak * to this "disk" is essentially as root. Note that credentials may change 1688 1.1 brezak * if some other uid can write directly to the mapped file (NFS). 1689 1.1 brezak */ 1690 1.108 thorpej static int 1691 1.147 elad vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred) 1692 1.1 brezak { 1693 1.1 brezak struct uio auio; 1694 1.1 brezak struct iovec aiov; 1695 1.5 cgd char *tmpbuf; 1696 1.5 cgd int error; 1697 1.1 brezak 1698 1.147 elad vnd->sc_cred = kauth_cred_dup(cred); 1699 1.5 cgd tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); 1700 1.5 cgd 1701 1.1 brezak /* XXX: Horrible kludge to establish credentials for NFS */ 1702 1.1 brezak aiov.iov_base = tmpbuf; 1703 1.264 riastrad aiov.iov_len = uimin(DEV_BSIZE, dbtob(vnd->sc_size)); 1704 1.1 brezak auio.uio_iov = &aiov; 1705 1.1 brezak auio.uio_iovcnt = 1; 1706 1.1 brezak auio.uio_offset = 0; 1707 1.1 brezak auio.uio_rw = UIO_READ; 1708 1.1 brezak auio.uio_resid = aiov.iov_len; 1709 1.141 yamt UIO_SETUP_SYSSPACE(&auio); 1710 1.56 fvdl vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1711 1.17 cgd error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred); 1712 1.54 bad if (error == 0) { 1713 1.54 bad /* 1714 1.54 bad * Because vnd does all IO directly through the vnode 1715 1.56 fvdl * we need to flush (at least) the buffer from the above 1716 1.54 bad * VOP_READ from the buffer cache to prevent cache 1717 1.54 bad * incoherencies. Also, be careful to write dirty 1718 1.54 bad * buffers back to stable storage. 1719 1.54 bad */ 1720 1.54 bad error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred, 1721 1.124 christos curlwp, 0, 0); 1722 1.54 bad } 1723 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 1724 1.5 cgd 1725 1.5 cgd free(tmpbuf, M_TEMP); 1726 1.197 dyoung return error; 1727 1.1 brezak } 1728 1.1 brezak 1729 1.1 brezak /* 1730 1.1 brezak * Set maxactive based on FS type 1731 1.1 brezak */ 1732 1.108 thorpej static void 1733 1.108 thorpej vndthrottle(struct vnd_softc *vnd, struct vnode *vp) 1734 1.1 brezak { 1735 1.5 cgd 1736 1.208 pooka if (vp->v_tag == VT_NFS) 1737 1.17 cgd vnd->sc_maxactive = 2; 1738 1.1 brezak else 1739 1.17 cgd vnd->sc_maxactive = 8; 1740 1.1 brezak 1741 1.17 cgd if (vnd->sc_maxactive < 1) 1742 1.17 cgd vnd->sc_maxactive = 1; 1743 1.1 brezak } 1744 1.1 brezak 1745 1.95 drochner #if 0 1746 1.108 thorpej static void 1747 1.108 thorpej vndshutdown(void) 1748 1.1 brezak { 1749 1.65 augustss struct vnd_softc *vnd; 1750 1.1 brezak 1751 1.17 cgd for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++) 1752 1.17 cgd if (vnd->sc_flags & VNF_INITED) 1753 1.17 cgd vndclear(vnd); 1754 1.1 brezak } 1755 1.95 drochner #endif 1756 1.1 brezak 1757 1.108 thorpej static void 1758 1.108 thorpej vndclear(struct vnd_softc *vnd, int myminor) 1759 1.1 brezak { 1760 1.65 augustss struct vnode *vp = vnd->sc_vp; 1761 1.94 yamt int fflags = FREAD; 1762 1.95 drochner int bmaj, cmaj, i, mn; 1763 1.113 yamt int s; 1764 1.1 brezak 1765 1.1 brezak #ifdef DEBUG 1766 1.17 cgd if (vnddebug & VDB_FOLLOW) 1767 1.30 christos printf("vndclear(%p): vp %p\n", vnd, vp); 1768 1.1 brezak #endif 1769 1.95 drochner /* locate the major number */ 1770 1.95 drochner bmaj = bdevsw_lookup_major(&vnd_bdevsw); 1771 1.95 drochner cmaj = cdevsw_lookup_major(&vnd_cdevsw); 1772 1.95 drochner 1773 1.95 drochner /* Nuke the vnodes for any open instances */ 1774 1.95 drochner for (i = 0; i < MAXPARTITIONS; i++) { 1775 1.176 cube mn = DISKMINOR(device_unit(vnd->sc_dev), i); 1776 1.286 riastrad if (mn != myminor) { /* XXX avoid to kill own vnode */ 1777 1.286 riastrad vdevgone(bmaj, mn, mn, VBLK); 1778 1.95 drochner vdevgone(cmaj, mn, mn, VCHR); 1779 1.286 riastrad } 1780 1.95 drochner } 1781 1.95 drochner 1782 1.94 yamt if ((vnd->sc_flags & VNF_READONLY) == 0) 1783 1.94 yamt fflags |= FWRITE; 1784 1.112 bouyer 1785 1.113 yamt s = splbio(); 1786 1.123 yamt bufq_drain(vnd->sc_tab); 1787 1.113 yamt splx(s); 1788 1.113 yamt 1789 1.112 bouyer vnd->sc_flags |= VNF_VUNCONF; 1790 1.112 bouyer wakeup(&vnd->sc_tab); 1791 1.112 bouyer while (vnd->sc_flags & VNF_KTHREAD) 1792 1.112 bouyer tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0); 1793 1.112 bouyer 1794 1.115 hubertf #ifdef VND_COMPRESSION 1795 1.116 christos /* free the compressed file buffers */ 1796 1.198 dyoung if (vnd->sc_flags & VNF_COMP) { 1797 1.198 dyoung if (vnd->sc_comp_offsets) { 1798 1.116 christos free(vnd->sc_comp_offsets, M_DEVBUF); 1799 1.116 christos vnd->sc_comp_offsets = NULL; 1800 1.116 christos } 1801 1.198 dyoung if (vnd->sc_comp_buff) { 1802 1.116 christos free(vnd->sc_comp_buff, M_DEVBUF); 1803 1.116 christos vnd->sc_comp_buff = NULL; 1804 1.116 christos } 1805 1.198 dyoung if (vnd->sc_comp_decombuf) { 1806 1.116 christos free(vnd->sc_comp_decombuf, M_DEVBUF); 1807 1.116 christos vnd->sc_comp_decombuf = NULL; 1808 1.116 christos } 1809 1.116 christos } 1810 1.115 hubertf #endif /* VND_COMPRESSION */ 1811 1.112 bouyer vnd->sc_flags &= 1812 1.242 mlelstv ~(VNF_INITED | VNF_READONLY | VNF_KLABEL | VNF_VLABEL 1813 1.203 dyoung | VNF_VUNCONF | VNF_COMP | VNF_CLEARING); 1814 1.197 dyoung if (vp == NULL) 1815 1.112 bouyer panic("vndclear: null vp"); 1816 1.177 ad (void) vn_close(vp, fflags, vnd->sc_cred); 1817 1.147 elad kauth_cred_free(vnd->sc_cred); 1818 1.197 dyoung vnd->sc_vp = NULL; 1819 1.197 dyoung vnd->sc_cred = NULL; 1820 1.17 cgd vnd->sc_size = 0; 1821 1.1 brezak } 1822 1.1 brezak 1823 1.108 thorpej static int 1824 1.108 thorpej vndsize(dev_t dev) 1825 1.1 brezak { 1826 1.41 thorpej struct vnd_softc *sc; 1827 1.41 thorpej struct disklabel *lp; 1828 1.41 thorpej int part, unit, omask; 1829 1.41 thorpej int size; 1830 1.41 thorpej 1831 1.41 thorpej unit = vndunit(dev); 1832 1.182 cegger sc = device_lookup_private(&vnd_cd, unit); 1833 1.131 cube if (sc == NULL) 1834 1.131 cube return -1; 1835 1.41 thorpej 1836 1.41 thorpej if ((sc->sc_flags & VNF_INITED) == 0) 1837 1.197 dyoung return -1; 1838 1.41 thorpej 1839 1.41 thorpej part = DISKPART(dev); 1840 1.41 thorpej omask = sc->sc_dkdev.dk_openmask & (1 << part); 1841 1.41 thorpej lp = sc->sc_dkdev.dk_label; 1842 1.41 thorpej 1843 1.124 christos if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1844 1.197 dyoung return -1; 1845 1.41 thorpej 1846 1.41 thorpej if (lp->d_partitions[part].p_fstype != FS_SWAP) 1847 1.41 thorpej size = -1; 1848 1.41 thorpej else 1849 1.41 thorpej size = lp->d_partitions[part].p_size * 1850 1.41 thorpej (lp->d_secsize / DEV_BSIZE); 1851 1.41 thorpej 1852 1.124 christos if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1853 1.197 dyoung return -1; 1854 1.1 brezak 1855 1.197 dyoung return size; 1856 1.1 brezak } 1857 1.1 brezak 1858 1.108 thorpej static int 1859 1.163 christos vnddump(dev_t dev, daddr_t blkno, void *va, 1860 1.160 christos size_t size) 1861 1.1 brezak { 1862 1.16 cgd 1863 1.19 cgd /* Not implemented. */ 1864 1.19 cgd return ENXIO; 1865 1.41 thorpej } 1866 1.41 thorpej 1867 1.108 thorpej static void 1868 1.108 thorpej vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp) 1869 1.41 thorpej { 1870 1.41 thorpej struct vndgeom *vng = &sc->sc_geom; 1871 1.41 thorpej struct partition *pp; 1872 1.235 mlelstv unsigned spb; 1873 1.41 thorpej 1874 1.72 thorpej memset(lp, 0, sizeof(*lp)); 1875 1.41 thorpej 1876 1.235 mlelstv spb = vng->vng_secsize / DEV_BSIZE; 1877 1.235 mlelstv if (sc->sc_size / spb > UINT32_MAX) 1878 1.233 mlelstv lp->d_secperunit = UINT32_MAX; 1879 1.233 mlelstv else 1880 1.235 mlelstv lp->d_secperunit = sc->sc_size / spb; 1881 1.41 thorpej lp->d_secsize = vng->vng_secsize; 1882 1.41 thorpej lp->d_nsectors = vng->vng_nsectors; 1883 1.41 thorpej lp->d_ntracks = vng->vng_ntracks; 1884 1.41 thorpej lp->d_ncylinders = vng->vng_ncylinders; 1885 1.41 thorpej lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1886 1.41 thorpej 1887 1.41 thorpej strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename)); 1888 1.239 christos lp->d_type = DKTYPE_VND; 1889 1.41 thorpej strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1890 1.41 thorpej lp->d_rpm = 3600; 1891 1.41 thorpej lp->d_interleave = 1; 1892 1.41 thorpej lp->d_flags = 0; 1893 1.41 thorpej 1894 1.41 thorpej pp = &lp->d_partitions[RAW_PART]; 1895 1.41 thorpej pp->p_offset = 0; 1896 1.41 thorpej pp->p_size = lp->d_secperunit; 1897 1.41 thorpej pp->p_fstype = FS_UNUSED; 1898 1.41 thorpej lp->d_npartitions = RAW_PART + 1; 1899 1.41 thorpej 1900 1.41 thorpej lp->d_magic = DISKMAGIC; 1901 1.41 thorpej lp->d_magic2 = DISKMAGIC; 1902 1.41 thorpej lp->d_checksum = dkcksum(lp); 1903 1.47 thorpej } 1904 1.47 thorpej 1905 1.47 thorpej /* 1906 1.47 thorpej * Read the disklabel from a vnd. If one is not present, create a fake one. 1907 1.47 thorpej */ 1908 1.108 thorpej static void 1909 1.131 cube vndgetdisklabel(dev_t dev, struct vnd_softc *sc) 1910 1.47 thorpej { 1911 1.97 dsl const char *errstring; 1912 1.47 thorpej struct disklabel *lp = sc->sc_dkdev.dk_label; 1913 1.47 thorpej struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel; 1914 1.47 thorpej int i; 1915 1.47 thorpej 1916 1.72 thorpej memset(clp, 0, sizeof(*clp)); 1917 1.47 thorpej 1918 1.47 thorpej vndgetdefaultlabel(sc, lp); 1919 1.41 thorpej 1920 1.41 thorpej /* 1921 1.41 thorpej * Call the generic disklabel extraction routine. 1922 1.41 thorpej */ 1923 1.41 thorpej errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp); 1924 1.41 thorpej if (errstring) { 1925 1.41 thorpej /* 1926 1.41 thorpej * Lack of disklabel is common, but we print the warning 1927 1.41 thorpej * anyway, since it might contain other useful information. 1928 1.41 thorpej */ 1929 1.176 cube aprint_normal_dev(sc->sc_dev, "%s\n", errstring); 1930 1.41 thorpej 1931 1.41 thorpej /* 1932 1.41 thorpej * For historical reasons, if there's no disklabel 1933 1.41 thorpej * present, all partitions must be FS_BSDFFS and 1934 1.41 thorpej * occupy the entire disk. 1935 1.41 thorpej */ 1936 1.41 thorpej for (i = 0; i < MAXPARTITIONS; i++) { 1937 1.52 enami /* 1938 1.52 enami * Don't wipe out port specific hack (such as 1939 1.52 enami * dos partition hack of i386 port). 1940 1.52 enami */ 1941 1.96 dsl if (lp->d_partitions[i].p_size != 0) 1942 1.52 enami continue; 1943 1.52 enami 1944 1.41 thorpej lp->d_partitions[i].p_size = lp->d_secperunit; 1945 1.41 thorpej lp->d_partitions[i].p_offset = 0; 1946 1.41 thorpej lp->d_partitions[i].p_fstype = FS_BSDFFS; 1947 1.41 thorpej } 1948 1.41 thorpej 1949 1.41 thorpej strncpy(lp->d_packname, "default label", 1950 1.41 thorpej sizeof(lp->d_packname)); 1951 1.47 thorpej 1952 1.96 dsl lp->d_npartitions = MAXPARTITIONS; 1953 1.47 thorpej lp->d_checksum = dkcksum(lp); 1954 1.41 thorpej } 1955 1.1 brezak } 1956 1.22 thorpej 1957 1.22 thorpej /* 1958 1.22 thorpej * Wait interruptibly for an exclusive lock. 1959 1.22 thorpej * 1960 1.22 thorpej * XXX 1961 1.22 thorpej * Several drivers do this; it should be abstracted and made MP-safe. 1962 1.22 thorpej */ 1963 1.22 thorpej static int 1964 1.108 thorpej vndlock(struct vnd_softc *sc) 1965 1.22 thorpej { 1966 1.22 thorpej int error; 1967 1.22 thorpej 1968 1.22 thorpej while ((sc->sc_flags & VNF_LOCKED) != 0) { 1969 1.22 thorpej sc->sc_flags |= VNF_WANTED; 1970 1.22 thorpej if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0) 1971 1.197 dyoung return error; 1972 1.22 thorpej } 1973 1.22 thorpej sc->sc_flags |= VNF_LOCKED; 1974 1.197 dyoung return 0; 1975 1.22 thorpej } 1976 1.22 thorpej 1977 1.22 thorpej /* 1978 1.22 thorpej * Unlock and wake up any waiters. 1979 1.22 thorpej */ 1980 1.22 thorpej static void 1981 1.108 thorpej vndunlock(struct vnd_softc *sc) 1982 1.22 thorpej { 1983 1.22 thorpej 1984 1.22 thorpej sc->sc_flags &= ~VNF_LOCKED; 1985 1.22 thorpej if ((sc->sc_flags & VNF_WANTED) != 0) { 1986 1.22 thorpej sc->sc_flags &= ~VNF_WANTED; 1987 1.22 thorpej wakeup(sc); 1988 1.22 thorpej } 1989 1.22 thorpej } 1990 1.115 hubertf 1991 1.115 hubertf #ifdef VND_COMPRESSION 1992 1.115 hubertf /* compressed file read */ 1993 1.115 hubertf static void 1994 1.116 christos compstrategy(struct buf *bp, off_t bn) 1995 1.116 christos { 1996 1.116 christos int error; 1997 1.116 christos int unit = vndunit(bp->b_dev); 1998 1.131 cube struct vnd_softc *vnd = 1999 1.182 cegger device_lookup_private(&vnd_cd, unit); 2000 1.116 christos u_int32_t comp_block; 2001 1.116 christos struct uio auio; 2002 1.163 christos char *addr; 2003 1.116 christos int s; 2004 1.116 christos 2005 1.116 christos /* set up constants for data move */ 2006 1.116 christos auio.uio_rw = UIO_READ; 2007 1.141 yamt UIO_SETUP_SYSSPACE(&auio); 2008 1.116 christos 2009 1.116 christos /* read, and transfer the data */ 2010 1.116 christos addr = bp->b_data; 2011 1.165 yamt bp->b_resid = bp->b_bcount; 2012 1.116 christos s = splbio(); 2013 1.116 christos while (bp->b_resid > 0) { 2014 1.116 christos unsigned length; 2015 1.116 christos size_t length_in_buffer; 2016 1.116 christos u_int32_t offset_in_buffer; 2017 1.116 christos struct iovec aiov; 2018 1.116 christos 2019 1.116 christos /* calculate the compressed block number */ 2020 1.116 christos comp_block = bn / (off_t)vnd->sc_comp_blksz; 2021 1.116 christos 2022 1.116 christos /* check for good block number */ 2023 1.116 christos if (comp_block >= vnd->sc_comp_numoffs) { 2024 1.116 christos bp->b_error = EINVAL; 2025 1.116 christos splx(s); 2026 1.116 christos return; 2027 1.116 christos } 2028 1.116 christos 2029 1.116 christos /* read in the compressed block, if not in buffer */ 2030 1.116 christos if (comp_block != vnd->sc_comp_buffblk) { 2031 1.116 christos length = vnd->sc_comp_offsets[comp_block + 1] - 2032 1.116 christos vnd->sc_comp_offsets[comp_block]; 2033 1.116 christos vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 2034 1.116 christos error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff, 2035 1.116 christos length, vnd->sc_comp_offsets[comp_block], 2036 1.187 ad UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred, 2037 1.187 ad NULL, NULL); 2038 1.116 christos if (error) { 2039 1.116 christos bp->b_error = error; 2040 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 2041 1.116 christos splx(s); 2042 1.116 christos return; 2043 1.116 christos } 2044 1.116 christos /* uncompress the buffer */ 2045 1.116 christos vnd->sc_comp_stream.next_in = vnd->sc_comp_buff; 2046 1.116 christos vnd->sc_comp_stream.avail_in = length; 2047 1.116 christos vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf; 2048 1.116 christos vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz; 2049 1.116 christos inflateReset(&vnd->sc_comp_stream); 2050 1.116 christos error = inflate(&vnd->sc_comp_stream, Z_FINISH); 2051 1.116 christos if (error != Z_STREAM_END) { 2052 1.116 christos if (vnd->sc_comp_stream.msg) 2053 1.176 cube aprint_normal_dev(vnd->sc_dev, 2054 1.176 cube "compressed file, %s\n", 2055 1.116 christos vnd->sc_comp_stream.msg); 2056 1.116 christos bp->b_error = EBADMSG; 2057 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 2058 1.116 christos splx(s); 2059 1.116 christos return; 2060 1.116 christos } 2061 1.116 christos vnd->sc_comp_buffblk = comp_block; 2062 1.209 hannken VOP_UNLOCK(vnd->sc_vp); 2063 1.116 christos } 2064 1.116 christos 2065 1.116 christos /* transfer the usable uncompressed data */ 2066 1.116 christos offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz; 2067 1.116 christos length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer; 2068 1.116 christos if (length_in_buffer > bp->b_resid) 2069 1.116 christos length_in_buffer = bp->b_resid; 2070 1.116 christos auio.uio_iov = &aiov; 2071 1.116 christos auio.uio_iovcnt = 1; 2072 1.116 christos aiov.iov_base = addr; 2073 1.116 christos aiov.iov_len = length_in_buffer; 2074 1.116 christos auio.uio_resid = aiov.iov_len; 2075 1.116 christos auio.uio_offset = 0; 2076 1.116 christos error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer, 2077 1.116 christos length_in_buffer, &auio); 2078 1.116 christos if (error) { 2079 1.116 christos bp->b_error = error; 2080 1.116 christos splx(s); 2081 1.116 christos return; 2082 1.116 christos } 2083 1.116 christos 2084 1.116 christos bn += length_in_buffer; 2085 1.116 christos addr += length_in_buffer; 2086 1.116 christos bp->b_resid -= length_in_buffer; 2087 1.116 christos } 2088 1.116 christos splx(s); 2089 1.115 hubertf } 2090 1.115 hubertf 2091 1.115 hubertf /* compression memory allocation routines */ 2092 1.115 hubertf static void * 2093 1.160 christos vnd_alloc(void *aux, u_int items, u_int siz) 2094 1.116 christos { 2095 1.117 christos return malloc(items * siz, M_TEMP, M_NOWAIT); 2096 1.115 hubertf } 2097 1.115 hubertf 2098 1.115 hubertf static void 2099 1.160 christos vnd_free(void *aux, void *ptr) 2100 1.115 hubertf { 2101 1.116 christos free(ptr, M_TEMP); 2102 1.115 hubertf } 2103 1.115 hubertf #endif /* VND_COMPRESSION */ 2104 1.174 riz 2105 1.174 riz static void 2106 1.222 christos vnd_set_geometry(struct vnd_softc *vnd) 2107 1.174 riz { 2108 1.222 christos struct disk_geom *dg = &vnd->sc_dkdev.dk_geom; 2109 1.279 mlelstv unsigned spb; 2110 1.174 riz 2111 1.222 christos memset(dg, 0, sizeof(*dg)); 2112 1.174 riz 2113 1.279 mlelstv spb = vnd->sc_geom.vng_secsize / DEV_BSIZE; 2114 1.279 mlelstv dg->dg_secperunit = vnd->sc_size / spb; 2115 1.222 christos dg->dg_secsize = vnd->sc_geom.vng_secsize; 2116 1.222 christos dg->dg_nsectors = vnd->sc_geom.vng_nsectors; 2117 1.222 christos dg->dg_ntracks = vnd->sc_geom.vng_ntracks; 2118 1.222 christos dg->dg_ncylinders = vnd->sc_geom.vng_ncylinders; 2119 1.174 riz 2120 1.229 prlw1 #ifdef DEBUG 2121 1.229 prlw1 if (vnddebug & VDB_LABEL) { 2122 1.229 prlw1 printf("dg->dg_secperunit: %" PRId64 "\n", dg->dg_secperunit); 2123 1.229 prlw1 printf("dg->dg_ncylinders: %u\n", dg->dg_ncylinders); 2124 1.229 prlw1 } 2125 1.229 prlw1 #endif 2126 1.222 christos disk_set_info(vnd->sc_dev, &vnd->sc_dkdev, NULL); 2127 1.174 riz } 2128 1.193 haad 2129 1.230 pooka #ifdef VND_COMPRESSION 2130 1.230 pooka #define VND_DEPENDS "zlib" 2131 1.230 pooka #else 2132 1.230 pooka #define VND_DEPENDS NULL 2133 1.230 pooka #endif 2134 1.230 pooka 2135 1.230 pooka MODULE(MODULE_CLASS_DRIVER, vnd, VND_DEPENDS); 2136 1.257 pgoyette 2137 1.257 pgoyette #ifdef _MODULE 2138 1.257 pgoyette int vnd_bmajor = -1, vnd_cmajor = -1; 2139 1.257 pgoyette 2140 1.193 haad CFDRIVER_DECL(vnd, DV_DISK, NULL); 2141 1.257 pgoyette #endif 2142 1.193 haad 2143 1.193 haad static int 2144 1.193 haad vnd_modcmd(modcmd_t cmd, void *arg) 2145 1.193 haad { 2146 1.257 pgoyette int error = 0; 2147 1.244 prlw1 2148 1.193 haad switch (cmd) { 2149 1.193 haad case MODULE_CMD_INIT: 2150 1.257 pgoyette #ifdef _MODULE 2151 1.285 pgoyette /* 2152 1.285 pgoyette * Attach the {b,c}devsw's 2153 1.285 pgoyette */ 2154 1.285 pgoyette error = devsw_attach("vnd", &vnd_bdevsw, &vnd_bmajor, 2155 1.285 pgoyette &vnd_cdevsw, &vnd_cmajor); 2156 1.285 pgoyette if (error) { 2157 1.285 pgoyette #ifdef DIAGNOSTIC 2158 1.285 pgoyette aprint_error("%s: unable to attach %s devsw, " 2159 1.285 pgoyette "error %d", __func__, vnd_cd.cd_name, error); 2160 1.285 pgoyette #endif 2161 1.285 pgoyette break; 2162 1.285 pgoyette } 2163 1.285 pgoyette 2164 1.193 haad error = config_cfdriver_attach(&vnd_cd); 2165 1.285 pgoyette if (error) { 2166 1.285 pgoyette devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2167 1.193 haad break; 2168 1.285 pgoyette } 2169 1.193 haad 2170 1.193 haad error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 2171 1.193 haad if (error) { 2172 1.193 haad config_cfdriver_detach(&vnd_cd); 2173 1.285 pgoyette devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2174 1.259 pgoyette #ifdef DIAGNOSTIC 2175 1.257 pgoyette aprint_error("%s: unable to register cfattach for \n" 2176 1.257 pgoyette "%s, error %d", __func__, vnd_cd.cd_name, error); 2177 1.259 pgoyette #endif 2178 1.193 haad break; 2179 1.193 haad } 2180 1.257 pgoyette #endif 2181 1.193 haad break; 2182 1.193 haad 2183 1.193 haad case MODULE_CMD_FINI: 2184 1.257 pgoyette #ifdef _MODULE 2185 1.257 pgoyette /* 2186 1.285 pgoyette * Remove device from autoconf database 2187 1.257 pgoyette */ 2188 1.193 haad error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2189 1.257 pgoyette if (error) { 2190 1.259 pgoyette #ifdef DIAGNOSTIC 2191 1.257 pgoyette aprint_error("%s: failed to detach %s cfattach, " 2192 1.257 pgoyette "error %d\n", __func__, vnd_cd.cd_name, error); 2193 1.259 pgoyette #endif 2194 1.257 pgoyette break; 2195 1.257 pgoyette } 2196 1.257 pgoyette error = config_cfdriver_detach(&vnd_cd); 2197 1.257 pgoyette if (error) { 2198 1.258 pgoyette (void)config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 2199 1.259 pgoyette #ifdef DIAGNOSTIC 2200 1.257 pgoyette aprint_error("%s: failed to detach %s cfdriver, " 2201 1.257 pgoyette "error %d\n", __func__, vnd_cd.cd_name, error); 2202 1.257 pgoyette break; 2203 1.259 pgoyette #endif 2204 1.257 pgoyette } 2205 1.285 pgoyette /* 2206 1.285 pgoyette * Remove {b,c}devsw's 2207 1.285 pgoyette */ 2208 1.285 pgoyette devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2209 1.285 pgoyette 2210 1.257 pgoyette #endif 2211 1.193 haad break; 2212 1.193 haad 2213 1.193 haad case MODULE_CMD_STAT: 2214 1.193 haad return ENOTTY; 2215 1.193 haad 2216 1.193 haad default: 2217 1.193 haad return ENOTTY; 2218 1.193 haad } 2219 1.193 haad 2220 1.193 haad return error; 2221 1.193 haad } 2222