DEVFS - move devfs headers to sys/sys; fix consumers
[dragonfly.git] / sys / dev / disk / vn / vn.c
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  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * from: Utah Hdr: vn.c 1.13 94/04/02
39  *
40  *      from: @(#)vn.c  8.6 (Berkeley) 4/1/94
41  * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
42  * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.38 2008/07/01 02:02:53 dillon Exp $
43  */
44
45 /*
46  * Vnode disk driver.
47  *
48  * Block/character interface to a vnode.  Allows one to treat a file
49  * as a disk (e.g. build a filesystem in it, mount it, etc.).
50  *
51  * NOTE 1: There is a security issue involved with this driver.
52  * Once mounted all access to the contents of the "mapped" file via
53  * the special file is controlled by the permissions on the special
54  * file, the protection of the mapped file is ignored (effectively,
55  * by using root credentials in all transactions).
56  *
57  * NOTE 2: Doesn't interact with leases, should it?
58  */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
63 #include <sys/proc.h>
64 #include <sys/priv.h>
65 #include <sys/nlookup.h>
66 #include <sys/buf.h>
67 #include <sys/malloc.h>
68 #include <sys/mount.h>
69 #include <sys/vnode.h>
70 #include <sys/fcntl.h>
71 #include <sys/conf.h>
72 #include <sys/diskslice.h>
73 #include <sys/disk.h>
74 #include <sys/stat.h>
75 #include <sys/module.h>
76 #include <sys/vnioctl.h>
77
78 #include <vm/vm.h>
79 #include <vm/vm_object.h>
80 #include <vm/vm_page.h>
81 #include <vm/vm_pager.h>
82 #include <vm/vm_pageout.h>
83 #include <vm/swap_pager.h>
84 #include <vm/vm_extern.h>
85 #include <vm/vm_zone.h>
86 #include <sys/devfs.h>
87
88 static  d_ioctl_t       vnioctl;
89 static  d_open_t        vnopen;
90 static  d_close_t       vnclose;
91 static  d_psize_t       vnsize;
92 static  d_strategy_t    vnstrategy;
93 #if 0
94 static  d_clone_t       vnclone;
95 #endif
96 DEVFS_DECLARE_CLONE_BITMAP(vn);
97 #define VN_PREALLOCATED_UNITS   4
98
99 #define CDEV_MAJOR 43
100
101 #define VN_BSIZE_BEST   8192
102
103 /*
104  * dev_ops
105  *      D_DISK          we want to look like a disk
106  *      D_CANFREE       We support BUF_CMD_FREEBLKS
107  */
108
109 static struct dev_ops vn_ops = {
110         { "vn", CDEV_MAJOR, D_DISK | D_CANFREE },
111         .d_open =       vnopen,
112         .d_close =      vnclose,
113         .d_read =       physread,
114         .d_write =      physwrite,
115         .d_ioctl =      vnioctl,
116         .d_strategy =   vnstrategy,
117         .d_psize =      vnsize
118 };
119
120 struct vn_softc {
121         int             sc_unit;
122         int             sc_flags;       /* flags                        */
123         u_int64_t       sc_size;        /* size of vn, sc_secsize scale */
124         int             sc_secsize;     /* sector size                  */
125         struct disk     sc_disk;
126         struct vnode    *sc_vp;         /* vnode if not NULL            */
127         vm_object_t     sc_object;      /* backing object if not NULL   */
128         struct ucred    *sc_cred;       /* credentials                  */
129         int              sc_maxactive;  /* max # of active requests     */
130         struct buf       sc_tab;        /* transfer queue               */
131         u_long           sc_options;    /* options                      */
132         cdev_t           sc_devlist;    /* devices that refer to this unit */
133         SLIST_ENTRY(vn_softc) sc_list;
134 };
135
136 static SLIST_HEAD(, vn_softc) vn_list;
137
138 /* sc_flags */
139 #define VNF_INITED      0x01
140 #define VNF_READONLY    0x02
141
142 static u_long   vn_options;
143
144 #define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))
145 #define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt))
146
147 static int      vnsetcred (struct vn_softc *vn, struct ucred *cred);
148 static void     vnclear (struct vn_softc *vn);
149 static int      vnget (cdev_t dev, struct vn_softc *vn , struct vn_user *vnu);
150 static int      vn_modevent (module_t, int, void *);
151 static int      vniocattach_file (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred);
152 static int      vniocattach_swap (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred);
153
154 static  int
155 vnclose(struct dev_close_args *ap)
156 {
157 #if 0
158         cdev_t dev = ap->a_head.a_dev;
159         struct vn_softc *vn = dev->si_drv1;
160         if (dev->si_uminor >= VN_PREALLOCATED_UNITS) {
161                 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(vn), dev->si_uminor);
162                 destroy_dev(dev);
163         }
164 #endif
165         return (0);
166 }
167
168 static struct vn_softc *
169 vncreatevn(void)
170 {
171         struct vn_softc *vn;
172
173         vn = kmalloc(sizeof *vn, M_DEVBUF, M_WAITOK | M_ZERO);
174         return vn;
175 }
176
177 static void
178 vninitvn(struct vn_softc *vn, cdev_t dev)
179 {
180         int unit;
181
182         KKASSERT(vn != NULL);
183         KKASSERT(dev != NULL);
184         unit = dkunit(dev);
185
186         vn->sc_unit = unit;
187         dev->si_drv1 = vn;
188         vn->sc_devlist = dev;
189         if (vn->sc_devlist->si_drv1 == NULL) {
190                 reference_dev(vn->sc_devlist);
191                 vn->sc_devlist->si_drv1 = vn;
192                 vn->sc_devlist->si_drv2 = NULL;
193         }
194         if (vn->sc_devlist != dev) {
195                 dev->si_drv1 = vn;
196                 dev->si_drv2 = vn->sc_devlist;
197                 vn->sc_devlist = dev;
198                 reference_dev(dev);
199         }
200         SLIST_INSERT_HEAD(&vn_list, vn, sc_list);
201 }
202
203 /*
204  * Called only when si_drv1 is NULL.  Locate the associated vn node and
205  * attach the device to it.
206  */
207 static struct vn_softc *
208 vnfindvn(cdev_t dev)
209 {
210         int unit;
211         struct vn_softc *vn;
212
213         unit = dkunit(dev);
214         SLIST_FOREACH(vn, &vn_list, sc_list) {
215                 if (vn->sc_unit == unit) {
216                         dev->si_drv1 = vn;
217                         dev->si_drv2 = vn->sc_devlist;
218                         vn->sc_devlist = dev;
219                         reference_dev(dev);
220                         break;
221                 }
222         }
223
224         KKASSERT(vn != NULL);
225
226         return vn;
227 }
228
229 static  int
230 vnopen(struct dev_open_args *ap)
231 {
232         cdev_t dev = ap->a_head.a_dev;
233         struct vn_softc *vn;
234
235         /*
236          * Locate preexisting device
237          */
238
239         if ((vn = dev->si_drv1) == NULL)
240                 vn = vnfindvn(dev);
241
242         /*
243          * Update si_bsize fields for device.  This data will be overriden by
244          * the slice/parition code for vn accesses through partitions, and
245          * used directly if you open the 'whole disk' device.
246          *
247          * si_bsize_best must be reinitialized in case VN has been 
248          * reconfigured, plus make it at least VN_BSIZE_BEST for efficiency.
249          */
250         dev->si_bsize_phys = vn->sc_secsize;
251         dev->si_bsize_best = vn->sc_secsize;
252         if (dev->si_bsize_best < VN_BSIZE_BEST)
253                 dev->si_bsize_best = VN_BSIZE_BEST;
254
255         if ((ap->a_oflags & FWRITE) && (vn->sc_flags & VNF_READONLY))
256                 return (EACCES);
257
258         IFOPT(vn, VN_FOLLOW)
259                 kprintf("vnopen(%s, 0x%x, 0x%x)\n",
260                     devtoname(dev), ap->a_oflags, ap->a_devtype);
261
262         return(0);
263 }
264
265 /*
266  *      vnstrategy:
267  *
268  *      Run strategy routine for VN device.  We use VOP_READ/VOP_WRITE calls
269  *      for vnode-backed vn's, and the new vm_pager_strategy() call for
270  *      vm_object-backed vn's.
271  */
272 static int
273 vnstrategy(struct dev_strategy_args *ap)
274 {
275         cdev_t dev = ap->a_head.a_dev;
276         struct bio *bio = ap->a_bio;
277         struct buf *bp;
278         struct bio *nbio;
279         int unit;
280         struct vn_softc *vn;
281         int error;
282
283         unit = dkunit(dev);
284         if ((vn = dev->si_drv1) == NULL)
285                 vn = vnfindvn(dev);
286
287         bp = bio->bio_buf;
288
289         IFOPT(vn, VN_DEBUG)
290                 kprintf("vnstrategy(%p): unit %d\n", bp, unit);
291
292         if ((vn->sc_flags & VNF_INITED) == 0) {
293                 bp->b_error = ENXIO;
294                 bp->b_flags |= B_ERROR;
295                 biodone(bio);
296                 return(0);
297         }
298
299         bp->b_resid = bp->b_bcount;
300
301         /*
302          * The vnode device is using disk/slice label support.
303          *
304          * The dscheck() function is called for validating the
305          * slices that exist ON the vnode device itself, and
306          * translate the "slice-relative" block number, again.
307          * dscheck() will call biodone() and return NULL if
308          * we are at EOF or beyond the device size.
309          */
310
311         nbio = bio;
312
313         /*
314          * Use the translated nbio from this point on
315          */
316         if (vn->sc_vp && bp->b_cmd == BUF_CMD_FREEBLKS) {
317                 /*
318                  * Freeblks is not handled for vnode-backed elements yet.
319                  */
320                 bp->b_resid = 0;
321                 /* operation complete */
322         } else if (vn->sc_vp) {
323                 /*
324                  * VNODE I/O
325                  *
326                  * If an error occurs, we set B_ERROR but we do not set 
327                  * B_INVAL because (for a write anyway), the buffer is 
328                  * still valid.
329                  */
330                 struct uio auio;
331                 struct iovec aiov;
332
333                 bzero(&auio, sizeof(auio));
334
335                 aiov.iov_base = bp->b_data;
336                 aiov.iov_len = bp->b_bcount;
337                 auio.uio_iov = &aiov;
338                 auio.uio_iovcnt = 1;
339                 auio.uio_offset = nbio->bio_offset;
340                 auio.uio_segflg = UIO_SYSSPACE;
341                 if (bp->b_cmd == BUF_CMD_READ)
342                         auio.uio_rw = UIO_READ;
343                 else
344                         auio.uio_rw = UIO_WRITE;
345                 auio.uio_resid = bp->b_bcount;
346                 auio.uio_td = curthread;
347                 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY);
348                 if (bp->b_cmd == BUF_CMD_READ)
349                         error = VOP_READ(vn->sc_vp, &auio, IO_DIRECT | IO_RECURSE, vn->sc_cred);
350                 else
351                         error = VOP_WRITE(vn->sc_vp, &auio, IO_DIRECT | IO_RECURSE, vn->sc_cred);
352                 vn_unlock(vn->sc_vp);
353                 bp->b_resid = auio.uio_resid;
354                 if (error) {
355                         bp->b_error = error;
356                         bp->b_flags |= B_ERROR;
357                 }
358                 /* operation complete */
359         } else if (vn->sc_object) {
360                 /*
361                  * OBJT_SWAP I/O (handles read, write, freebuf)
362                  *
363                  * We have nothing to do if freeing  blocks on a reserved
364                  * swap area, othrewise execute the op.
365                  */
366                 if (bp->b_cmd == BUF_CMD_FREEBLKS && TESTOPT(vn, VN_RESERVE)) {
367                         bp->b_resid = 0;
368                         /* operation complete */
369                 } else {
370                         vm_pager_strategy(vn->sc_object, nbio);
371                         return(0);
372                         /* NOT REACHED */
373                 }
374         } else {
375                 bp->b_resid = bp->b_bcount;
376                 bp->b_flags |= B_ERROR | B_INVAL;
377                 bp->b_error = EINVAL;
378                 /* operation complete */
379         }
380         biodone(nbio);
381         return(0);
382 }
383
384 /* ARGSUSED */
385 static  int
386 vnioctl(struct dev_ioctl_args *ap)
387 {
388         cdev_t dev = ap->a_head.a_dev;
389         struct vn_softc *vn;
390         struct vn_ioctl *vio;
391         int error;
392         u_long *f;
393
394         vn = dev->si_drv1;
395         IFOPT(vn,VN_FOLLOW) {
396                 kprintf("vnioctl(%s, 0x%lx, %p, 0x%x): unit %d\n",
397                     devtoname(dev), ap->a_cmd, ap->a_data, ap->a_fflag,
398                     dkunit(dev));
399         }
400
401         switch (ap->a_cmd) {
402         case VNIOCATTACH:
403         case VNIOCDETACH:
404         case VNIOCGSET:
405         case VNIOCGCLEAR:
406         case VNIOCGET:
407         case VNIOCUSET:
408         case VNIOCUCLEAR:
409                 goto vn_specific;
410         }
411
412 #if 0
413         if (dkslice(dev) != WHOLE_DISK_SLICE ||
414                 dkpart(dev) != WHOLE_SLICE_PART)
415                 return (ENOTTY);
416 #endif
417
418     vn_specific:
419
420         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
421         if (error)
422                 return (error);
423
424         vio = (struct vn_ioctl *)ap->a_data;
425         f = (u_long*)ap->a_data;
426
427         switch (ap->a_cmd) {
428         case VNIOCATTACH:
429                 if (vn->sc_flags & VNF_INITED)
430                         return(EBUSY);
431
432                 if (vio->vn_file == NULL)
433                         error = vniocattach_swap(vn, vio, dev, ap->a_fflag, ap->a_cred);
434                 else
435                         error = vniocattach_file(vn, vio, dev, ap->a_fflag, ap->a_cred);
436                 break;
437
438         case VNIOCDETACH:
439                 if ((vn->sc_flags & VNF_INITED) == 0)
440                         return(ENXIO);
441                 /*
442                  * XXX handle i/o in progress.  Return EBUSY, or wait, or
443                  * flush the i/o.
444                  * XXX handle multiple opens of the device.  Return EBUSY,
445                  * or revoke the fd's.
446                  * How are these problems handled for removable and failing
447                  * hardware devices? (Hint: They are not)
448                  */
449                 if (count_dev(vn->sc_devlist) > 1)
450                         return (EBUSY);
451
452                 vnclear(vn);
453                 IFOPT(vn, VN_FOLLOW)
454                         kprintf("vnioctl: CLRed\n");
455                 break;
456
457         case VNIOCGET:
458                 error = vnget(dev, vn, (struct vn_user *) ap->a_data);
459                 break;
460
461         case VNIOCGSET:
462                 vn_options |= *f;
463                 *f = vn_options;
464                 break;
465
466         case VNIOCGCLEAR:
467                 vn_options &= ~(*f);
468                 *f = vn_options;
469                 break;
470
471         case VNIOCUSET:
472                 vn->sc_options |= *f;
473                 *f = vn->sc_options;
474                 break;
475
476         case VNIOCUCLEAR:
477                 vn->sc_options &= ~(*f);
478                 *f = vn->sc_options;
479                 break;
480
481         default:
482                 error = ENOTTY;
483                 break;
484         }
485         return(error);
486 }
487
488 /*
489  *      vniocattach_file:
490  *
491  *      Attach a file to a VN partition.  Return the size in the vn_size
492  *      field.
493  */
494
495 static int
496 vniocattach_file(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev,
497                  int flag, struct ucred *cred)
498 {
499         struct vattr vattr;
500         struct nlookupdata nd;
501         int error, flags;
502         struct vnode *vp;
503         struct disk_info info;
504
505         flags = FREAD|FWRITE;
506         error = nlookup_init(&nd, vio->vn_file, 
507                                 UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
508         if (error)
509                 return (error);
510         if ((error = vn_open(&nd, NULL, flags, 0)) != 0) {
511                 if (error != EACCES && error != EPERM && error != EROFS)
512                         goto done;
513                 flags &= ~FWRITE;
514                 nlookup_done(&nd);
515                 error = nlookup_init(&nd, vio->vn_file, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
516                 if (error)
517                         return (error);
518                 if ((error = vn_open(&nd, NULL, flags, 0)) != 0)
519                         goto done;
520         }
521         vp = nd.nl_open_vp;
522         if (vp->v_type != VREG ||
523             (error = VOP_GETATTR(vp, &vattr))) {
524                 if (error == 0)
525                         error = EINVAL;
526                 goto done;
527         }
528         vn_unlock(vp);
529         vn->sc_secsize = DEV_BSIZE;
530         vn->sc_vp = vp;
531         nd.nl_open_vp = NULL;
532
533         /*
534          * If the size is specified, override the file attributes.  Note that
535          * the vn_size argument is in PAGE_SIZE sized blocks.
536          */
537         if (vio->vn_size)
538                 vn->sc_size = vio->vn_size * PAGE_SIZE / vn->sc_secsize;
539         else
540                 vn->sc_size = vattr.va_size / vn->sc_secsize;
541         error = vnsetcred(vn, cred);
542         if (error) {
543                 vn->sc_vp = NULL;
544                 vn_close(vp, flags);
545                 goto done;
546         }
547         vn->sc_flags |= VNF_INITED;
548         if (flags == FREAD)
549                 vn->sc_flags |= VNF_READONLY;
550
551         /*
552          * Set the disk info so that probing is triggered
553          */
554         bzero(&info, sizeof(struct disk_info));
555         info.d_media_blksize = vn->sc_secsize;
556         info.d_media_blocks = vn->sc_size;
557         /*
558          * reserve mbr sector for backwards compatibility
559          * when no slices exist.
560          */
561         info.d_dsflags = DSO_COMPATMBR;
562         info.d_secpertrack = 32;
563         info.d_nheads = 64 / (vn->sc_secsize / DEV_BSIZE);
564         info.d_secpercyl = info.d_secpertrack * info.d_nheads;
565         info.d_ncylinders = vn->sc_size / info.d_secpercyl;
566         disk_setdiskinfo_sync(&vn->sc_disk, &info);
567
568         error = dev_dopen(dev, flag, S_IFCHR, cred);
569         if (error)
570                 vnclear(vn);
571
572         IFOPT(vn, VN_FOLLOW)
573                 kprintf("vnioctl: SET vp %p size %llx blks\n",
574                        vn->sc_vp, (long long)vn->sc_size);
575 done:
576         nlookup_done(&nd);
577         return(error);
578 }
579
580 /*
581  *      vniocattach_swap:
582  *
583  *      Attach swap backing store to a VN partition of the size specified
584  *      in vn_size.
585  */
586
587 static int
588 vniocattach_swap(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev,
589                  int flag, struct ucred *cred)
590 {
591         int error;
592         struct disk_info info;
593
594         /*
595          * Range check.  Disallow negative sizes or any size less then the
596          * size of a page.  Then round to a page.
597          */
598
599         if (vio->vn_size <= 0)
600                 return(EDOM);
601
602         /*
603          * Allocate an OBJT_SWAP object.
604          *
605          * sc_secsize is PAGE_SIZE'd
606          *
607          * vio->vn_size is in PAGE_SIZE'd chunks.
608          * sc_size must be in PAGE_SIZE'd chunks.  
609          * Note the truncation.
610          */
611
612         vn->sc_secsize = PAGE_SIZE;
613         vn->sc_size = vio->vn_size;
614         vn->sc_object = vm_pager_allocate(OBJT_SWAP, NULL,
615                                           vn->sc_secsize * (off_t)vio->vn_size,
616                                           VM_PROT_DEFAULT, 0);
617         IFOPT(vn, VN_RESERVE) {
618                 if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) {
619                         vm_pager_deallocate(vn->sc_object);
620                         vn->sc_object = NULL;
621                         return(EDOM);
622                 }
623         }
624         vn->sc_flags |= VNF_INITED;
625
626         error = vnsetcred(vn, cred);
627         if (error == 0) {
628                 /*
629                  * Set the disk info so that probing is triggered
630                  */
631                 bzero(&info, sizeof(struct disk_info));
632                 info.d_media_blksize = vn->sc_secsize;
633                 info.d_media_blocks = vn->sc_size;
634                 /*
635                  * reserve mbr sector for backwards compatibility
636                  * when no slices exist.
637                  */
638                 info.d_dsflags = DSO_COMPATMBR;
639                 info.d_secpertrack = 32;
640                 info.d_nheads = 64 / (vn->sc_secsize / DEV_BSIZE);
641                 info.d_secpercyl = info.d_secpertrack * info.d_nheads;
642                 info.d_ncylinders = vn->sc_size / info.d_secpercyl;
643                 disk_setdiskinfo_sync(&vn->sc_disk, &info);
644
645                 error = dev_dopen(dev, flag, S_IFCHR, cred);
646         }
647         if (error == 0) {
648                 IFOPT(vn, VN_FOLLOW) {
649                         kprintf("vnioctl: SET vp %p size %llx\n",
650                                vn->sc_vp, (long long)vn->sc_size);
651                 }
652         }
653         if (error)
654                 vnclear(vn);
655         return(error);
656 }
657
658 /*
659  * Duplicate the current processes' credentials.  Since we are called only
660  * as the result of a SET ioctl and only root can do that, any future access
661  * to this "disk" is essentially as root.  Note that credentials may change
662  * if some other uid can write directly to the mapped file (NFS).
663  */
664 int
665 vnsetcred(struct vn_softc *vn, struct ucred *cred)
666 {
667         char *tmpbuf;
668         int error = 0;
669
670         /*
671          * Set credits in our softc
672          */
673
674         if (vn->sc_cred)
675                 crfree(vn->sc_cred);
676         vn->sc_cred = crdup(cred);
677
678         /*
679          * Horrible kludge to establish credentials for NFS  XXX.
680          */
681
682         if (vn->sc_vp) {
683                 struct uio auio;
684                 struct iovec aiov;
685
686                 tmpbuf = kmalloc(vn->sc_secsize, M_TEMP, M_WAITOK);
687                 bzero(&auio, sizeof(auio));
688
689                 aiov.iov_base = tmpbuf;
690                 aiov.iov_len = vn->sc_secsize;
691                 auio.uio_iov = &aiov;
692                 auio.uio_iovcnt = 1;
693                 auio.uio_offset = 0;
694                 auio.uio_rw = UIO_READ;
695                 auio.uio_segflg = UIO_SYSSPACE;
696                 auio.uio_resid = aiov.iov_len;
697                 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY);
698                 error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred);
699                 vn_unlock(vn->sc_vp);
700                 kfree(tmpbuf, M_TEMP);
701         }
702         return (error);
703 }
704
705 void
706 vnclear(struct vn_softc *vn)
707 {
708         IFOPT(vn, VN_FOLLOW)
709                 kprintf("vnclear(%p): vp=%p\n", vn, vn->sc_vp);
710         vn->sc_flags &= ~VNF_INITED;
711         if (vn->sc_vp != NULL) {
712                 vn_close(vn->sc_vp,
713                     (vn->sc_flags & VNF_READONLY) ?  FREAD : (FREAD|FWRITE));
714                 vn->sc_vp = NULL;
715         }
716         vn->sc_flags &= ~VNF_READONLY;
717         if (vn->sc_cred) {
718                 crfree(vn->sc_cred);
719                 vn->sc_cred = NULL;
720         }
721         if (vn->sc_object != NULL) {
722                 vm_pager_deallocate(vn->sc_object);
723                 vn->sc_object = NULL;
724         }
725
726         disk_unprobe(&vn->sc_disk);
727
728         vn->sc_size = 0;
729 }
730
731 /*
732  *      vnget:
733  *
734  *      populate a struct vn_user for the VNIOCGET ioctl.
735  *      interface conventions defined in sys/sys/vnioctl.h.
736  */
737
738 static int
739 vnget(cdev_t dev, struct vn_softc *vn, struct vn_user *vnu)
740 {
741         int error, found = 0; 
742         char *freepath, *fullpath;
743         struct vattr vattr;
744
745         if (vnu->vnu_unit == -1) {
746                 vnu->vnu_unit = dkunit(dev);
747         }
748         else if (vnu->vnu_unit < 0)
749                 return (EINVAL);
750
751         SLIST_FOREACH(vn, &vn_list, sc_list) {
752
753                 if(vn->sc_unit != vnu->vnu_unit)
754                         continue;
755
756                 found = 1;
757
758                 if (vn->sc_flags & VNF_INITED && vn->sc_vp != NULL) {
759
760                         /* note: u_cred checked in vnioctl above */
761                         error = VOP_GETATTR(vn->sc_vp, &vattr);
762                         if (error) {
763                                 kprintf("vnget: VOP_GETATTR for %p failed\n",
764                                         vn->sc_vp);
765                                 return (error);
766                         }
767
768                         error = vn_fullpath(curproc, vn->sc_vp,
769                                                 &fullpath, &freepath);
770
771                         if (error) {
772                                 kprintf("vnget: unable to resolve vp %p\n",
773                                         vn->sc_vp);
774                                 return(error);
775                         }
776                         
777                         strlcpy(vnu->vnu_file, fullpath,
778                                 sizeof(vnu->vnu_file));
779                         kfree(freepath, M_TEMP);
780                         vnu->vnu_dev = vattr.va_fsid;
781                         vnu->vnu_ino = vattr.va_fileid;
782
783                 } 
784                 else if (vn->sc_flags & VNF_INITED && vn->sc_object != NULL){
785
786                         strlcpy(vnu->vnu_file, _VN_USER_SWAP,
787                                 sizeof(vnu->vnu_file));
788                         vnu->vnu_size = vn->sc_size;
789                         vnu->vnu_secsize = vn->sc_secsize;
790
791                 } else {
792
793                         bzero(vnu->vnu_file, sizeof(vnu->vnu_file));
794                         vnu->vnu_dev = 0;
795                         vnu->vnu_ino = 0;
796
797                 }
798                 break;
799         }
800
801         if (!found)
802                 return(ENXIO);
803
804         return(0);
805 }
806
807 static int
808 vnsize(struct dev_psize_args *ap)
809 {
810         cdev_t dev = ap->a_head.a_dev;
811         struct vn_softc *vn;
812
813         vn = dev->si_drv1;
814         if (!vn)
815                 return(ENXIO);
816         if ((vn->sc_flags & VNF_INITED) == 0)
817                 return(ENXIO);
818         ap->a_result = (int64_t)vn->sc_size;
819         return(0);
820 }
821
822 #if 0
823 static int
824 vnclone(struct dev_clone_args *ap)
825 {
826         int unit;
827
828         unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(vn), 0);
829         ap->a_dev = make_only_dev(&vn_ops, unit, UID_ROOT, GID_OPERATOR, 0600,
830                                                                 "vn%d", unit);
831
832         return 0;
833 }
834 #endif
835
836 static int 
837 vn_modevent(module_t mod, int type, void *data)
838 {
839         struct vn_softc *vn;
840         struct disk_info info;
841         cdev_t dev;
842         int i;
843
844         switch (type) {
845         case MOD_LOAD:
846 #if 0
847                 make_dev(&vn_ops, 0, UID_ROOT, GID_OPERATOR, 0640, "vn");
848 #endif
849                 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(vn));
850                 for (i = 0; i < VN_PREALLOCATED_UNITS; i++) {
851                         vn = vncreatevn();
852                         dev = disk_create(i, &vn->sc_disk, &vn_ops);
853                         vninitvn(vn, dev);
854
855                         bzero(&info, sizeof(struct disk_info));
856                         info.d_media_blksize = 512;
857                         info.d_media_blocks = 0;
858                         info.d_dsflags = DSO_MBRQUIET;
859                         info.d_secpertrack = 32;
860                         info.d_nheads = 64;
861                         info.d_secpercyl = info.d_secpertrack * info.d_nheads;
862                         info.d_ncylinders = 0;
863                         disk_setdiskinfo_sync(&vn->sc_disk, &info);
864
865                         devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(vn), i);
866                 }
867 #if 0
868                 devfs_clone_handler_add("vn", vnclone);
869 #endif
870                 break;
871         case MOD_UNLOAD:
872                 devfs_clone_bitmap_uninit(&DEVFS_CLONE_BITMAP(vn));
873 #if 0
874                 devfs_clone_handler_del("vn");
875 #endif
876                 /* fall through */
877         case MOD_SHUTDOWN:
878                 while ((vn = SLIST_FIRST(&vn_list)) != NULL) {
879                         SLIST_REMOVE_HEAD(&vn_list, sc_list);
880                         if (vn->sc_flags & VNF_INITED)
881                                 vnclear(vn);
882                         /* Cleanup all cdev_t's that refer to this unit */
883                         while ((dev = vn->sc_devlist) != NULL) {
884                                 vn->sc_devlist = dev->si_drv2;
885                                 dev->si_drv1 = dev->si_drv2 = NULL;
886                                 destroy_dev(dev);
887                         }
888                         kfree(vn, M_DEVBUF);
889                 }
890                 dev_ops_remove_all(&vn_ops);
891                 break;
892         default:
893                 break;
894         }
895         return 0;
896 }
897
898 DEV_MODULE(vn, vn_modevent, 0);