f576544aa02e7b495b9515852ab4689eb52faebc
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* %sccs.include.redist.c%
* from: Utah $Hdr: vn.c 1.1 91/04/30$
* @(#)vn.c 7.6 (Berkeley) %G%
* Block/character interface to a vnode. Allows one to treat a file
* as a disk (e.g. build a filesystem in it, mount it, etc.).
* NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
* instead of a simple VOP_RDWR. We do this to avoid distorting the
* NOTE 2: There is a security issue involved with this driver.
* Once mounted all access to the contents of the "mapped" file via
* the special file is controlled by the permissions on the special
* file, the protection of the mapped file is ignored (effectively,
* by using root credentials in all transactions).
#define vnunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */
((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
free((caddr_t)(bp), M_DEVBUF)
int sc_flags
; /* flags */
size_t sc_size
; /* size of vn */
struct vnode
*sc_vp
; /* vnode */
struct ucred
*sc_cred
; /* credentials */
int sc_maxactive
; /* max # of active requests */
vnopen(dev
, flags
, mode
, p
)
if (vndebug
& VDB_FOLLOW
)
printf("vnopen(%x, %x, %x, %x)\n", dev
, flags
, mode
, p
);
* Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
* Note that this driver can only be used for swapping over NFS on the hp
* since nfs_strategy on the vax cannot handle u-areas and page tables.
int unit
= vnunit(bp
->b_dev
);
register struct vn_softc
*vn
= &vn_softc
[unit
];
register struct buf
*nbp
;
register int bn
, bsize
, resid
;
if (vndebug
& VDB_FOLLOW
)
printf("vnstrategy(%x): unit %d\n", bp
, unit
);
if ((vn
->sc_flags
& VNF_INITED
) == 0) {
sz
= howmany(bp
->b_bcount
, DEV_BSIZE
);
bp
->b_resid
= bp
->b_bcount
;
if (bn
< 0 || bn
+ sz
> vn
->sc_size
) {
bsize
= vn
->sc_vp
->v_mount
->mnt_stat
.f_bsize
;
flags
= bp
->b_flags
| B_CALL
;
for (resid
= bp
->b_resid
; resid
; resid
-= sz
) {
sz
= MIN(bsize
- off
, resid
);
(void) VOP_BMAP(vn
->sc_vp
, bn
/ bsize
, &vp
, &nbn
);
printf("vnstrategy: vp %x/%x bn %x/%x\n",
nbp
->b_bufsize
= bp
->b_bufsize
;
if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
nbp
->b_blkno
= nbn
+ btodb(off
);
nbp
->b_proc
= bp
->b_proc
;
nbp
->b_iodone
= vniodone
;
nbp
->b_pfcent
= (int) bp
; /* XXX */
* Just sort by block number
nbp
->b_cylin
= nbp
->b_blkno
;
disksort(&vntab
[unit
], nbp
);
if (vntab
[unit
].b_active
< vn
->sc_maxactive
) {
* Feed requests sequentially.
* We do it this way to keep from flooding NFS servers if we are connected
* to an NFS file. This places the burden on the client rather than the
register struct vn_softc
*vn
= &vn_softc
[unit
];
* Dequeue now since lower level strategy routine might
vntab
[unit
].b_actf
= bp
->b_actf
;
printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
unit
, bp
, bp
->b_vp
, bp
->b_blkno
, bp
->b_un
.b_addr
,
register struct buf
*pbp
= (struct buf
*)bp
->b_pfcent
; /* XXX */
register int unit
= vnunit(pbp
->b_dev
);
printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
unit
, bp
, bp
->b_vp
, bp
->b_blkno
, bp
->b_un
.b_addr
,
printf("vniodone: bp %x error %d\n", bp
, bp
->b_error
);
pbp
->b_error
= biowait(bp
);
pbp
->b_resid
-= bp
->b_bcount
;
printf("vniodone: pbp %x iodone\n", pbp
);
vnread(dev
, uio
, flags
, p
)
register int unit
= vnunit(dev
);
if (vndebug
& VDB_FOLLOW
)
printf("vnread(%x, %x, %x, %x)\n", dev
, uio
, flags
, p
);
return(physio(vnstrategy
, &vnbuf
[unit
], dev
, B_READ
, minphys
, uio
));
vnwrite(dev
, uio
, flags
, p
)
register int unit
= vnunit(dev
);
if (vndebug
& VDB_FOLLOW
)
printf("vnwrite(%x, %x, %x, %x)\n", dev
, uio
, flags
, p
);
return(physio(vnstrategy
, &vnbuf
[unit
], dev
, B_WRITE
, minphys
, uio
));
vnioctl(dev
, cmd
, data
, flag
, p
)
register struct vn_softc
*vn
;
if (vndebug
& VDB_FOLLOW
)
printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n",
dev
, cmd
, data
, flag
, p
, unit
);
error
= suser(p
->p_ucred
, &p
->p_acflag
);
vio
= (struct vn_ioctl
*)data
;
if (vn
->sc_flags
& VNF_INITED
)
* Always open for read and write.
* This is probably bogus, but it lets vn_open()
* weed out directories, sockets, etc. so we don't
* have to worry about them.
nd
.ni_segflg
= UIO_USERSPACE
;
nd
.ni_dirp
= vio
->vn_file
;
if (error
= vn_open(&nd
, p
, FREAD
|FWRITE
, 0))
if (error
= VOP_GETATTR(nd
.ni_vp
, &vattr
, p
->p_ucred
, p
)) {
(void) vn_close(nd
.ni_vp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
vn
->sc_size
= btodb(vattr
.va_size
); /* note truncation */
if (error
= vnsetcred(vn
, p
->p_ucred
)) {
(void) vn_close(vn
->sc_vp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
vnthrottle(vn
, vn
->sc_vp
);
vio
->vn_size
= dbtob(vn
->sc_size
);
vn
->sc_flags
|= VNF_INITED
;
printf("vnioctl: SET vp %x size %x\n",
if ((vn
->sc_flags
& VNF_INITED
) == 0)
printf("vnioctl: CLRed\n");
* Duplicate the current processes' credentials. Since we are called only
* as the result of a SET ioctl and only root can do that, any future access
* to this "disk" is essentially as root. Note that credentials may change
* if some other uid can write directly to the mapped file (NFS).
register struct vn_softc
*vn
;
vn
->sc_cred
= crdup(cred
);
/* XXX: Horrible kludge to establish credentials for NFS */
aiov
.iov_len
= MIN(DEV_BSIZE
, dbtob(vn
->sc_size
));
auio
.uio_segflg
= UIO_SYSSPACE
;
auio
.uio_resid
= aiov
.iov_len
;
return(VOP_READ(vn
->sc_vp
, &auio
, 0, vn
->sc_cred
));
* Set maxactive based on FS type
register struct vn_softc
*vn
;
extern struct vnodeops ufs_vnodeops
, nfsv2_vnodeops
;
if (vp
->v_op
== &nfsv2_vnodeops
)
if (vn
->sc_maxactive
< 1)
register struct vn_softc
*vn
;
for (vn
= &vn_softc
[0]; vn
< &vn_softc
[NVN
]; vn
++)
if (vn
->sc_flags
& VNF_INITED
)
register struct vn_softc
*vn
;
register struct vnode
*vp
= vn
->sc_vp
;
struct proc
*p
= curproc
; /* XXX */
if (vndebug
& VDB_FOLLOW
)
printf("vnclear(%x): vp %x\n", vp
);
vn
->sc_flags
&= ~VNF_INITED
;
if (vp
== (struct vnode
*)0)
panic("vnioctl: null vp");
/* XXX - this doesn't work right now */
(void) VOP_FSYNC(vp
, 0, vn
->sc_cred
, MNT_WAIT
, p
);
(void) vn_close(vp
, FREAD
|FWRITE
, vn
->sc_cred
, p
);
vn
->sc_vp
= (struct vnode
*)0;
vn
->sc_cred
= (struct ucred
*)0;
register struct vn_softc
*vn
= &vn_softc
[unit
];
if (unit
>= NVN
|| (vn
->sc_flags
& VNF_INITED
) == 0)