1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: vn.c 1.8 92/12/20$ 13 * 14 * @(#)vn.c 8.3 (Berkeley) 11/16/93 15 */ 16 17 /* 18 * Vnode disk driver. 19 * 20 * Block/character interface to a vnode. Allows one to treat a file 21 * as a disk (e.g. build a filesystem in it, mount it, etc.). 22 * 23 * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode 24 * instead of a simple VOP_RDWR. We do this to avoid distorting the 25 * local buffer cache. 26 * 27 * NOTE 2: There is a security issue involved with this driver. 28 * Once mounted all access to the contents of the "mapped" file via 29 * the special file is controlled by the permissions on the special 30 * file, the protection of the mapped file is ignored (effectively, 31 * by using root credentials in all transactions). 32 * 33 * NOTE 3: Doesn't interact with leases, should it? 34 */ 35 #include "vn.h" 36 #if NVN > 0 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/namei.h> 41 #include <sys/proc.h> 42 #include <sys/errno.h> 43 #include <sys/dkstat.h> 44 #include <sys/buf.h> 45 #include <sys/malloc.h> 46 #include <sys/ioctl.h> 47 #include <sys/mount.h> 48 #include <sys/vnode.h> 49 #include <sys/file.h> 50 #include <sys/uio.h> 51 52 #include <miscfs/specfs/specdev.h> 53 54 #include <dev/vnioctl.h> 55 56 #ifdef DEBUG 57 int vndebug = 0x00; 58 #define VDB_FOLLOW 0x01 59 #define VDB_INIT 0x02 60 #define VDB_IO 0x04 61 #endif 62 63 #define b_cylin b_resid 64 65 #define vnunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ 66 67 #define getvnbuf() \ 68 ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) 69 #define putvnbuf(bp) \ 70 free((caddr_t)(bp), M_DEVBUF) 71 72 struct vn_softc { 73 int sc_flags; /* flags */ 74 size_t sc_size; /* size of vn */ 75 struct vnode *sc_vp; /* vnode */ 76 struct ucred *sc_cred; /* credentials */ 77 int sc_maxactive; /* max # of active requests */ 78 struct buf sc_tab; /* transfer queue */ 79 }; 80 81 /* sc_flags */ 82 #define VNF_ALIVE 0x01 83 #define VNF_INITED 0x02 84 85 #if 0 /* if you need static allocation */ 86 struct vn_softc vn_softc[NVN]; 87 int numvnd = NVN; 88 #else 89 struct vn_softc *vn_softc; 90 int numvnd; 91 #endif 92 93 void 94 vnattach(num) 95 int num; 96 { 97 char *mem; 98 register u_long size; 99 100 if (num <= 0) 101 return; 102 size = num * sizeof(struct vn_softc); 103 mem = malloc(size, M_DEVBUF, M_NOWAIT); 104 if (mem == NULL) { 105 printf("WARNING: no memory for vnode disks\n"); 106 return; 107 } 108 bzero(mem, size); 109 vn_softc = (struct vn_softc *)mem; 110 numvnd = num; 111 } 112 113 int 114 vnopen(dev, flags, mode, p) 115 dev_t dev; 116 int flags, mode; 117 struct proc *p; 118 { 119 int unit = vnunit(dev); 120 121 #ifdef DEBUG 122 if (vndebug & VDB_FOLLOW) 123 printf("vnopen(%x, %x, %x, %x)\n", dev, flags, mode, p); 124 #endif 125 if (unit >= numvnd) 126 return(ENXIO); 127 return(0); 128 } 129 130 /* 131 * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY. 132 * Note that this driver can only be used for swapping over NFS on the hp 133 * since nfs_strategy on the vax cannot handle u-areas and page tables. 134 */ 135 vnstrategy(bp) 136 register struct buf *bp; 137 { 138 int unit = vnunit(bp->b_dev); 139 register struct vn_softc *vn = &vn_softc[unit]; 140 register struct buf *nbp; 141 register int bn, bsize, resid; 142 register caddr_t addr; 143 int sz, flags; 144 extern void vniodone(); 145 146 #ifdef DEBUG 147 if (vndebug & VDB_FOLLOW) 148 printf("vnstrategy(%x): unit %d\n", bp, unit); 149 #endif 150 if ((vn->sc_flags & VNF_INITED) == 0) { 151 bp->b_error = ENXIO; 152 bp->b_flags |= B_ERROR; 153 biodone(bp); 154 return; 155 } 156 bn = bp->b_blkno; 157 sz = howmany(bp->b_bcount, DEV_BSIZE); 158 bp->b_resid = bp->b_bcount; 159 if (bn < 0 || bn + sz > vn->sc_size) { 160 if (bn != vn->sc_size) { 161 bp->b_error = EINVAL; 162 bp->b_flags |= B_ERROR; 163 } 164 biodone(bp); 165 return; 166 } 167 bn = dbtob(bn); 168 bsize = vn->sc_vp->v_mount->mnt_stat.f_iosize; 169 addr = bp->b_data; 170 flags = bp->b_flags | B_CALL; 171 for (resid = bp->b_resid; resid; resid -= sz) { 172 struct vnode *vp; 173 daddr_t nbn; 174 int off, s; 175 176 nbp = getvnbuf(); 177 off = bn % bsize; 178 sz = min(bsize - off, resid); 179 (void) VOP_BMAP(vn->sc_vp, bn / bsize, &vp, &nbn, NULL); 180 #ifdef DEBUG 181 if (vndebug & VDB_IO) 182 printf("vnstrategy: vp %x/%x bn %x/%x\n", 183 vn->sc_vp, vp, bn, nbn); 184 #endif 185 nbp->b_flags = flags; 186 nbp->b_bcount = sz; 187 nbp->b_bufsize = bp->b_bufsize; 188 nbp->b_error = 0; 189 if (vp->v_type == VBLK || vp->v_type == VCHR) 190 nbp->b_dev = vp->v_rdev; 191 else 192 nbp->b_dev = NODEV; 193 nbp->b_data = addr; 194 nbp->b_blkno = nbn + btodb(off); 195 nbp->b_proc = bp->b_proc; 196 nbp->b_iodone = vniodone; 197 nbp->b_vp = vp; 198 nbp->b_pfcent = (int) bp; /* XXX */ 199 nbp->b_rcred = vn->sc_cred; /* XXX crdup? */ 200 nbp->b_wcred = vn->sc_cred; /* XXX crdup? */ 201 nbp->b_dirtyoff = bp->b_dirtyoff; 202 nbp->b_dirtyend = bp->b_dirtyend; 203 nbp->b_validoff = bp->b_validoff; 204 nbp->b_validend = bp->b_validend; 205 /* 206 * There is a hole in the file...punt. 207 * Note that we deal with this after the nbp allocation. 208 * This ensures that we properly clean up any operations 209 * that we have already fired off. 210 * 211 * XXX we could deal with this but it would be 212 * a hassle (in the write case). 213 */ 214 if ((long)nbn == -1) { 215 nbp->b_error = EIO; 216 nbp->b_flags |= B_ERROR; 217 bp->b_resid -= (resid - sz); 218 biodone(nbp); 219 return; 220 } 221 /* 222 * Just sort by block number 223 */ 224 nbp->b_cylin = nbp->b_blkno; 225 s = splbio(); 226 disksort(&vn->sc_tab, nbp); 227 if (vn->sc_tab.b_active < vn->sc_maxactive) { 228 vn->sc_tab.b_active++; 229 vnstart(vn); 230 } 231 splx(s); 232 bn += sz; 233 addr += sz; 234 } 235 } 236 237 /* 238 * Feed requests sequentially. 239 * We do it this way to keep from flooding NFS servers if we are connected 240 * to an NFS file. This places the burden on the client rather than the 241 * server. 242 */ 243 vnstart(vn) 244 register struct vn_softc *vn; 245 { 246 register struct buf *bp; 247 248 /* 249 * Dequeue now since lower level strategy routine might 250 * queue using same links 251 */ 252 bp = vn->sc_tab.b_actf; 253 vn->sc_tab.b_actf = bp->b_actf; 254 #ifdef DEBUG 255 if (vndebug & VDB_IO) 256 printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n", 257 vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_data, 258 bp->b_bcount); 259 #endif 260 if ((bp->b_flags & B_READ) == 0) 261 bp->b_vp->v_numoutput++; 262 VOP_STRATEGY(bp); 263 } 264 265 void 266 vniodone(bp) 267 register struct buf *bp; 268 { 269 register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */ 270 register struct vn_softc *vn = &vn_softc[vnunit(pbp->b_dev)]; 271 int s; 272 273 s = splbio(); 274 #ifdef DEBUG 275 if (vndebug & VDB_IO) 276 printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n", 277 vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_data, 278 bp->b_bcount); 279 #endif 280 if (bp->b_error) { 281 #ifdef DEBUG 282 if (vndebug & VDB_IO) 283 printf("vniodone: bp %x error %d\n", bp, bp->b_error); 284 #endif 285 pbp->b_flags |= B_ERROR; 286 pbp->b_error = biowait(bp); 287 } 288 pbp->b_resid -= bp->b_bcount; 289 putvnbuf(bp); 290 if (pbp->b_resid == 0) { 291 #ifdef DEBUG 292 if (vndebug & VDB_IO) 293 printf("vniodone: pbp %x iodone\n", pbp); 294 #endif 295 biodone(pbp); 296 } 297 if (vn->sc_tab.b_actf) 298 vnstart(vn); 299 else 300 vn->sc_tab.b_active--; 301 splx(s); 302 } 303 304 vnread(dev, uio, flags, p) 305 dev_t dev; 306 struct uio *uio; 307 int flags; 308 struct proc *p; 309 { 310 311 #ifdef DEBUG 312 if (vndebug & VDB_FOLLOW) 313 printf("vnread(%x, %x, %x, %x)\n", dev, uio, flags, p); 314 #endif 315 return(physio(vnstrategy, NULL, dev, B_READ, minphys, uio)); 316 } 317 318 vnwrite(dev, uio, flags, p) 319 dev_t dev; 320 struct uio *uio; 321 int flags; 322 struct proc *p; 323 { 324 325 #ifdef DEBUG 326 if (vndebug & VDB_FOLLOW) 327 printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p); 328 #endif 329 return(physio(vnstrategy, NULL, dev, B_WRITE, minphys, uio)); 330 } 331 332 /* ARGSUSED */ 333 vnioctl(dev, cmd, data, flag, p) 334 dev_t dev; 335 u_long cmd; 336 caddr_t data; 337 int flag; 338 struct proc *p; 339 { 340 int unit = vnunit(dev); 341 register struct vn_softc *vn; 342 struct vn_ioctl *vio; 343 struct vattr vattr; 344 struct nameidata nd; 345 int error; 346 347 #ifdef DEBUG 348 if (vndebug & VDB_FOLLOW) 349 printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n", 350 dev, cmd, data, flag, p, unit); 351 #endif 352 error = suser(p->p_ucred, &p->p_acflag); 353 if (error) 354 return (error); 355 if (unit >= numvnd) 356 return (ENXIO); 357 358 vn = &vn_softc[unit]; 359 vio = (struct vn_ioctl *)data; 360 switch (cmd) { 361 362 case VNIOCSET: 363 if (vn->sc_flags & VNF_INITED) 364 return(EBUSY); 365 /* 366 * Always open for read and write. 367 * This is probably bogus, but it lets vn_open() 368 * weed out directories, sockets, etc. so we don't 369 * have to worry about them. 370 */ 371 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p); 372 if (error = vn_open(&nd, FREAD|FWRITE, 0)) 373 return(error); 374 if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) { 375 VOP_UNLOCK(nd.ni_vp); 376 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p); 377 return(error); 378 } 379 VOP_UNLOCK(nd.ni_vp); 380 vn->sc_vp = nd.ni_vp; 381 vn->sc_size = btodb(vattr.va_size); /* note truncation */ 382 if (error = vnsetcred(vn, p->p_ucred)) { 383 (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p); 384 return(error); 385 } 386 vnthrottle(vn, vn->sc_vp); 387 vio->vn_size = dbtob(vn->sc_size); 388 vn->sc_flags |= VNF_INITED; 389 #ifdef DEBUG 390 if (vndebug & VDB_INIT) 391 printf("vnioctl: SET vp %x size %x\n", 392 vn->sc_vp, vn->sc_size); 393 #endif 394 break; 395 396 case VNIOCCLR: 397 if ((vn->sc_flags & VNF_INITED) == 0) 398 return(ENXIO); 399 vnclear(vn); 400 #ifdef DEBUG 401 if (vndebug & VDB_INIT) 402 printf("vnioctl: CLRed\n"); 403 #endif 404 break; 405 406 default: 407 return(ENXIO); 408 } 409 return(0); 410 } 411 412 /* 413 * Duplicate the current processes' credentials. Since we are called only 414 * as the result of a SET ioctl and only root can do that, any future access 415 * to this "disk" is essentially as root. Note that credentials may change 416 * if some other uid can write directly to the mapped file (NFS). 417 */ 418 vnsetcred(vn, cred) 419 register struct vn_softc *vn; 420 struct ucred cred; 421 { 422 struct uio auio; 423 struct iovec aiov; 424 char tmpbuf[DEV_BSIZE]; 425 426 vn->sc_cred = crdup(cred); 427 /* XXX: Horrible kludge to establish credentials for NFS */ 428 aiov.iov_base = tmpbuf; 429 aiov.iov_len = min(DEV_BSIZE, dbtob(vn->sc_size)); 430 auio.uio_iov = &aiov; 431 auio.uio_iovcnt = 1; 432 auio.uio_offset = 0; 433 auio.uio_rw = UIO_READ; 434 auio.uio_segflg = UIO_SYSSPACE; 435 auio.uio_resid = aiov.iov_len; 436 return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred)); 437 } 438 439 /* 440 * Set maxactive based on FS type 441 */ 442 vnthrottle(vn, vp) 443 register struct vn_softc *vn; 444 struct vnode *vp; 445 { 446 extern int (**nfsv2_vnodeop_p)(); 447 448 if (vp->v_op == nfsv2_vnodeop_p) 449 vn->sc_maxactive = 2; 450 else 451 vn->sc_maxactive = 8; 452 453 if (vn->sc_maxactive < 1) 454 vn->sc_maxactive = 1; 455 } 456 457 vnshutdown() 458 { 459 register struct vn_softc *vn; 460 461 for (vn = &vn_softc[0]; vn < &vn_softc[numvnd]; vn++) 462 if (vn->sc_flags & VNF_INITED) 463 vnclear(vn); 464 } 465 466 vnclear(vn) 467 register struct vn_softc *vn; 468 { 469 register struct vnode *vp = vn->sc_vp; 470 struct proc *p = curproc; /* XXX */ 471 472 #ifdef DEBUG 473 if (vndebug & VDB_FOLLOW) 474 printf("vnclear(%x): vp %x\n", vp); 475 #endif 476 vn->sc_flags &= ~VNF_INITED; 477 if (vp == (struct vnode *)0) 478 panic("vnioctl: null vp"); 479 #if 0 480 /* XXX - this doesn't work right now */ 481 (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p); 482 #endif 483 (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p); 484 crfree(vn->sc_cred); 485 vn->sc_vp = (struct vnode *)0; 486 vn->sc_cred = (struct ucred *)0; 487 vn->sc_size = 0; 488 } 489 490 vnsize(dev) 491 dev_t dev; 492 { 493 int unit = vnunit(dev); 494 register struct vn_softc *vn = &vn_softc[unit]; 495 496 if (unit >= numvnd || (vn->sc_flags & VNF_INITED) == 0) 497 return(-1); 498 return(vn->sc_size); 499 } 500 501 vndump(dev) 502 { 503 return(ENXIO); 504 } 505 #endif 506