* 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: fd.c 1.3 89/12/03$
* @(#)vn.c 7.1 (Berkeley) %G%
* File (vnode) disk driver.
* Block/character interface to a vnode. Note that this uses the
* VOP_BMAP/VOP_STRATEGY interface to the vnode instead of a simple
* VOP_RDWR. We do this to avoid distorting the local buffer cache.
* NOTE: 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 fdunit(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 fd */
struct vnode
*sc_vp
; /* vnode */
struct ucred
*sc_cred
; /* credentials */
int sc_maxactive
; /* max # of active requests */
if (fddebug
& FDB_FOLLOW
)
printf("fdopen(%x, %x)\n", dev
, flags
);
* 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
= fdunit(bp
->b_dev
);
register struct fd_softc
*fs
= &fd_softc
[unit
];
register struct buf
*nbp
;
register int bn
, bsize
, resid
;
if (fddebug
& FDB_FOLLOW
)
printf("fdstrategy(%x): unit %d\n", bp
, unit
);
if ((fs
->sc_flags
& FDF_INITED
) == 0) {
sz
= howmany(bp
->b_bcount
, DEV_BSIZE
);
bp
->b_resid
= bp
->b_bcount
;
if (bn
< 0 || bn
+ sz
> fs
->sc_size
) {
bsize
= fs
->sc_vp
->v_vfsp
->vfs_bsize
;
flags
= bp
->b_flags
| B_CALL
;
for (resid
= bp
->b_resid
; resid
; resid
-= sz
) {
sz
= MIN(bsize
- off
, resid
);
(void) VOP_BMAP(fs
->sc_vp
, bn
/ bsize
, &vp
, &nbn
);
printf("fdstrategy: vp %x/%x bn %x/%x dev %x\n",
fs
->sc_vp
, vp
, bn
, nbn
, vp
->v_rdev
);
nbp
->b_bufsize
= bp
->b_bufsize
;
nbp
->b_blkno
= nbn
+ btodb(off
);
nbp
->b_proc
= bp
->b_proc
;
nbp
->b_iodone
= fdiodone
;
nbp
->b_pfcent
= (int) bp
; /* XXX */
* Just sort by block number
nbp
->b_cylin
= nbp
->b_blkno
;
disksort(&fdtab
[unit
], nbp
);
if (fdtab
[unit
].b_active
< fs
->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 fd_softc
*fs
= &fd_softc
[unit
];
* Dequeue now since lower level strategy routine might
fdtab
[unit
].b_actf
= bp
->b_actf
;
printf("fdstart(%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
= fdunit(pbp
->b_dev
);
printf("fdiodone(%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("fdiodone: bp %x error %d\n", bp
, bp
->b_error
);
pbp
->b_error
= geterror(bp
);
pbp
->b_resid
-= bp
->b_bcount
;
printf("fdiodone: pbp %x iodone\n", pbp
);
register int unit
= fdunit(dev
);
if (fddebug
& FDB_FOLLOW
)
printf("fdread(%x, %x)\n", dev
, uio
);
return(physio(fdstrategy
, &fdbuf
[unit
], dev
, B_READ
, minphys
, uio
));
register int unit
= fdunit(dev
);
if (fddebug
& FDB_FOLLOW
)
printf("fdwrite(%x, %x)\n", dev
, uio
);
return(physio(fdstrategy
, &fdbuf
[unit
], dev
, B_WRITE
, minphys
, uio
));
fdioctl(dev
, cmd
, data
, flag
)
register struct fd_softc
*fs
;
if (fddebug
& FDB_FOLLOW
)
printf("fdioctl(%x, %x, %x, %x): unit %d\n",
dev
, cmd
, data
, flag
, unit
);
error
= suser(u
.u_cred
, &u
.u_acflag
);
fio
= (struct fd_ioctl
*)data
;
if (fs
->sc_flags
& FDF_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.
error
= vn_open(fio
->fd_file
, UIO_USERSPACE
,
error
= VOP_GETATTR(vp
, &vattr
, u
.u_cred
);
vn_close(vp
, FREAD
|FWRITE
);
fs
->sc_size
= btodb(vattr
.va_size
); /* note truncation */
vn_close(vp
, FREAD
|FWRITE
);
fio
->fd_size
= dbtob(fs
->sc_size
);
fs
->sc_flags
|= FDF_INITED
;
printf("fdioctl: SET vp %x size %x\n",
if ((fs
->sc_flags
& FDF_INITED
) == 0)
printf("fdioctl: 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 fd_softc
*fs
;
fs
->sc_cred
= crdup(u
.u_cred
);
/* XXX: Horrible kludge to establish credentials for NFS */
aiov
.iov_len
= MIN(DEV_BSIZE
, dbtob(fs
->sc_size
));
auio
.uio_segflg
= UIO_SYSSPACE
;
auio
.uio_resid
= aiov
.iov_len
;
return(VOP_READ(fs
->sc_vp
, &auio
, 0, fs
->sc_cred
));
* Set maxactive based on FS type
register struct fd_softc
*fs
;
extern struct vnodeops ufs_vnodeops
, nfs_vnodeops
;
if (vp
->v_op
== &nfs_vnodeops
)
if (fs
->sc_maxactive
< 1)
register struct fd_softc
*fs
;
for (fs
= &fd_softc
[0]; fs
< &fd_softc
[NFD
]; fs
++)
if (fs
->sc_flags
& FDF_INITED
)
register struct fd_softc
*fs
;
register struct vnode
*vp
= fs
->sc_vp
;
if (fddebug
& FDB_FOLLOW
)
printf("fdclear(%x): vp %x\n", vp
);
fs
->sc_flags
&= ~FDF_INITED
;
if (vp
== (struct vnode
*)0)
panic("fdioctl: null vp");
/* XXX - this doesn't work right now */
(void) VOP_FSYNC(vp
, fs
->sc_cred
);
vn_close(vp
, FREAD
|FWRITE
);
fs
->sc_vp
= (struct vnode
*)0;
fs
->sc_cred
= (struct ucred
*)0;
register struct fd_softc
*fs
= &fd_softc
[unit
];
if (unit
>= NFD
|| (fs
->sc_flags
& FDF_INITED
) == 0)