mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-19 02:29:40 +00:00
- FDESC, FIFO, NULL, PORTAL, PROC, UMAP and UNION file
systems were repo-copied from sys/miscfs to sys/fs. - Renamed the following file systems and their modules: fdesc -> fdescfs, portal -> portalfs, union -> unionfs. - Renamed corresponding kernel options: FDESC -> FDESCFS, PORTAL -> PORTALFS, UNION -> UNIONFS. - Install header files for the above file systems. - Removed bogus -I${.CURDIR}/../../sys CFLAGS from userland Makefiles.
This commit is contained in:
parent
468f05c7f7
commit
99d300a1ec
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77031
@ -20,8 +20,22 @@
|
||||
..
|
||||
..
|
||||
fs
|
||||
fdescfs
|
||||
..
|
||||
fifofs
|
||||
..
|
||||
nullfs
|
||||
..
|
||||
portalfs
|
||||
..
|
||||
procfs
|
||||
..
|
||||
smbfs
|
||||
..
|
||||
umapfs
|
||||
..
|
||||
unionfs
|
||||
..
|
||||
..
|
||||
g++
|
||||
std
|
||||
|
@ -44,8 +44,10 @@ LDIRS= cam msdosfs net netatalk netatm netgraph netinet netinet6 \
|
||||
sys vm
|
||||
|
||||
LNOHEADERDIRS= fs isofs ufs dev
|
||||
LSUBDIRS= fs/smbfs isofs/cd9660 ufs/ffs ufs/mfs ufs/ufs \
|
||||
cam/scsi dev/ppbus dev/usb dev/wi
|
||||
|
||||
LSUBDIRS= cam/scsi dev/ppbus dev/usb dev/wi \
|
||||
fs/fdesc fs/fifofs fs/nullfs fs/portal fs/procfs fs/smbfs \
|
||||
fs/umapfs fs/union isofs/cd9660 ufs/ffs ufs/mfs ufs/ufs
|
||||
|
||||
# Define SHARED to indicate whether you want symbolic links to the system
|
||||
# source (``symlinks''), or a separate copy (``copies''). ``symlinks'' is
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_null.c getmntopts.c
|
||||
MAN= mount_null.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -50,7 +50,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_null.c getmntopts.c
|
||||
MAN= mount_null.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -50,7 +50,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -7,7 +7,7 @@ SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
|
||||
MAN= mount_portal.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
#include <fs/portalfs/portal.h>
|
||||
|
||||
/*
|
||||
* Meta-chars in an RE. Paths in the config file containing
|
||||
|
@ -7,7 +7,7 @@ SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
|
||||
MAN= mount_portal.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
#include <fs/portalfs/portal.h>
|
||||
|
||||
/*
|
||||
* Meta-chars in an RE. Paths in the config file containing
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_umap.c getmntopts.c
|
||||
MAN= mount_umap.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -52,7 +52,7 @@ static const char rcsid[] =
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <fs/umapfs/umap.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_umap.c getmntopts.c
|
||||
MAN= mount_umap.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -52,7 +52,7 @@ static const char rcsid[] =
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <fs/umapfs/umap.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_union.c getmntopts.c
|
||||
MAN= mount_union.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -52,7 +52,7 @@ static const char rcsid[] =
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <miscfs/union/union.h>
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -6,7 +6,7 @@ SRCS= mount_union.c getmntopts.c
|
||||
MAN= mount_union.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT}
|
||||
CFLAGS+=-I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -52,7 +52,7 @@ static const char rcsid[] =
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <miscfs/union/union.h>
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
@ -142,7 +142,7 @@
|
||||
#include <ddb/ddb.h>
|
||||
#include <alpha/alpha/db_instruction.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
u_int64_t cycles_per_usec;
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/reg.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
@ -75,7 +75,7 @@
|
||||
#include <ddb/ddb.h>
|
||||
#include <alpha/alpha/db_instruction.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <alpha/osf1/osf1_signal.h>
|
||||
#include <alpha/osf1/osf1_proto.h>
|
||||
|
@ -662,16 +662,16 @@ options NFS #Network File System
|
||||
# The rest are optional:
|
||||
#options NFS_NOSERVER #Disable the NFS-server code.
|
||||
options CD9660 #ISO 9660 filesystem
|
||||
options FDESC #File descriptor filesystem
|
||||
options FDESCFS #File descriptor filesystem
|
||||
options HPFS #OS/2 File system
|
||||
options MSDOSFS #MS DOS File System (FAT, FAT32)
|
||||
options NTFS #NT File System
|
||||
options NULLFS #NULL filesystem
|
||||
options NWFS #NetWare filesystem
|
||||
options PORTAL #Portal filesystem
|
||||
options PORTALFS #Portal filesystem
|
||||
options PROCFS #Process filesystem
|
||||
options UMAPFS #UID map filesystem
|
||||
options UNION #Union filesystem
|
||||
options UNIONFS #Union filesystem
|
||||
# options NODEVFS #disable devices filesystem
|
||||
# The xFS_ROOT options REQUIRE the associated ``options xFS''
|
||||
options NFS_ROOT #NFS usable as root device
|
||||
|
@ -585,15 +585,44 @@ dev/wds/wd7000.c optional wds isa
|
||||
dev/wi/if_wi.c optional wi card
|
||||
dev/wi/if_wi.c optional wi pccard
|
||||
dev/xe/if_xe.c optional xe card
|
||||
fs/devfs/devfs_vnops.c standard
|
||||
fs/devfs/devfs_vfsops.c standard
|
||||
fs/deadfs/dead_vnops.c standard
|
||||
fs/devfs/devfs_devs.c standard
|
||||
fs/devfs/devfs_vfsops.c standard
|
||||
fs/devfs/devfs_vnops.c standard
|
||||
fs/fdescfs/fdesc_vfsops.c optional fdescfs
|
||||
fs/fdescfs/fdesc_vnops.c optional fdescfs
|
||||
fs/fifofs/fifo_vnops.c standard
|
||||
fs/hpfs/hpfs_alsubr.c optional hpfs
|
||||
fs/hpfs/hpfs_hash.c optional hpfs
|
||||
fs/hpfs/hpfs_lookup.c optional hpfs
|
||||
fs/hpfs/hpfs_subr.c optional hpfs
|
||||
fs/hpfs/hpfs_vfsops.c optional hpfs
|
||||
fs/hpfs/hpfs_vnops.c optional hpfs
|
||||
fs/hpfs/hpfs_hash.c optional hpfs
|
||||
fs/hpfs/hpfs_subr.c optional hpfs
|
||||
fs/hpfs/hpfs_lookup.c optional hpfs
|
||||
fs/hpfs/hpfs_alsubr.c optional hpfs
|
||||
fs/nullfs/null_subr.c optional nullfs
|
||||
fs/nullfs/null_vfsops.c optional nullfs
|
||||
fs/nullfs/null_vnops.c optional nullfs
|
||||
fs/portalfs/portal_vfsops.c optional portalfs
|
||||
fs/portalfs/portal_vnops.c optional portalfs
|
||||
fs/procfs/procfs_ctl.c optional procfs
|
||||
fs/procfs/procfs_dbregs.c standard
|
||||
fs/procfs/procfs_fpregs.c standard
|
||||
fs/procfs/procfs_map.c optional procfs
|
||||
fs/procfs/procfs_mem.c standard
|
||||
fs/procfs/procfs_note.c optional procfs
|
||||
fs/procfs/procfs_regs.c standard
|
||||
fs/procfs/procfs_rlimit.c optional procfs
|
||||
fs/procfs/procfs_status.c optional procfs
|
||||
fs/procfs/procfs_subr.c optional procfs
|
||||
fs/procfs/procfs_type.c optional procfs
|
||||
fs/procfs/procfs_vfsops.c optional procfs
|
||||
fs/procfs/procfs_vnops.c optional procfs
|
||||
fs/specfs/spec_vnops.c standard
|
||||
fs/umapfs/umap_subr.c optional umapfs
|
||||
fs/umapfs/umap_vfsops.c optional umapfs
|
||||
fs/umapfs/umap_vnops.c optional umapfs
|
||||
fs/unionfs/union_subr.c optional unionfs
|
||||
fs/unionfs/union_vfsops.c optional unionfs
|
||||
fs/unionfs/union_vnops.c optional unionfs
|
||||
gnu/ext2fs/ext2_alloc.c optional ext2fs
|
||||
gnu/ext2fs/ext2_balloc.c optional ext2fs
|
||||
gnu/ext2fs/ext2_inode.c optional ext2fs
|
||||
@ -803,35 +832,6 @@ libkern/strtol.c standard
|
||||
libkern/strtoq.c standard
|
||||
libkern/strtoul.c standard
|
||||
libkern/strtouq.c standard
|
||||
miscfs/deadfs/dead_vnops.c standard
|
||||
miscfs/fdesc/fdesc_vfsops.c optional fdesc
|
||||
miscfs/fdesc/fdesc_vnops.c optional fdesc
|
||||
miscfs/fifofs/fifo_vnops.c standard
|
||||
miscfs/nullfs/null_subr.c optional nullfs
|
||||
miscfs/nullfs/null_vfsops.c optional nullfs
|
||||
miscfs/nullfs/null_vnops.c optional nullfs
|
||||
miscfs/portal/portal_vfsops.c optional portal
|
||||
miscfs/portal/portal_vnops.c optional portal
|
||||
miscfs/procfs/procfs_ctl.c optional procfs
|
||||
miscfs/procfs/procfs_dbregs.c standard
|
||||
miscfs/procfs/procfs_fpregs.c standard
|
||||
miscfs/procfs/procfs_map.c optional procfs
|
||||
miscfs/procfs/procfs_mem.c standard
|
||||
miscfs/procfs/procfs_note.c optional procfs
|
||||
miscfs/procfs/procfs_regs.c standard
|
||||
miscfs/procfs/procfs_rlimit.c optional procfs
|
||||
miscfs/procfs/procfs_status.c optional procfs
|
||||
miscfs/procfs/procfs_subr.c optional procfs
|
||||
miscfs/procfs/procfs_type.c optional procfs
|
||||
miscfs/procfs/procfs_vfsops.c optional procfs
|
||||
miscfs/procfs/procfs_vnops.c optional procfs
|
||||
miscfs/specfs/spec_vnops.c standard
|
||||
miscfs/umapfs/umap_subr.c optional umapfs
|
||||
miscfs/umapfs/umap_vfsops.c optional umapfs
|
||||
miscfs/umapfs/umap_vnops.c optional umapfs
|
||||
miscfs/union/union_subr.c optional union
|
||||
miscfs/union/union_vfsops.c optional union
|
||||
miscfs/union/union_vnops.c optional union
|
||||
msdosfs/msdosfs_conv.c optional msdosfs
|
||||
msdosfs/msdosfs_denode.c optional msdosfs
|
||||
msdosfs/msdosfs_fat.c optional msdosfs
|
||||
|
@ -118,7 +118,7 @@ INCLUDE_CONFIG_FILE opt_config.h
|
||||
CD9660 opt_dontuse.h
|
||||
CODA opt_dontuse.h
|
||||
EXT2FS opt_dontuse.h
|
||||
FDESC opt_dontuse.h
|
||||
FDESCFS opt_dontuse.h
|
||||
FFS opt_dontuse.h
|
||||
IFS opt_dontuse.h
|
||||
LINPROCFS opt_dontuse.h
|
||||
@ -126,12 +126,12 @@ MFS opt_dontuse.h
|
||||
MSDOSFS opt_dontuse.h
|
||||
NULLFS opt_dontuse.h
|
||||
NWFS opt_dontuse.h
|
||||
PORTAL opt_dontuse.h
|
||||
PORTALFS opt_dontuse.h
|
||||
PROCFS opt_dontuse.h
|
||||
UMAPFS opt_dontuse.h
|
||||
NTFS opt_dontuse.h
|
||||
HPFS opt_dontuse.h
|
||||
UNION opt_dontuse.h
|
||||
UNIONFS opt_dontuse.h
|
||||
|
||||
# These static filesystems has one slightly bogus static dependency in
|
||||
# sys/i386/i386/autoconf.c. If any of these filesystems are
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/fifofs/fifo.h>
|
||||
#include <fs/fifofs/fifo.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/unistd.h>
|
||||
|
@ -54,7 +54,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
#include <fs/fdescfs/fdesc.h>
|
||||
|
||||
static MALLOC_DEFINE(M_FDESCMNT, "FDESC mount", "FDESC mount structure");
|
||||
|
||||
|
@ -58,7 +58,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
#include <fs/fdescfs/fdesc.h>
|
||||
|
||||
#define FDL_WANT 0x01
|
||||
#define FDL_LOCKED 0x02
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include <sys/event.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/un.h>
|
||||
#include <miscfs/fifofs/fifo.h>
|
||||
#include <fs/fifofs/fifo.h>
|
||||
|
||||
/*
|
||||
* This structure is associated with the FIFO vnode and stores
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NNULLNODECACHE 16
|
||||
|
@ -54,7 +54,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
|
||||
|
||||
|
@ -185,7 +185,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
@ -57,7 +57,7 @@
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/portal/portal.h>
|
||||
#include <fs/portalfs/portal.h>
|
||||
|
||||
static MALLOC_DEFINE(M_PORTALFSMNT, "PORTAL mount", "PORTAL mount structure");
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/unpcb.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
#include <fs/portalfs/portal.h>
|
||||
|
||||
static int portal_fileid = PORTAL_ROOTFILEID+1;
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include <sys/sx.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
@ -54,7 +54,7 @@
|
||||
#include <sys/user.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_donote(curp, p, pfs, uio)
|
||||
|
@ -52,7 +52,7 @@
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_doregs(curp, p, pfs, uio)
|
||||
|
@ -52,7 +52,7 @@
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
|
||||
int
|
||||
|
@ -56,7 +56,7 @@
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_param.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#define DOCHECK() do { if (ps >= psbuf+sizeof(psbuf)) goto bailout; } while (0)
|
||||
int
|
||||
|
@ -50,7 +50,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
static struct pfsnode *pfshead;
|
||||
static int pfsvplock;
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_dotype(curp, p, pfs, uio)
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
static int procfs_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
|
@ -66,7 +66,7 @@
|
||||
|
||||
#include <vm/vm_zone.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
static int procfs_access __P((struct vop_access_args *));
|
||||
static int procfs_badop __P((void));
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <fs/umapfs/umap.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NUMAPNODECACHE 16
|
||||
|
@ -53,7 +53,7 @@
|
||||
#include <sys/namei.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <fs/umapfs/umap.h>
|
||||
|
||||
static MALLOC_DEFINE(M_UMAPFSMNT, "UMAP mount", "UMAP mount structure");
|
||||
|
||||
|
@ -51,8 +51,8 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
#include <fs/umapfs/umap.h>
|
||||
#include <fs/nullfs/null.h>
|
||||
|
||||
static int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
|
||||
SYSCTL_INT(_debug, OID_AUTO, umapfs_bug_bypass, CTLFLAG_RW,
|
||||
|
@ -58,7 +58,7 @@
|
||||
#include <vm/vm_zone.h>
|
||||
#include <vm/vm_object.h> /* for vm cache coherency */
|
||||
|
||||
#include <miscfs/union/union.h>
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
#include <sys/proc.h>
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <miscfs/union/union.h>
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure");
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
||||
#include <sys/buf.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <miscfs/union/union.h>
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vnode_pager.h>
|
||||
|
@ -662,16 +662,16 @@ options NFS #Network File System
|
||||
# The rest are optional:
|
||||
#options NFS_NOSERVER #Disable the NFS-server code.
|
||||
options CD9660 #ISO 9660 filesystem
|
||||
options FDESC #File descriptor filesystem
|
||||
options FDESCFS #File descriptor filesystem
|
||||
options HPFS #OS/2 File system
|
||||
options MSDOSFS #MS DOS File System (FAT, FAT32)
|
||||
options NTFS #NT File System
|
||||
options NULLFS #NULL filesystem
|
||||
options NWFS #NetWare filesystem
|
||||
options PORTAL #Portal filesystem
|
||||
options PORTALFS #Portal filesystem
|
||||
options PROCFS #Process filesystem
|
||||
options UMAPFS #UID map filesystem
|
||||
options UNION #Union filesystem
|
||||
options UNIONFS #Union filesystem
|
||||
# options NODEVFS #disable devices filesystem
|
||||
# The xFS_ROOT options REQUIRE the associated ``options xFS''
|
||||
options NFS_ROOT #NFS usable as root device
|
||||
|
@ -77,7 +77,7 @@
|
||||
|
||||
#include <machine/reg.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
@ -75,7 +75,7 @@
|
||||
#include <ddb/ddb.h>
|
||||
#include <alpha/alpha/db_instruction.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
u_int64_t cycles_per_usec;
|
||||
|
@ -73,7 +73,7 @@
|
||||
#include <sys/vnode.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/fifofs/fifo.h>
|
||||
#include <fs/fifofs/fifo.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/unistd.h>
|
||||
|
@ -28,17 +28,17 @@ COMM= ${SYS}/conf/*.[ch] \
|
||||
${SYS}/dev/smbus/*.[ch] \
|
||||
${SYS}/dev/vn/*.[ch] \
|
||||
${SYS}/dev/vx/*.[ch] \
|
||||
${SYS}/fs/deadfs/*.[ch] \
|
||||
${SYS}/fs/fdescfs/*.[ch] \
|
||||
${SYS}/fs/fifofs/*.[ch] \
|
||||
${SYS}/fs/nullfs/*.[ch] \
|
||||
${SYS}/fs/portalfs/*.[ch] \
|
||||
${SYS}/fs/procfs/*.[ch] \
|
||||
${SYS}/fs/specfs/*.[ch] \
|
||||
${SYS}/fs/umapfs/*.[ch] \
|
||||
${SYS}/fs/unionfs/*.[ch] \
|
||||
${SYS}/isofs/cd9660/*.[ch] \
|
||||
${SYS}/kern/*.[ch] \
|
||||
${SYS}/miscfs/deadfs/*.[ch] \
|
||||
${SYS}/miscfs/fdesc/*.[ch] \
|
||||
${SYS}/miscfs/fifofs/*.[ch] \
|
||||
${SYS}/miscfs/nullfs/*.[ch] \
|
||||
${SYS}/miscfs/portal/*.[ch] \
|
||||
${SYS}/miscfs/procfs/*.[ch] \
|
||||
${SYS}/miscfs/specfs/*.[ch] \
|
||||
${SYS}/miscfs/umapfs/*.[ch] \
|
||||
${SYS}/miscfs/union/*.[ch] \
|
||||
${SYS}/msdosfs/*.[ch] \
|
||||
${SYS}/net/*.[ch] \
|
||||
${SYS}/netatalk/*.[ch] \
|
||||
@ -91,17 +91,17 @@ COMMDIR2= ${SYS}/dev/advansys \
|
||||
${SYS}/dev/smbus \
|
||||
${SYS}/dev/vn \
|
||||
${SYS}/dev/vx \
|
||||
${SYS}/fs/deadfs \
|
||||
${SYS}/fs/devfs \
|
||||
${SYS}/fs/fdescfs \
|
||||
${SYS}/fs/fifofs \
|
||||
${SYS}/fs/nullfs \
|
||||
${SYS}/fs/portalfs \
|
||||
${SYS}/fs/procfs \
|
||||
${SYS}/fs/specfs \
|
||||
${SYS}/fs/umapfs \
|
||||
${SYS}/fs/unionfs \
|
||||
${SYS}/isofs/cd9660 \
|
||||
${SYS}/miscfs/deadfs \
|
||||
${SYS}/miscfs/devfs \
|
||||
${SYS}/miscfs/fdesc \
|
||||
${SYS}/miscfs/fifofs \
|
||||
${SYS}/miscfs/nullfs \
|
||||
${SYS}/miscfs/portal \
|
||||
${SYS}/miscfs/procfs \
|
||||
${SYS}/miscfs/specfs \
|
||||
${SYS}/miscfs/umapfs \
|
||||
${SYS}/miscfs/union \
|
||||
${SYS}/ufs/ffs \
|
||||
${SYS}/ufs/mfs \
|
||||
${SYS}/ufs/ufs
|
||||
|
@ -33,11 +33,11 @@ SYSDIR=/sys
|
||||
# Directories in which to place tags links (other than machine-dependent)
|
||||
DGEN= conf \
|
||||
dev dev/scsi \
|
||||
fs fs/deadfs fs/fdescfs fs/fifofs \
|
||||
fs/lofs fs/nullfs fs/portalfs fs/procfs \
|
||||
fs/specfs fs/umapfs fs/unionfs \
|
||||
hp hp/dev hp/hpux \
|
||||
kern libkern \
|
||||
miscfs miscfs/deadfs miscfs/fdesc miscfs/fifofs \
|
||||
miscfs/lofs miscfs/nullfs miscfs/portal miscfs/procfs \
|
||||
miscfs/specfs miscfs/umapfs miscfs/union \
|
||||
net netccitt netinet netiso netns nfs scripts sys \
|
||||
ufs ufs/ffs ufs/lfs ufs/mfs ufs/ufs \
|
||||
vm
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <fs/procfs/procfs.h>
|
||||
|
||||
/* use the equivalent procfs code */
|
||||
#if 0
|
||||
|
@ -68,7 +68,6 @@
|
||||
#include <sys/jail.h>
|
||||
|
||||
#include <machine/limits.h>
|
||||
#include <miscfs/union/union.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
|
@ -68,7 +68,6 @@
|
||||
#include <sys/jail.h>
|
||||
|
||||
#include <machine/limits.h>
|
||||
#include <miscfs/union/union.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)dead_vnops.c 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
static int chkvnlock __P((struct vnode *));
|
||||
/*
|
||||
* Prototypes for dead operations on vnodes.
|
||||
*/
|
||||
static int dead_badop __P((void));
|
||||
static int dead_bmap __P((struct vop_bmap_args *));
|
||||
static int dead_ioctl __P((struct vop_ioctl_args *));
|
||||
static int dead_lock __P((struct vop_lock_args *));
|
||||
static int dead_lookup __P((struct vop_lookup_args *));
|
||||
static int dead_open __P((struct vop_open_args *));
|
||||
static int dead_poll __P((struct vop_poll_args *));
|
||||
static int dead_print __P((struct vop_print_args *));
|
||||
static int dead_read __P((struct vop_read_args *));
|
||||
static int dead_write __P((struct vop_write_args *));
|
||||
|
||||
vop_t **dead_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc dead_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_advlock_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_bmap_desc, (vop_t *) dead_bmap },
|
||||
{ &vop_create_desc, (vop_t *) dead_badop },
|
||||
{ &vop_getattr_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_inactive_desc, (vop_t *) vop_null },
|
||||
{ &vop_ioctl_desc, (vop_t *) dead_ioctl },
|
||||
{ &vop_link_desc, (vop_t *) dead_badop },
|
||||
{ &vop_lock_desc, (vop_t *) dead_lock },
|
||||
{ &vop_lookup_desc, (vop_t *) dead_lookup },
|
||||
{ &vop_mkdir_desc, (vop_t *) dead_badop },
|
||||
{ &vop_mknod_desc, (vop_t *) dead_badop },
|
||||
{ &vop_open_desc, (vop_t *) dead_open },
|
||||
{ &vop_pathconf_desc, (vop_t *) vop_ebadf }, /* per pathconf(2) */
|
||||
{ &vop_poll_desc, (vop_t *) dead_poll },
|
||||
{ &vop_print_desc, (vop_t *) dead_print },
|
||||
{ &vop_read_desc, (vop_t *) dead_read },
|
||||
{ &vop_readdir_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_readlink_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_reclaim_desc, (vop_t *) vop_null },
|
||||
{ &vop_remove_desc, (vop_t *) dead_badop },
|
||||
{ &vop_rename_desc, (vop_t *) dead_badop },
|
||||
{ &vop_rmdir_desc, (vop_t *) dead_badop },
|
||||
{ &vop_setattr_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_symlink_desc, (vop_t *) dead_badop },
|
||||
{ &vop_write_desc, (vop_t *) dead_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc dead_vnodeop_opv_desc =
|
||||
{ &dead_vnodeop_p, dead_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(dead_vnodeop_opv_desc);
|
||||
|
||||
/*
|
||||
* Trivial lookup routine that always fails.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
*ap->a_vpp = NULL;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open always fails as if device did not exist.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (chkvnlock(ap->a_vp))
|
||||
panic("dead_read: lock");
|
||||
/*
|
||||
* Return EOF for tty devices, EIO for others
|
||||
*/
|
||||
if ((ap->a_vp->v_flag & VISTTY) == 0)
|
||||
return (EIO);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (chkvnlock(ap->a_vp))
|
||||
panic("dead_write: lock");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (!chkvnlock(ap->a_vp))
|
||||
return (ENOTTY);
|
||||
return (VCALL(ap->a_vp, VOFFSET(vop_ioctl), ap));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wait until the vnode has finished changing state.
|
||||
*/
|
||||
static int
|
||||
dead_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
/*
|
||||
* Since we are not using the lock manager, we must clear
|
||||
* the interlock here.
|
||||
*/
|
||||
if (ap->a_flags & LK_INTERLOCK) {
|
||||
mtx_unlock(&vp->v_interlock);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
}
|
||||
if (!chkvnlock(vp))
|
||||
return (0);
|
||||
return (VCALL(vp, VOFFSET(vop_lock), ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until the vnode has finished changing state.
|
||||
*/
|
||||
static int
|
||||
dead_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
int *a_runb;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (!chkvnlock(ap->a_vp))
|
||||
return (EIO);
|
||||
return (VOP_BMAP(ap->a_vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp, ap->a_runb));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a dead vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
dead_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, dead vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty vnode bad operation
|
||||
*/
|
||||
static int
|
||||
dead_badop()
|
||||
{
|
||||
|
||||
panic("dead_badop called");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to wait during times when the vnode is
|
||||
* in a state of change.
|
||||
*/
|
||||
int
|
||||
chkvnlock(vp)
|
||||
register struct vnode *vp;
|
||||
{
|
||||
int locked = 0;
|
||||
|
||||
while (vp->v_flag & VXLOCK) {
|
||||
vp->v_flag |= VXWANT;
|
||||
(void) tsleep((caddr_t)vp, PINOD, "ckvnlk", 0);
|
||||
locked = 1;
|
||||
}
|
||||
return (locked);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trivial poll routine that always returns POLLHUP.
|
||||
* This is necessary so that a process which is polling a file
|
||||
* gets notified when that file is revoke()d.
|
||||
*/
|
||||
static int
|
||||
dead_poll(ap)
|
||||
struct vop_poll_args *ap;
|
||||
{
|
||||
return (POLLHUP);
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fdesc.h 8.5 (Berkeley) 1/21/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct fdescmount {
|
||||
struct vnode *f_root; /* Root node */
|
||||
};
|
||||
|
||||
#define FD_ROOT 1
|
||||
#define FD_DESC 3
|
||||
|
||||
typedef enum {
|
||||
Froot,
|
||||
Fdesc
|
||||
} fdntype;
|
||||
|
||||
struct fdescnode {
|
||||
LIST_ENTRY(fdescnode) fd_hash; /* Hash list */
|
||||
struct vnode *fd_vnode; /* Back ptr to vnode */
|
||||
fdntype fd_type; /* Type of this node */
|
||||
unsigned fd_fd; /* Fd to be dup'ed */
|
||||
int fd_ix; /* filesystem index */
|
||||
};
|
||||
|
||||
#define VFSTOFDESC(mp) ((struct fdescmount *)((mp)->mnt_data))
|
||||
#define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data)
|
||||
|
||||
extern int fdesc_init __P((struct vfsconf *));
|
||||
extern int fdesc_root __P((struct mount *, struct vnode **));
|
||||
extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **,
|
||||
struct proc *));
|
||||
#endif /* _KERNEL */
|
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fdesc_vfsops.c 8.4 (Berkeley) 1/21/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* /dev/fd Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
|
||||
static MALLOC_DEFINE(M_FDESCMNT, "FDESC mount", "FDESC mount structure");
|
||||
|
||||
static int fdesc_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
static int fdesc_unmount __P((struct mount *mp, int mntflags,
|
||||
struct proc *p));
|
||||
static int fdesc_statfs __P((struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p));
|
||||
|
||||
/*
|
||||
* Mount the per-process file descriptors (/dev/fd)
|
||||
*/
|
||||
static int
|
||||
fdesc_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct fdescmount *fmp;
|
||||
struct vnode *rvp;
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
MALLOC(fmp, struct fdescmount *, sizeof(struct fdescmount),
|
||||
M_FDESCMNT, M_WAITOK); /* XXX */
|
||||
rvp->v_type = VDIR;
|
||||
rvp->v_flag |= VROOT;
|
||||
fmp->f_root = rvp;
|
||||
/* XXX -- don't mark as local to work around fts() problems */
|
||||
/*mp->mnt_flag |= MNT_LOCAL;*/
|
||||
mp->mnt_data = (qaddr_t) fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
|
||||
bcopy("fdesc", mp->mnt_stat.f_mntfromname, sizeof("fdesc"));
|
||||
(void)fdesc_statfs(mp, &mp->mnt_stat, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*
|
||||
* There is 1 extra root vnode reference corresponding
|
||||
* to f_root.
|
||||
*/
|
||||
if ((error = vflush(mp, 1, flags)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Finally, throw away the fdescmount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_FDESCMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = VFSTOFDESC(mp)->f_root;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct filedesc *fdp;
|
||||
int lim;
|
||||
int i;
|
||||
int last;
|
||||
int freefd;
|
||||
|
||||
/*
|
||||
* Compute number of free file descriptors.
|
||||
* [ Strange results will ensue if the open file
|
||||
* limit is ever reduced below the current number
|
||||
* of open files... ]
|
||||
*/
|
||||
lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
|
||||
fdp = p->p_fd;
|
||||
last = min(fdp->fd_nfiles, lim);
|
||||
freefd = 0;
|
||||
for (i = fdp->fd_freefile; i < last; i++)
|
||||
if (fdp->fd_ofiles[i] == NULL)
|
||||
freefd++;
|
||||
|
||||
/*
|
||||
* Adjust for the fact that the fdesc array may not
|
||||
* have been fully allocated yet.
|
||||
*/
|
||||
if (fdp->fd_nfiles < lim)
|
||||
freefd += (lim - fdp->fd_nfiles);
|
||||
|
||||
sbp->f_flags = 0;
|
||||
sbp->f_bsize = DEV_BSIZE;
|
||||
sbp->f_iosize = DEV_BSIZE;
|
||||
sbp->f_blocks = 2; /* 1K to keep df happy */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = lim + 1; /* Allow for "." */
|
||||
sbp->f_ffree = freefd; /* See comments above */
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct vfsops fdesc_vfsops = {
|
||||
fdesc_mount,
|
||||
vfs_stdstart,
|
||||
fdesc_unmount,
|
||||
fdesc_root,
|
||||
vfs_stdquotactl,
|
||||
fdesc_statfs,
|
||||
vfs_stdsync,
|
||||
vfs_stdvget,
|
||||
vfs_stdfhtovp,
|
||||
vfs_stdcheckexp,
|
||||
vfs_stdvptofh,
|
||||
fdesc_init,
|
||||
vfs_stduninit,
|
||||
vfs_stdextattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(fdesc_vfsops, fdesc, VFCF_SYNTHETIC);
|
@ -1,576 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fdesc_vnops.c 8.9 (Berkeley) 1/21/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* /dev/fd Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/kernel.h> /* boottime */
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/file.h> /* Must come after sys/malloc.h */
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
|
||||
#define FDL_WANT 0x01
|
||||
#define FDL_LOCKED 0x02
|
||||
static int fdcache_lock;
|
||||
|
||||
static vop_t **fdesc_vnodeop_p;
|
||||
|
||||
#define NFDCACHE 4
|
||||
#define FD_NHASH(ix) \
|
||||
(&fdhashtbl[(ix) & fdhash])
|
||||
static LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
|
||||
static u_long fdhash;
|
||||
|
||||
static int fdesc_badop __P((void));
|
||||
static int fdesc_getattr __P((struct vop_getattr_args *ap));
|
||||
static int fdesc_inactive __P((struct vop_inactive_args *ap));
|
||||
static int fdesc_lookup __P((struct vop_lookup_args *ap));
|
||||
static int fdesc_open __P((struct vop_open_args *ap));
|
||||
static int fdesc_print __P((struct vop_print_args *ap));
|
||||
static int fdesc_readdir __P((struct vop_readdir_args *ap));
|
||||
static int fdesc_reclaim __P((struct vop_reclaim_args *ap));
|
||||
static int fdesc_poll __P((struct vop_poll_args *ap));
|
||||
static int fdesc_setattr __P((struct vop_setattr_args *ap));
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
int
|
||||
fdesc_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_allocvp(ftype, ix, mp, vpp, p)
|
||||
fdntype ftype;
|
||||
int ix;
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct fdhashhead *fc;
|
||||
struct fdescnode *fd;
|
||||
int error = 0;
|
||||
|
||||
fc = FD_NHASH(ix);
|
||||
loop:
|
||||
LIST_FOREACH(fd, fc, fd_hash) {
|
||||
if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
|
||||
if (vget(fd->fd_vnode, 0, p))
|
||||
goto loop;
|
||||
*vpp = fd->fd_vnode;
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* otherwise lock the array while we call getnewvnode
|
||||
* since that can block.
|
||||
*/
|
||||
if (fdcache_lock & FDL_LOCKED) {
|
||||
fdcache_lock |= FDL_WANT;
|
||||
(void) tsleep((caddr_t) &fdcache_lock, PINOD, "fdalvp", 0);
|
||||
goto loop;
|
||||
}
|
||||
fdcache_lock |= FDL_LOCKED;
|
||||
|
||||
/*
|
||||
* Do the MALLOC before the getnewvnode since doing so afterward
|
||||
* might cause a bogus v_data pointer to get dereferenced
|
||||
* elsewhere if MALLOC should block.
|
||||
*/
|
||||
MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
|
||||
|
||||
error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
|
||||
if (error) {
|
||||
FREE(fd, M_TEMP);
|
||||
goto out;
|
||||
}
|
||||
(*vpp)->v_data = fd;
|
||||
fd->fd_vnode = *vpp;
|
||||
fd->fd_type = ftype;
|
||||
fd->fd_fd = -1;
|
||||
fd->fd_ix = ix;
|
||||
LIST_INSERT_HEAD(fc, fd, fd_hash);
|
||||
|
||||
out:
|
||||
fdcache_lock &= ~FDL_LOCKED;
|
||||
|
||||
if (fdcache_lock & FDL_WANT) {
|
||||
fdcache_lock &= ~FDL_WANT;
|
||||
wakeup((caddr_t) &fdcache_lock);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vp is the current namei directory
|
||||
* ndp is the name to locate in that directory...
|
||||
*/
|
||||
static int
|
||||
fdesc_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct proc *p = cnp->cn_proc;
|
||||
int nlen = cnp->cn_namelen;
|
||||
int nfiles = p->p_fd->fd_nfiles;
|
||||
u_int fd;
|
||||
int error;
|
||||
struct vnode *fvp;
|
||||
|
||||
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
|
||||
error = EROFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
VOP_UNLOCK(dvp, 0, p);
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (VTOFDESC(dvp)->fd_type != Froot) {
|
||||
error = ENOTDIR;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fd = 0;
|
||||
/* the only time a leading 0 is acceptable is if it's "0" */
|
||||
if (*pname == '0' && nlen != 1) {
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
while (nlen--) {
|
||||
if (*pname < '0' || *pname > '9') {
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
fd = 10 * fd + *pname++ - '0';
|
||||
}
|
||||
|
||||
if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {
|
||||
error = EBADF;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
VTOFDESC(fvp)->fd_fd = fd;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
*vpp = fvp;
|
||||
return (0);
|
||||
|
||||
bad:
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
if (VTOFDESC(vp)->fd_type == Froot)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* XXX Kludge: set p->p_dupfd to contain the value of the the file
|
||||
* descriptor being sought for duplication. The error return ensures
|
||||
* that the vnode for this device will be released by vn_open. Open
|
||||
* will detect this special error and take the actions in dupfdopen.
|
||||
* Other callers of vn_open or VOP_OPEN will simply report the
|
||||
* error.
|
||||
*/
|
||||
ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct filedesc *fdp = ap->a_p->p_fd;
|
||||
struct file *fp;
|
||||
struct stat stb;
|
||||
u_int fd;
|
||||
int error = 0;
|
||||
|
||||
switch (VTOFDESC(vp)->fd_type) {
|
||||
case Froot:
|
||||
VATTR_NULL(vap);
|
||||
|
||||
vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
vap->va_type = VDIR;
|
||||
vap->va_nlink = 2;
|
||||
vap->va_size = DEV_BSIZE;
|
||||
vap->va_fileid = VTOFDESC(vp)->fd_ix;
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_blocksize = DEV_BSIZE;
|
||||
vap->va_atime.tv_sec = boottime.tv_sec;
|
||||
vap->va_atime.tv_nsec = 0;
|
||||
vap->va_mtime = vap->va_atime;
|
||||
vap->va_ctime = vap->va_mtime;
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
vap->va_rdev = 0;
|
||||
vap->va_bytes = 0;
|
||||
break;
|
||||
|
||||
case Fdesc:
|
||||
fd = VTOFDESC(vp)->fd_fd;
|
||||
|
||||
if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
|
||||
return (EBADF);
|
||||
|
||||
bzero(&stb, sizeof(stb));
|
||||
error = fo_stat(fp, &stb, ap->a_p);
|
||||
if (error == 0) {
|
||||
VATTR_NULL(vap);
|
||||
vap->va_type = IFTOVT(stb.st_mode);
|
||||
vap->va_mode = stb.st_mode;
|
||||
#define FDRX (VREAD|VEXEC)
|
||||
if (vap->va_type == VDIR)
|
||||
vap->va_mode &= ~((FDRX)|(FDRX>>3)|(FDRX>>6));
|
||||
#undef FDRX
|
||||
vap->va_nlink = 1;
|
||||
vap->va_flags = 0;
|
||||
vap->va_bytes = stb.st_blocks * stb.st_blksize;
|
||||
vap->va_fileid = VTOFDESC(vp)->fd_ix;
|
||||
vap->va_size = stb.st_size;
|
||||
vap->va_blocksize = stb.st_blksize;
|
||||
vap->va_rdev = stb.st_rdev;
|
||||
|
||||
/*
|
||||
* If no time data is provided, use the current time.
|
||||
*/
|
||||
if (stb.st_atimespec.tv_sec == 0 &&
|
||||
stb.st_atimespec.tv_nsec == 0)
|
||||
nanotime(&stb.st_atimespec);
|
||||
|
||||
if (stb.st_ctimespec.tv_sec == 0 &&
|
||||
stb.st_ctimespec.tv_nsec == 0)
|
||||
nanotime(&stb.st_ctimespec);
|
||||
|
||||
if (stb.st_mtimespec.tv_sec == 0 &&
|
||||
stb.st_mtimespec.tv_nsec == 0)
|
||||
nanotime(&stb.st_mtimespec);
|
||||
|
||||
vap->va_atime = stb.st_atimespec;
|
||||
vap->va_mtime = stb.st_mtimespec;
|
||||
vap->va_ctime = stb.st_ctimespec;
|
||||
vap->va_uid = stb.st_uid;
|
||||
vap->va_gid = stb.st_gid;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("fdesc_getattr");
|
||||
break;
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
vp->v_type = vap->va_type;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct vnode *vp;
|
||||
struct mount *mp;
|
||||
struct file *fp;
|
||||
unsigned fd;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Can't mess with the root vnode
|
||||
*/
|
||||
if (VTOFDESC(ap->a_vp)->fd_type == Froot)
|
||||
return (EACCES);
|
||||
|
||||
fd = VTOFDESC(ap->a_vp)->fd_fd;
|
||||
|
||||
/*
|
||||
* Allow setattr where there is an underlying vnode.
|
||||
*/
|
||||
error = getvnode(ap->a_p->p_fd, fd, &fp);
|
||||
if (error) {
|
||||
/*
|
||||
* getvnode() returns EINVAL if the file descriptor is not
|
||||
* backed by a vnode. Silently drop all changes except
|
||||
* chflags(2) in this case.
|
||||
*/
|
||||
if (error == EINVAL) {
|
||||
if (vap->va_flags != VNOVAL)
|
||||
error = EOPNOTSUPP;
|
||||
else
|
||||
error = 0;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
vp = (struct vnode *)fp->f_data;
|
||||
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
|
||||
return (error);
|
||||
error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p);
|
||||
vn_finished_write(mp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define UIO_MX 16
|
||||
|
||||
static int
|
||||
fdesc_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct filedesc *fdp;
|
||||
struct dirent d;
|
||||
struct dirent *dp = &d;
|
||||
int error, i, off, fcnt;
|
||||
|
||||
/*
|
||||
* We don't allow exporting fdesc mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies)
|
||||
panic("fdesc_readdir: not hungry");
|
||||
|
||||
if (VTOFDESC(ap->a_vp)->fd_type != Froot)
|
||||
panic("fdesc_readdir: not dir");
|
||||
|
||||
off = (int)uio->uio_offset;
|
||||
if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
|
||||
uio->uio_resid < UIO_MX)
|
||||
return (EINVAL);
|
||||
i = (u_int)off / UIO_MX;
|
||||
fdp = uio->uio_procp->p_fd;
|
||||
error = 0;
|
||||
|
||||
fcnt = i - 2; /* The first two nodes are `.' and `..' */
|
||||
|
||||
while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) {
|
||||
switch (i) {
|
||||
case 0: /* `.' */
|
||||
case 1: /* `..' */
|
||||
bzero((caddr_t)dp, UIO_MX);
|
||||
|
||||
dp->d_fileno = i + FD_ROOT;
|
||||
dp->d_namlen = i + 1;
|
||||
dp->d_reclen = UIO_MX;
|
||||
bcopy("..", dp->d_name, dp->d_namlen);
|
||||
dp->d_name[i + 1] = '\0';
|
||||
dp->d_type = DT_DIR;
|
||||
break;
|
||||
default:
|
||||
if (fdp->fd_ofiles[fcnt] == NULL)
|
||||
goto done;
|
||||
|
||||
bzero((caddr_t) dp, UIO_MX);
|
||||
dp->d_namlen = sprintf(dp->d_name, "%d", fcnt);
|
||||
dp->d_reclen = UIO_MX;
|
||||
dp->d_type = DT_UNKNOWN;
|
||||
dp->d_fileno = i + FD_DESC;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* And ship to userland
|
||||
*/
|
||||
error = uiomove((caddr_t) dp, UIO_MX, uio);
|
||||
if (error)
|
||||
break;
|
||||
i++;
|
||||
fcnt++;
|
||||
}
|
||||
|
||||
done:
|
||||
uio->uio_offset = i * UIO_MX;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_poll(ap)
|
||||
struct vop_poll_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_events;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
return seltrue(0, ap->a_events, ap->a_p);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
/*
|
||||
* Clear out the v_type field to avoid
|
||||
* nasty things happening in vgone().
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, ap->a_p);
|
||||
vp->v_type = VNON;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct fdescnode *fd = VTOFDESC(vp);
|
||||
|
||||
LIST_REMOVE(fd, fd_hash);
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a /dev/fd vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fdesc_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, fdesc vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* /dev/fd "should never get here" operation
|
||||
*/
|
||||
static int
|
||||
fdesc_badop()
|
||||
{
|
||||
|
||||
panic("fdesc: bad op");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *) vop_null },
|
||||
{ &vop_getattr_desc, (vop_t *) fdesc_getattr },
|
||||
{ &vop_inactive_desc, (vop_t *) fdesc_inactive },
|
||||
{ &vop_lookup_desc, (vop_t *) fdesc_lookup },
|
||||
{ &vop_open_desc, (vop_t *) fdesc_open },
|
||||
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
|
||||
{ &vop_poll_desc, (vop_t *) fdesc_poll },
|
||||
{ &vop_print_desc, (vop_t *) fdesc_print },
|
||||
{ &vop_readdir_desc, (vop_t *) fdesc_readdir },
|
||||
{ &vop_reclaim_desc, (vop_t *) fdesc_reclaim },
|
||||
{ &vop_setattr_desc, (vop_t *) fdesc_setattr },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc fdesc_vnodeop_opv_desc =
|
||||
{ &fdesc_vnodeop_p, fdesc_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(fdesc_vnodeop_opv_desc);
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fifo.h 8.6 (Berkeley) 5/21/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
extern vop_t **fifo_vnodeop_p;
|
||||
|
||||
/*
|
||||
* Prototypes for fifo operations on vnodes.
|
||||
*/
|
||||
int fifo_vnoperate __P((struct vop_generic_args *));
|
||||
int fifo_printinfo __P((struct vnode *));
|
||||
|
@ -1,587 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1990, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/un.h>
|
||||
#include <miscfs/fifofs/fifo.h>
|
||||
|
||||
/*
|
||||
* This structure is associated with the FIFO vnode and stores
|
||||
* the state associated with the FIFO.
|
||||
*/
|
||||
struct fifoinfo {
|
||||
struct socket *fi_readsock;
|
||||
struct socket *fi_writesock;
|
||||
long fi_readers;
|
||||
long fi_writers;
|
||||
};
|
||||
|
||||
static int fifo_badop __P((void));
|
||||
static int fifo_print __P((struct vop_print_args *));
|
||||
static int fifo_lookup __P((struct vop_lookup_args *));
|
||||
static int fifo_open __P((struct vop_open_args *));
|
||||
static int fifo_close __P((struct vop_close_args *));
|
||||
static int fifo_read __P((struct vop_read_args *));
|
||||
static int fifo_write __P((struct vop_write_args *));
|
||||
static int fifo_ioctl __P((struct vop_ioctl_args *));
|
||||
static int fifo_poll __P((struct vop_poll_args *));
|
||||
static int fifo_kqfilter __P((struct vop_kqfilter_args *));
|
||||
static int fifo_pathconf __P((struct vop_pathconf_args *));
|
||||
static int fifo_advlock __P((struct vop_advlock_args *));
|
||||
|
||||
static void filt_fifordetach(struct knote *kn);
|
||||
static int filt_fiforead(struct knote *kn, long hint);
|
||||
static void filt_fifowdetach(struct knote *kn);
|
||||
static int filt_fifowrite(struct knote *kn, long hint);
|
||||
|
||||
static struct filterops fiforead_filtops =
|
||||
{ 1, NULL, filt_fifordetach, filt_fiforead };
|
||||
static struct filterops fifowrite_filtops =
|
||||
{ 1, NULL, filt_fifowdetach, filt_fifowrite };
|
||||
|
||||
vop_t **fifo_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_advlock_desc, (vop_t *) fifo_advlock },
|
||||
{ &vop_close_desc, (vop_t *) fifo_close },
|
||||
{ &vop_create_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_getattr_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
|
||||
{ &vop_ioctl_desc, (vop_t *) fifo_ioctl },
|
||||
{ &vop_lease_desc, (vop_t *) vop_null },
|
||||
{ &vop_link_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_lookup_desc, (vop_t *) fifo_lookup },
|
||||
{ &vop_mkdir_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_mknod_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_open_desc, (vop_t *) fifo_open },
|
||||
{ &vop_pathconf_desc, (vop_t *) fifo_pathconf },
|
||||
{ &vop_poll_desc, (vop_t *) fifo_poll },
|
||||
{ &vop_kqfilter_desc, (vop_t *) fifo_kqfilter },
|
||||
{ &vop_print_desc, (vop_t *) fifo_print },
|
||||
{ &vop_read_desc, (vop_t *) fifo_read },
|
||||
{ &vop_readdir_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_readlink_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_reallocblks_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_reclaim_desc, (vop_t *) vop_null },
|
||||
{ &vop_remove_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_rename_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_rmdir_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_setattr_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_symlink_desc, (vop_t *) fifo_badop },
|
||||
{ &vop_write_desc, (vop_t *) fifo_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc fifo_vnodeop_opv_desc =
|
||||
{ &fifo_vnodeop_p, fifo_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(fifo_vnodeop_opv_desc);
|
||||
|
||||
int
|
||||
fifo_vnoperate(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* Trivial lookup routine that always fails.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
*ap->a_vpp = NULL;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open called to set up a new instance of a fifo or
|
||||
* to find an active instance of a fifo.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct fifoinfo *fip;
|
||||
struct proc *p = ap->a_p;
|
||||
struct socket *rso, *wso;
|
||||
int error;
|
||||
|
||||
if ((fip = vp->v_fifoinfo) == NULL) {
|
||||
MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
|
||||
vp->v_fifoinfo = fip;
|
||||
error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p);
|
||||
if (error) {
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_readsock = rso;
|
||||
error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p);
|
||||
if (error) {
|
||||
(void)soclose(rso);
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_writesock = wso;
|
||||
error = unp_connect2(wso, rso);
|
||||
if (error) {
|
||||
(void)soclose(wso);
|
||||
(void)soclose(rso);
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_readers = fip->fi_writers = 0;
|
||||
wso->so_snd.sb_lowat = PIPE_BUF;
|
||||
rso->so_state |= SS_CANTRCVMORE;
|
||||
}
|
||||
if (ap->a_mode & FREAD) {
|
||||
fip->fi_readers++;
|
||||
if (fip->fi_readers == 1) {
|
||||
fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
|
||||
if (fip->fi_writers > 0)
|
||||
wakeup((caddr_t)&fip->fi_writers);
|
||||
}
|
||||
}
|
||||
if (ap->a_mode & FWRITE) {
|
||||
fip->fi_writers++;
|
||||
if (fip->fi_writers == 1) {
|
||||
fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
|
||||
if (fip->fi_readers > 0)
|
||||
wakeup((caddr_t)&fip->fi_readers);
|
||||
}
|
||||
}
|
||||
if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
|
||||
while (fip->fi_writers == 0) {
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = tsleep((caddr_t)&fip->fi_readers,
|
||||
PCATCH | PSOCK, "fifoor", 0);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (ap->a_mode & FWRITE) {
|
||||
if (ap->a_mode & O_NONBLOCK) {
|
||||
if (fip->fi_readers == 0) {
|
||||
error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
while (fip->fi_readers == 0) {
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = tsleep((caddr_t)&fip->fi_writers,
|
||||
PCATCH | PSOCK, "fifoow", 0);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
bad:
|
||||
VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
struct proc *p = uio->uio_procp;
|
||||
int error, startresid;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
panic("fifo_read mode");
|
||||
#endif
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
rso->so_state |= SS_NBIO;
|
||||
startresid = uio->uio_resid;
|
||||
VOP_UNLOCK(ap->a_vp, 0, p);
|
||||
error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
|
||||
(struct mbuf **)0, (int *)0);
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
rso->so_state &= ~SS_NBIO;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
struct proc *p = ap->a_uio->uio_procp;
|
||||
int error;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ap->a_uio->uio_rw != UIO_WRITE)
|
||||
panic("fifo_write mode");
|
||||
#endif
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
wso->so_state |= SS_NBIO;
|
||||
VOP_UNLOCK(ap->a_vp, 0, p);
|
||||
error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0,
|
||||
(struct mbuf *)0, 0, p);
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
wso->so_state &= ~SS_NBIO;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct file filetmp;
|
||||
int error;
|
||||
|
||||
if (ap->a_command == FIONBIO)
|
||||
return (0);
|
||||
if (ap->a_fflag & FREAD) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (ap->a_fflag & FWRITE) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_kqfilter(ap)
|
||||
struct vop_kqfilter_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct knote *a_kn;
|
||||
} */ *ap;
|
||||
{
|
||||
struct socket *so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
struct sockbuf *sb;
|
||||
|
||||
switch (ap->a_kn->kn_filter) {
|
||||
case EVFILT_READ:
|
||||
ap->a_kn->kn_fop = &fiforead_filtops;
|
||||
sb = &so->so_rcv;
|
||||
break;
|
||||
case EVFILT_WRITE:
|
||||
ap->a_kn->kn_fop = &fifowrite_filtops;
|
||||
sb = &so->so_snd;
|
||||
break;
|
||||
default:
|
||||
return (1);
|
||||
}
|
||||
|
||||
ap->a_kn->kn_hook = (caddr_t)so;
|
||||
|
||||
SLIST_INSERT_HEAD(&sb->sb_sel.si_note, ap->a_kn, kn_selnext);
|
||||
sb->sb_flags |= SB_KNOTE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
filt_fifordetach(struct knote *kn)
|
||||
{
|
||||
struct socket *so = (struct socket *)kn->kn_hook;
|
||||
|
||||
SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
|
||||
if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
|
||||
so->so_rcv.sb_flags &= ~SB_KNOTE;
|
||||
}
|
||||
|
||||
static int
|
||||
filt_fiforead(struct knote *kn, long hint)
|
||||
{
|
||||
struct socket *so = (struct socket *)kn->kn_hook;
|
||||
|
||||
kn->kn_data = so->so_rcv.sb_cc;
|
||||
if (so->so_state & SS_CANTRCVMORE) {
|
||||
kn->kn_flags |= EV_EOF;
|
||||
return (1);
|
||||
}
|
||||
kn->kn_flags &= ~EV_EOF;
|
||||
return (kn->kn_data > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
filt_fifowdetach(struct knote *kn)
|
||||
{
|
||||
struct socket *so = (struct socket *)kn->kn_hook;
|
||||
|
||||
SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
|
||||
if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
|
||||
so->so_snd.sb_flags &= ~SB_KNOTE;
|
||||
}
|
||||
|
||||
static int
|
||||
filt_fifowrite(struct knote *kn, long hint)
|
||||
{
|
||||
struct socket *so = (struct socket *)kn->kn_hook;
|
||||
|
||||
kn->kn_data = sbspace(&so->so_snd);
|
||||
if (so->so_state & SS_CANTSENDMORE) {
|
||||
kn->kn_flags |= EV_EOF;
|
||||
return (1);
|
||||
}
|
||||
kn->kn_flags &= ~EV_EOF;
|
||||
return (kn->kn_data >= so->so_snd.sb_lowat);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_poll(ap)
|
||||
struct vop_poll_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_events;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct file filetmp;
|
||||
int revents = 0;
|
||||
|
||||
if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
if (filetmp.f_data)
|
||||
revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
|
||||
ap->a_p);
|
||||
}
|
||||
if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
if (filetmp.f_data)
|
||||
revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
|
||||
ap->a_p);
|
||||
}
|
||||
return (revents);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device close routine
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct fifoinfo *fip = vp->v_fifoinfo;
|
||||
int error1, error2;
|
||||
|
||||
if (ap->a_fflag & FREAD) {
|
||||
fip->fi_readers--;
|
||||
if (fip->fi_readers == 0)
|
||||
socantsendmore(fip->fi_writesock);
|
||||
}
|
||||
if (ap->a_fflag & FWRITE) {
|
||||
fip->fi_writers--;
|
||||
if (fip->fi_writers == 0)
|
||||
socantrcvmore(fip->fi_readsock);
|
||||
}
|
||||
if (vp->v_usecount > 1)
|
||||
return (0);
|
||||
error1 = soclose(fip->fi_readsock);
|
||||
error2 = soclose(fip->fi_writesock);
|
||||
FREE(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
if (error1)
|
||||
return (error1);
|
||||
return (error2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print out internal contents of a fifo vnode.
|
||||
*/
|
||||
int
|
||||
fifo_printinfo(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
register struct fifoinfo *fip = vp->v_fifoinfo;
|
||||
|
||||
printf(", fifo with %ld readers and %ld writers",
|
||||
fip->fi_readers, fip->fi_writers);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a fifo vnode.
|
||||
*/
|
||||
static int
|
||||
fifo_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON");
|
||||
fifo_printinfo(ap->a_vp);
|
||||
printf("\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to fifo's.
|
||||
*/
|
||||
int
|
||||
fifo_pathconf(ap)
|
||||
struct vop_pathconf_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_name;
|
||||
int *a_retval;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
switch (ap->a_name) {
|
||||
case _PC_LINK_MAX:
|
||||
*ap->a_retval = LINK_MAX;
|
||||
return (0);
|
||||
case _PC_PIPE_BUF:
|
||||
*ap->a_retval = PIPE_BUF;
|
||||
return (0);
|
||||
case _PC_CHOWN_RESTRICTED:
|
||||
*ap->a_retval = 1;
|
||||
return (0);
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Fifo advisory byte-level locks.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
fifo_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
caddr_t a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fifo bad operation
|
||||
*/
|
||||
static int
|
||||
fifo_badop()
|
||||
{
|
||||
|
||||
panic("fifo_badop called");
|
||||
/* NOTREACHED */
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)null.h 8.3 (Berkeley) 8/20/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct null_args {
|
||||
char *target; /* Target of loopback */
|
||||
};
|
||||
|
||||
struct null_mount {
|
||||
struct mount *nullm_vfs;
|
||||
struct vnode *nullm_rootvp; /* Reference to root null_node */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* A cache of vnode references
|
||||
*/
|
||||
struct null_node {
|
||||
LIST_ENTRY(null_node) null_hash; /* Hash list */
|
||||
struct vnode *null_lowervp; /* VREFed once */
|
||||
struct vnode *null_vnode; /* Back pointer */
|
||||
};
|
||||
|
||||
#define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data))
|
||||
#define VTONULL(vp) ((struct null_node *)(vp)->v_data)
|
||||
#define NULLTOV(xp) ((xp)->null_vnode)
|
||||
|
||||
int nullfs_init(struct vfsconf *vfsp);
|
||||
int nullfs_uninit(struct vfsconf *vfsp);
|
||||
int null_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp);
|
||||
int null_bypass(struct vop_generic_args *ap);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno);
|
||||
#define NULLVPTOLOWERVP(vp) null_checkvp((vp), __FILE__, __LINE__)
|
||||
#else
|
||||
#define NULLVPTOLOWERVP(vp) (VTONULL(vp)->null_lowervp)
|
||||
#endif
|
||||
|
||||
extern vop_t **null_vnodeop_p;
|
||||
extern struct lock null_hashlock;
|
||||
|
||||
#ifdef MALLOC_DECLARE
|
||||
MALLOC_DECLARE(M_NULLFSNODE);
|
||||
#endif
|
||||
|
||||
#ifdef NULLFS_DEBUG
|
||||
#define NULLFSDEBUG(format, args...) printf(format ,## args)
|
||||
#else
|
||||
#define NULLFSDEBUG(format, args...)
|
||||
#endif /* NULLFS_DEBUG */
|
||||
|
||||
#endif /* _KERNEL */
|
@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)null_subr.c 8.7 (Berkeley) 5/14/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NNULLNODECACHE 16
|
||||
|
||||
/*
|
||||
* Null layer cache:
|
||||
* Each cache entry holds a reference to the lower vnode
|
||||
* along with a pointer to the alias vnode. When an
|
||||
* entry is added the lower vnode is VREF'd. When the
|
||||
* alias is removed the lower vnode is vrele'd.
|
||||
*/
|
||||
|
||||
#define NULL_NHASH(vp) \
|
||||
(&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash])
|
||||
|
||||
static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
|
||||
static u_long null_node_hash;
|
||||
struct lock null_hashlock;
|
||||
|
||||
static MALLOC_DEFINE(M_NULLFSHASH, "NULLFS hash", "NULLFS hash table");
|
||||
MALLOC_DEFINE(M_NULLFSNODE, "NULLFS node", "NULLFS vnode private part");
|
||||
|
||||
static int null_node_alloc(struct mount *mp, struct vnode *lowervp,
|
||||
struct vnode **vpp);
|
||||
static struct vnode *
|
||||
null_node_find(struct mount *mp, struct vnode *lowervp);
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
int
|
||||
nullfs_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
NULLFSDEBUG("nullfs_init\n"); /* printed during system boot */
|
||||
null_node_hashtbl = hashinit(NNULLNODECACHE, M_NULLFSHASH, &null_node_hash);
|
||||
lockinit(&null_hashlock, PVFS, "nullhs", 0, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_uninit(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
if (null_node_hashtbl) {
|
||||
lockdestroy(&null_hashlock);
|
||||
free(null_node_hashtbl, M_NULLFSHASH);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a VREF'ed alias for lower vnode if already exists, else 0.
|
||||
* Lower vnode should be locked on entry and will be left locked on exit.
|
||||
*/
|
||||
static struct vnode *
|
||||
null_node_find(mp, lowervp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct null_node_hashhead *hd;
|
||||
struct null_node *a;
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Find hash base, and then search the (two-way) linked
|
||||
* list looking for a null_node structure which is referencing
|
||||
* the lower vnode. If found, the increment the null_node
|
||||
* reference count (but NOT the lower vnode's VREF counter).
|
||||
*/
|
||||
hd = NULL_NHASH(lowervp);
|
||||
loop:
|
||||
lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
|
||||
LIST_FOREACH(a, hd, null_hash) {
|
||||
if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
|
||||
vp = NULLTOV(a);
|
||||
lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
|
||||
/*
|
||||
* We need vget for the VXLOCK
|
||||
* stuff, but we don't want to lock
|
||||
* the lower node.
|
||||
*/
|
||||
if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
|
||||
printf ("null_node_find: vget failed.\n");
|
||||
goto loop;
|
||||
};
|
||||
/*
|
||||
* Now we got both vnodes locked, so release the
|
||||
* lower one.
|
||||
*/
|
||||
VOP_UNLOCK(lowervp, 0, p);
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
|
||||
|
||||
return NULLVP;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make a new null_node node.
|
||||
* Vp is the alias vnode, lofsvp is the lower vnode.
|
||||
* Maintain a reference to (lowervp).
|
||||
*/
|
||||
static int
|
||||
null_node_alloc(mp, lowervp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct null_node_hashhead *hd;
|
||||
struct null_node *xp;
|
||||
struct vnode *othervp, *vp;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Do the MALLOC before the getnewvnode since doing so afterward
|
||||
* might cause a bogus v_data pointer to get dereferenced
|
||||
* elsewhere if MALLOC should block.
|
||||
*/
|
||||
MALLOC(xp, struct null_node *, sizeof(struct null_node),
|
||||
M_NULLFSNODE, M_WAITOK);
|
||||
|
||||
error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp);
|
||||
if (error) {
|
||||
FREE(xp, M_NULLFSNODE);
|
||||
return (error);
|
||||
}
|
||||
vp = *vpp;
|
||||
|
||||
vp->v_type = lowervp->v_type;
|
||||
xp->null_vnode = vp;
|
||||
vp->v_data = xp;
|
||||
xp->null_lowervp = lowervp;
|
||||
/*
|
||||
* Before we insert our new node onto the hash chains,
|
||||
* check to see if someone else has beaten us to it.
|
||||
* (We could have slept in MALLOC.)
|
||||
*/
|
||||
othervp = null_node_find(mp, lowervp);
|
||||
if (othervp) {
|
||||
vp->v_data = NULL;
|
||||
FREE(xp, M_NULLFSNODE);
|
||||
vp->v_type = VBAD; /* node is discarded */
|
||||
vrele(vp);
|
||||
*vpp = othervp;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* From NetBSD:
|
||||
* Now lock the new node. We rely on the fact that we were passed
|
||||
* a locked vnode. If the lower node is exporting a struct lock
|
||||
* (v_vnlock != NULL) then we just set the upper v_vnlock to the
|
||||
* lower one, and both are now locked. If the lower node is exporting
|
||||
* NULL, then we copy that up and manually lock the new vnode.
|
||||
*/
|
||||
|
||||
lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
|
||||
vp->v_vnlock = lowervp->v_vnlock;
|
||||
error = VOP_LOCK(vp, LK_EXCLUSIVE | LK_THISLAYER, p);
|
||||
if (error)
|
||||
panic("null_node_alloc: can't lock new vnode\n");
|
||||
|
||||
VREF(lowervp);
|
||||
hd = NULL_NHASH(lowervp);
|
||||
LIST_INSERT_HEAD(hd, xp, null_hash);
|
||||
lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to find an existing null_node vnode refering to the given underlying
|
||||
* vnode (which should be locked). If no vnode found, create a new null_node
|
||||
* vnode which contains a reference to the lower vnode.
|
||||
*/
|
||||
int
|
||||
null_node_create(mp, lowervp, newvpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **newvpp;
|
||||
{
|
||||
struct vnode *aliasvp;
|
||||
|
||||
aliasvp = null_node_find(mp, lowervp);
|
||||
if (aliasvp) {
|
||||
/*
|
||||
* null_node_find has taken another reference
|
||||
* to the alias vnode.
|
||||
*/
|
||||
vrele(lowervp);
|
||||
#ifdef NULLFS_DEBUG
|
||||
vprint("null_node_create: exists", aliasvp);
|
||||
#endif
|
||||
} else {
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Get new vnode.
|
||||
*/
|
||||
NULLFSDEBUG("null_node_create: create new alias vnode\n");
|
||||
|
||||
/*
|
||||
* Make new vnode reference the null_node.
|
||||
*/
|
||||
error = null_node_alloc(mp, lowervp, &aliasvp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* aliasvp is already VREF'd by getnewvnode()
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (lowervp->v_usecount < 1) {
|
||||
/* Should never happen... */
|
||||
vprint ("null_node_create: alias ", aliasvp);
|
||||
vprint ("null_node_create: lower ", lowervp);
|
||||
panic ("null_node_create: lower has 0 usecount.");
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NULLFS_DEBUG
|
||||
vprint("null_node_create: alias", aliasvp);
|
||||
vprint("null_node_create: lower", lowervp);
|
||||
#endif
|
||||
|
||||
*newvpp = aliasvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#ifdef DDB
|
||||
#define null_checkvp_barrier 1
|
||||
#else
|
||||
#define null_checkvp_barrier 0
|
||||
#endif
|
||||
|
||||
struct vnode *
|
||||
null_checkvp(vp, fil, lno)
|
||||
struct vnode *vp;
|
||||
char *fil;
|
||||
int lno;
|
||||
{
|
||||
struct null_node *a = VTONULL(vp);
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Can't do this check because vop_reclaim runs
|
||||
* with a funny vop vector.
|
||||
*/
|
||||
if (vp->v_op != null_vnodeop_p) {
|
||||
printf ("null_checkvp: on non-null-node\n");
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("null_checkvp");
|
||||
};
|
||||
#endif
|
||||
if (a->null_lowervp == NULLVP) {
|
||||
/* Should never happen */
|
||||
int i; u_long *p;
|
||||
printf("vp = %p, ZERO ptr\n", (void *)vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %lx", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("null_checkvp");
|
||||
}
|
||||
if (a->null_lowervp->v_usecount < 1) {
|
||||
int i; u_long *p;
|
||||
printf("vp = %p, unref'ed lowervp\n", (void *)vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %lx", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic ("null with unref'ed lowervp");
|
||||
};
|
||||
#ifdef notyet
|
||||
printf("null %x/%d -> %x/%d [%s, %d]\n",
|
||||
NULLTOV(a), NULLTOV(a)->v_usecount,
|
||||
a->null_lowervp, a->null_lowervp->v_usecount,
|
||||
fil, lno);
|
||||
#endif
|
||||
return a->null_lowervp;
|
||||
}
|
||||
#endif
|
@ -1,425 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
|
||||
*
|
||||
* @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Null Layer
|
||||
* (See null_vnops.c for a description of what this does.)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
|
||||
|
||||
static int nullfs_fhtovp(struct mount *mp, struct fid *fidp,
|
||||
struct vnode **vpp);
|
||||
static int nullfs_checkexp(struct mount *mp, struct sockaddr *nam,
|
||||
int *extflagsp, struct ucred **credanonp);
|
||||
static int nullfs_mount(struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p);
|
||||
static int nullfs_quotactl(struct mount *mp, int cmd, uid_t uid,
|
||||
caddr_t arg, struct proc *p);
|
||||
static int nullfs_root(struct mount *mp, struct vnode **vpp);
|
||||
static int nullfs_start(struct mount *mp, int flags, struct proc *p);
|
||||
static int nullfs_statfs(struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p);
|
||||
static int nullfs_sync(struct mount *mp, int waitfor,
|
||||
struct ucred *cred, struct proc *p);
|
||||
static int nullfs_unmount(struct mount *mp, int mntflags, struct proc *p);
|
||||
static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
|
||||
static int nullfs_vptofh(struct vnode *vp, struct fid *fhp);
|
||||
static int nullfs_extattrctl(struct mount *mp, int cmd,
|
||||
struct vnode *filename_vp,
|
||||
int namespace, const char *attrname,
|
||||
struct proc *p);
|
||||
|
||||
/*
|
||||
* Mount null layer
|
||||
*/
|
||||
static int
|
||||
nullfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct null_args args;
|
||||
struct vnode *lowerrootvp, *vp;
|
||||
struct vnode *nullm_rootvp;
|
||||
struct null_mount *xmp;
|
||||
u_int size;
|
||||
int isvnunlocked = 0;
|
||||
|
||||
NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
return (EOPNOTSUPP);
|
||||
/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Unlock lower node to avoid deadlock.
|
||||
* (XXX) VOP_ISLOCKED is needed?
|
||||
*/
|
||||
if ((mp->mnt_vnodecovered->v_op == null_vnodeop_p) &&
|
||||
VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) {
|
||||
VOP_UNLOCK(mp->mnt_vnodecovered, 0, p);
|
||||
isvnunlocked = 1;
|
||||
}
|
||||
/*
|
||||
* Find lower node
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
error = namei(ndp);
|
||||
/*
|
||||
* Re-lock vnode.
|
||||
*/
|
||||
if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
|
||||
vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
|
||||
/*
|
||||
* Sanity check on lower vnode
|
||||
*/
|
||||
lowerrootvp = ndp->ni_vp;
|
||||
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULLVP;
|
||||
|
||||
/*
|
||||
* Check multi null mount to avoid `lock against myself' panic.
|
||||
*/
|
||||
if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) {
|
||||
NULLFSDEBUG("nullfs_mount: multi null mount?\n");
|
||||
vput(lowerrootvp);
|
||||
return (EDEADLK);
|
||||
}
|
||||
|
||||
xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
|
||||
M_NULLFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
/*
|
||||
* Save reference to underlying FS
|
||||
*/
|
||||
xmp->nullm_vfs = lowerrootvp->v_mount;
|
||||
|
||||
/*
|
||||
* Save reference. Each mount also holds
|
||||
* a reference on the root vnode.
|
||||
*/
|
||||
error = null_node_create(mp, lowerrootvp, &vp);
|
||||
/*
|
||||
* Unlock the node (either the lower or the alias)
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
/*
|
||||
* Make sure the node alias worked
|
||||
*/
|
||||
if (error) {
|
||||
vrele(lowerrootvp);
|
||||
free(xmp, M_NULLFSMNT); /* XXX */
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep a held reference to the root vnode.
|
||||
* It is vrele'd in nullfs_unmount.
|
||||
*/
|
||||
nullm_rootvp = vp;
|
||||
nullm_rootvp->v_flag |= VROOT;
|
||||
xmp->nullm_rootvp = nullm_rootvp;
|
||||
if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) xmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
|
||||
&size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
(void)nullfs_statfs(mp, &mp->mnt_stat, p);
|
||||
NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS start. Nothing needed here - the start routine
|
||||
* on the underlying filesystem will have been called
|
||||
* when that filesystem was mounted.
|
||||
*/
|
||||
static int
|
||||
nullfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to null layer
|
||||
*/
|
||||
static int
|
||||
nullfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
void *mntdata;
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/* There is 1 extra root vnode reference (nullm_rootvp). */
|
||||
error = vflush(mp, 1, flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Finally, throw away the null_mount structure
|
||||
*/
|
||||
mntdata = mp->mnt_data;
|
||||
mp->mnt_data = 0;
|
||||
free(mntdata, M_NULLFSMNT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
|
||||
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
|
||||
(void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
|
||||
VREF(vp);
|
||||
|
||||
#ifdef NULLFS_DEBUG
|
||||
if (VOP_ISLOCKED(vp, NULL)) {
|
||||
Debugger("root vnode is locked.\n");
|
||||
vrele(vp);
|
||||
return (EDEADLK);
|
||||
}
|
||||
#endif
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_quotactl(mp, cmd, uid, arg, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
caddr_t arg;
|
||||
struct proc *p;
|
||||
{
|
||||
return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct statfs mstat;
|
||||
|
||||
NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
|
||||
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
|
||||
(void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_sync(mp, waitfor, cred, p)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
{
|
||||
/*
|
||||
* XXX - Assumes no data cached at null layer.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_vget(mp, ino, vpp)
|
||||
struct mount *mp;
|
||||
ino_t ino;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
int error;
|
||||
error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (null_node_create(mp, *vpp, vpp));
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_fhtovp(mp, fidp, vpp)
|
||||
struct mount *mp;
|
||||
struct fid *fidp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
int error;
|
||||
error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (null_node_create(mp, *vpp, vpp));
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_checkexp(mp, nam, extflagsp, credanonp)
|
||||
struct mount *mp;
|
||||
struct sockaddr *nam;
|
||||
int *extflagsp;
|
||||
struct ucred **credanonp;
|
||||
{
|
||||
|
||||
return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam,
|
||||
extflagsp, credanonp);
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_vptofh(vp, fhp)
|
||||
struct vnode *vp;
|
||||
struct fid *fhp;
|
||||
{
|
||||
return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
|
||||
}
|
||||
|
||||
static int
|
||||
nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
struct vnode *filename_vp;
|
||||
int namespace;
|
||||
const char *attrname;
|
||||
struct proc *p;
|
||||
{
|
||||
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp,
|
||||
namespace, attrname, p);
|
||||
}
|
||||
|
||||
|
||||
static struct vfsops null_vfsops = {
|
||||
nullfs_mount,
|
||||
nullfs_start,
|
||||
nullfs_unmount,
|
||||
nullfs_root,
|
||||
nullfs_quotactl,
|
||||
nullfs_statfs,
|
||||
nullfs_sync,
|
||||
nullfs_vget,
|
||||
nullfs_fhtovp,
|
||||
nullfs_checkexp,
|
||||
nullfs_vptofh,
|
||||
nullfs_init,
|
||||
nullfs_uninit,
|
||||
nullfs_extattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK);
|
@ -1,852 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* John Heidemann of the UCLA Ficus project.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)null_vnops.c 8.6 (Berkeley) 5/27/95
|
||||
*
|
||||
* Ancestors:
|
||||
* @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92
|
||||
* ...and...
|
||||
* @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Null Layer
|
||||
*
|
||||
* (See mount_null(8) for more information.)
|
||||
*
|
||||
* The null layer duplicates a portion of the file system
|
||||
* name space under a new name. In this respect, it is
|
||||
* similar to the loopback file system. It differs from
|
||||
* the loopback fs in two respects: it is implemented using
|
||||
* a stackable layers techniques, and its "null-node"s stack above
|
||||
* all lower-layer vnodes, not just over directory vnodes.
|
||||
*
|
||||
* The null layer has two purposes. First, it serves as a demonstration
|
||||
* of layering by proving a layer which does nothing. (It actually
|
||||
* does everything the loopback file system does, which is slightly
|
||||
* more than nothing.) Second, the null layer can serve as a prototype
|
||||
* layer. Since it provides all necessary layer framework,
|
||||
* new file system layers can be created very easily be starting
|
||||
* with a null layer.
|
||||
*
|
||||
* The remainder of this man page examines the null layer as a basis
|
||||
* for constructing new layers.
|
||||
*
|
||||
*
|
||||
* INSTANTIATING NEW NULL LAYERS
|
||||
*
|
||||
* New null layers are created with mount_null(8).
|
||||
* Mount_null(8) takes two arguments, the pathname
|
||||
* of the lower vfs (target-pn) and the pathname where the null
|
||||
* layer will appear in the namespace (alias-pn). After
|
||||
* the null layer is put into place, the contents
|
||||
* of target-pn subtree will be aliased under alias-pn.
|
||||
*
|
||||
*
|
||||
* OPERATION OF A NULL LAYER
|
||||
*
|
||||
* The null layer is the minimum file system layer,
|
||||
* simply bypassing all possible operations to the lower layer
|
||||
* for processing there. The majority of its activity centers
|
||||
* on the bypass routine, through which nearly all vnode operations
|
||||
* pass.
|
||||
*
|
||||
* The bypass routine accepts arbitrary vnode operations for
|
||||
* handling by the lower layer. It begins by examing vnode
|
||||
* operation arguments and replacing any null-nodes by their
|
||||
* lower-layer equivlants. It then invokes the operation
|
||||
* on the lower layer. Finally, it replaces the null-nodes
|
||||
* in the arguments and, if a vnode is return by the operation,
|
||||
* stacks a null-node on top of the returned vnode.
|
||||
*
|
||||
* Although bypass handles most operations, vop_getattr, vop_lock,
|
||||
* vop_unlock, vop_inactive, vop_reclaim, and vop_print are not
|
||||
* bypassed. Vop_getattr must change the fsid being returned.
|
||||
* Vop_lock and vop_unlock must handle any locking for the
|
||||
* current vnode as well as pass the lock request down.
|
||||
* Vop_inactive and vop_reclaim are not bypassed so that
|
||||
* they can handle freeing null-layer specific data. Vop_print
|
||||
* is not bypassed to avoid excessive debugging information.
|
||||
* Also, certain vnode operations change the locking state within
|
||||
* the operation (create, mknod, remove, link, rename, mkdir, rmdir,
|
||||
* and symlink). Ideally these operations should not change the
|
||||
* lock state, but should be changed to let the caller of the
|
||||
* function unlock them. Otherwise all intermediate vnode layers
|
||||
* (such as union, umapfs, etc) must catch these functions to do
|
||||
* the necessary locking at their layer.
|
||||
*
|
||||
*
|
||||
* INSTANTIATING VNODE STACKS
|
||||
*
|
||||
* Mounting associates the null layer with a lower layer,
|
||||
* effect stacking two VFSes. Vnode stacks are instead
|
||||
* created on demand as files are accessed.
|
||||
*
|
||||
* The initial mount creates a single vnode stack for the
|
||||
* root of the new null layer. All other vnode stacks
|
||||
* are created as a result of vnode operations on
|
||||
* this or other null vnode stacks.
|
||||
*
|
||||
* New vnode stacks come into existance as a result of
|
||||
* an operation which returns a vnode.
|
||||
* The bypass routine stacks a null-node above the new
|
||||
* vnode before returning it to the caller.
|
||||
*
|
||||
* For example, imagine mounting a null layer with
|
||||
* "mount_null /usr/include /dev/layer/null".
|
||||
* Changing directory to /dev/layer/null will assign
|
||||
* the root null-node (which was created when the null layer was mounted).
|
||||
* Now consider opening "sys". A vop_lookup would be
|
||||
* done on the root null-node. This operation would bypass through
|
||||
* to the lower layer which would return a vnode representing
|
||||
* the UFS "sys". Null_bypass then builds a null-node
|
||||
* aliasing the UFS "sys" and returns this to the caller.
|
||||
* Later operations on the null-node "sys" will repeat this
|
||||
* process when constructing other vnode stacks.
|
||||
*
|
||||
*
|
||||
* CREATING OTHER FILE SYSTEM LAYERS
|
||||
*
|
||||
* One of the easiest ways to construct new file system layers is to make
|
||||
* a copy of the null layer, rename all files and variables, and
|
||||
* then begin modifing the copy. Sed can be used to easily rename
|
||||
* all variables.
|
||||
*
|
||||
* The umap layer is an example of a layer descended from the
|
||||
* null layer.
|
||||
*
|
||||
*
|
||||
* INVOKING OPERATIONS ON LOWER LAYERS
|
||||
*
|
||||
* There are two techniques to invoke operations on a lower layer
|
||||
* when the operation cannot be completely bypassed. Each method
|
||||
* is appropriate in different situations. In both cases,
|
||||
* it is the responsibility of the aliasing layer to make
|
||||
* the operation arguments "correct" for the lower layer
|
||||
* by mapping an vnode arguments to the lower layer.
|
||||
*
|
||||
* The first approach is to call the aliasing layer's bypass routine.
|
||||
* This method is most suitable when you wish to invoke the operation
|
||||
* currently being handled on the lower layer. It has the advantage
|
||||
* that the bypass routine already must do argument mapping.
|
||||
* An example of this is null_getattrs in the null layer.
|
||||
*
|
||||
* A second approach is to directly invoke vnode operations on
|
||||
* the lower layer with the VOP_OPERATIONNAME interface.
|
||||
* The advantage of this method is that it is easy to invoke
|
||||
* arbitrary operations on the lower layer. The disadvantage
|
||||
* is that vnode arguments must be manualy mapped.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vnode_pager.h>
|
||||
|
||||
static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
|
||||
SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW,
|
||||
&null_bug_bypass, 0, "");
|
||||
|
||||
static int null_access(struct vop_access_args *ap);
|
||||
static int null_createvobject(struct vop_createvobject_args *ap);
|
||||
static int null_destroyvobject(struct vop_destroyvobject_args *ap);
|
||||
static int null_getattr(struct vop_getattr_args *ap);
|
||||
static int null_getvobject(struct vop_getvobject_args *ap);
|
||||
static int null_inactive(struct vop_inactive_args *ap);
|
||||
static int null_islocked(struct vop_islocked_args *ap);
|
||||
static int null_lock(struct vop_lock_args *ap);
|
||||
static int null_lookup(struct vop_lookup_args *ap);
|
||||
static int null_open(struct vop_open_args *ap);
|
||||
static int null_print(struct vop_print_args *ap);
|
||||
static int null_reclaim(struct vop_reclaim_args *ap);
|
||||
static int null_rename(struct vop_rename_args *ap);
|
||||
static int null_setattr(struct vop_setattr_args *ap);
|
||||
static int null_unlock(struct vop_unlock_args *ap);
|
||||
|
||||
/*
|
||||
* This is the 10-Apr-92 bypass routine.
|
||||
* This version has been optimized for speed, throwing away some
|
||||
* safety checks. It should still always work, but it's not as
|
||||
* robust to programmer errors.
|
||||
*
|
||||
* In general, we map all vnodes going down and unmap them on the way back.
|
||||
* As an exception to this, vnodes can be marked "unmapped" by setting
|
||||
* the Nth bit in operation's vdesc_flags.
|
||||
*
|
||||
* Also, some BSD vnode operations have the side effect of vrele'ing
|
||||
* their arguments. With stacking, the reference counts are held
|
||||
* by the upper node, not the lower one, so we must handle these
|
||||
* side-effects here. This is not of concern in Sun-derived systems
|
||||
* since there are no such side-effects.
|
||||
*
|
||||
* This makes the following assumptions:
|
||||
* - only one returned vpp
|
||||
* - no INOUT vpp's (Sun's vop_open has one of these)
|
||||
* - the vnode operation vector of the first vnode should be used
|
||||
* to determine what implementation of the op should be invoked
|
||||
* - all mapped vnodes are of our vnode-type (NEEDSWORK:
|
||||
* problems on rmdir'ing mount points and renaming?)
|
||||
*/
|
||||
int
|
||||
null_bypass(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode **this_vp_p;
|
||||
int error;
|
||||
struct vnode *old_vps[VDESC_MAX_VPS];
|
||||
struct vnode **vps_p[VDESC_MAX_VPS];
|
||||
struct vnode ***vppp;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
int reles, i;
|
||||
|
||||
if (null_bug_bypass)
|
||||
printf ("null_bypass: %s\n", descp->vdesc_name);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* We require at least one vp.
|
||||
*/
|
||||
if (descp->vdesc_vp_offsets == NULL ||
|
||||
descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
|
||||
panic ("null_bypass: no vp's in map");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Map the vnodes going in.
|
||||
* Later, we'll invoke the operation based on
|
||||
* the first mapped vnode's operation vector.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
vps_p[i] = this_vp_p =
|
||||
VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
|
||||
/*
|
||||
* We're not guaranteed that any but the first vnode
|
||||
* are of our type. Check for and don't map any
|
||||
* that aren't. (We must always map first vp or vclean fails.)
|
||||
*/
|
||||
if (i && (*this_vp_p == NULLVP ||
|
||||
(*this_vp_p)->v_op != null_vnodeop_p)) {
|
||||
old_vps[i] = NULLVP;
|
||||
} else {
|
||||
old_vps[i] = *this_vp_p;
|
||||
*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
|
||||
/*
|
||||
* XXX - Several operations have the side effect
|
||||
* of vrele'ing their vp's. We must account for
|
||||
* that. (This should go away in the future.)
|
||||
*/
|
||||
if (reles & VDESC_VP0_WILLRELE)
|
||||
VREF(*this_vp_p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the operation on the lower layer
|
||||
* with the modified argument structure.
|
||||
*/
|
||||
if (vps_p[0] && *vps_p[0])
|
||||
error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
|
||||
else {
|
||||
printf("null_bypass: no map for %s\n", descp->vdesc_name);
|
||||
error = EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maintain the illusion of call-by-value
|
||||
* by restoring vnodes in the argument structure
|
||||
* to their original value.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
if (old_vps[i]) {
|
||||
*(vps_p[i]) = old_vps[i];
|
||||
#if 0
|
||||
if (reles & VDESC_VP0_WILLUNLOCK)
|
||||
VOP_UNLOCK(*(vps_p[i]), LK_THISLAYER, curproc);
|
||||
#endif
|
||||
if (reles & VDESC_VP0_WILLRELE)
|
||||
vrele(*(vps_p[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the possible out-going vpp
|
||||
* (Assumes that the lower layer always returns
|
||||
* a VREF'ed vpp unless it gets an error.)
|
||||
*/
|
||||
if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
|
||||
!(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
|
||||
!error) {
|
||||
/*
|
||||
* XXX - even though some ops have vpp returned vp's,
|
||||
* several ops actually vrele this before returning.
|
||||
* We must avoid these ops.
|
||||
* (This should go away when these ops are regularized.)
|
||||
*/
|
||||
if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
|
||||
goto out;
|
||||
vppp = VOPARG_OFFSETTO(struct vnode***,
|
||||
descp->vdesc_vpp_offset,ap);
|
||||
if (*vppp)
|
||||
error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp);
|
||||
}
|
||||
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to carry on the locking protocol on the null layer vnodes
|
||||
* as we progress through the tree. We also have to enforce read-only
|
||||
* if this layer is mounted read-only.
|
||||
*/
|
||||
static int
|
||||
null_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
struct proc *p = cnp->cn_proc;
|
||||
int flags = cnp->cn_flags;
|
||||
struct vnode *vp, *ldvp, *lvp;
|
||||
int error;
|
||||
|
||||
if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
|
||||
return (EROFS);
|
||||
/*
|
||||
* Although it is possible to call null_bypass(), we'll do
|
||||
* a direct call to reduce overhead
|
||||
*/
|
||||
ldvp = NULLVPTOLOWERVP(dvp);
|
||||
vp = lvp = NULL;
|
||||
error = VOP_LOOKUP(ldvp, &lvp, cnp);
|
||||
if (error == EJUSTRETURN && (flags & ISLASTCN) &&
|
||||
(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
|
||||
error = EROFS;
|
||||
|
||||
/*
|
||||
* Rely only on the PDIRUNLOCK flag which should be carefully
|
||||
* tracked by underlying filesystem.
|
||||
*/
|
||||
if (cnp->cn_flags & PDIRUNLOCK)
|
||||
VOP_UNLOCK(dvp, LK_THISLAYER, p);
|
||||
if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) {
|
||||
if (ldvp == lvp) {
|
||||
*ap->a_vpp = dvp;
|
||||
VREF(dvp);
|
||||
vrele(lvp);
|
||||
} else {
|
||||
error = null_node_create(dvp->v_mount, lvp, &vp);
|
||||
if (error == 0)
|
||||
*ap->a_vpp = vp;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setattr call. Disallow write attempts if the layer is mounted read-only.
|
||||
*/
|
||||
int
|
||||
null_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
|
||||
if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
|
||||
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
|
||||
vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
|
||||
(vp->v_mount->mnt_flag & MNT_RDONLY))
|
||||
return (EROFS);
|
||||
if (vap->va_size != VNOVAL) {
|
||||
switch (vp->v_type) {
|
||||
case VDIR:
|
||||
return (EISDIR);
|
||||
case VCHR:
|
||||
case VBLK:
|
||||
case VSOCK:
|
||||
case VFIFO:
|
||||
if (vap->va_flags != VNOVAL)
|
||||
return (EOPNOTSUPP);
|
||||
return (0);
|
||||
case VREG:
|
||||
case VLNK:
|
||||
default:
|
||||
/*
|
||||
* Disallow write attempts if the filesystem is
|
||||
* mounted read-only.
|
||||
*/
|
||||
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
||||
return (EROFS);
|
||||
}
|
||||
}
|
||||
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle getattr only to change the fsid.
|
||||
*/
|
||||
static int
|
||||
null_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
|
||||
return (error);
|
||||
|
||||
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle to disallow write access if mounted read-only.
|
||||
*/
|
||||
static int
|
||||
null_access(ap)
|
||||
struct vop_access_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
mode_t mode = ap->a_mode;
|
||||
|
||||
/*
|
||||
* Disallow write attempts on read-only layers;
|
||||
* unless the file is a socket, fifo, or a block or
|
||||
* character device resident on the file system.
|
||||
*/
|
||||
if (mode & VWRITE) {
|
||||
switch (vp->v_type) {
|
||||
case VDIR:
|
||||
case VLNK:
|
||||
case VREG:
|
||||
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
||||
return (EROFS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We must handle open to be able to catch MNT_NODEV and friends.
|
||||
*/
|
||||
static int
|
||||
null_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vnode *lvp = NULLVPTOLOWERVP(ap->a_vp);
|
||||
|
||||
if ((vp->v_mount->mnt_flag & MNT_NODEV) &&
|
||||
(lvp->v_type == VBLK || lvp->v_type == VCHR))
|
||||
return ENXIO;
|
||||
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle this to eliminate null FS to lower FS
|
||||
* file moving. Don't know why we don't allow this,
|
||||
* possibly we should.
|
||||
*/
|
||||
static int
|
||||
null_rename(ap)
|
||||
struct vop_rename_args /* {
|
||||
struct vnode *a_fdvp;
|
||||
struct vnode *a_fvp;
|
||||
struct componentname *a_fcnp;
|
||||
struct vnode *a_tdvp;
|
||||
struct vnode *a_tvp;
|
||||
struct componentname *a_tcnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *tdvp = ap->a_tdvp;
|
||||
struct vnode *fvp = ap->a_fvp;
|
||||
struct vnode *fdvp = ap->a_fdvp;
|
||||
struct vnode *tvp = ap->a_tvp;
|
||||
|
||||
/* Check for cross-device rename. */
|
||||
if ((fvp->v_mount != tdvp->v_mount) ||
|
||||
(tvp && (fvp->v_mount != tvp->v_mount))) {
|
||||
if (tdvp == tvp)
|
||||
vrele(tdvp);
|
||||
else
|
||||
vput(tdvp);
|
||||
if (tvp)
|
||||
vput(tvp);
|
||||
vrele(fdvp);
|
||||
vrele(fvp);
|
||||
return (EXDEV);
|
||||
}
|
||||
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode lock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
static int
|
||||
null_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int flags = ap->a_flags;
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *lvp;
|
||||
int error;
|
||||
|
||||
if (flags & LK_THISLAYER) {
|
||||
if (vp->v_vnlock != NULL)
|
||||
return 0; /* lock is shared across layers */
|
||||
error = lockmgr(&vp->v_lock, flags & ~LK_THISLAYER,
|
||||
&vp->v_interlock, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (vp->v_vnlock != NULL) {
|
||||
/*
|
||||
* The lower level has exported a struct lock to us. Use
|
||||
* it so that all vnodes in the stack lock and unlock
|
||||
* simultaneously. Note: we don't DRAIN the lock as DRAIN
|
||||
* decommissions the lock - just because our vnode is
|
||||
* going away doesn't mean the struct lock below us is.
|
||||
* LK_EXCLUSIVE is fine.
|
||||
*/
|
||||
if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
|
||||
NULLFSDEBUG("null_lock: avoiding LK_DRAIN\n");
|
||||
return(lockmgr(vp->v_vnlock,
|
||||
(flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE,
|
||||
&vp->v_interlock, p));
|
||||
}
|
||||
return(lockmgr(vp->v_vnlock, flags, &vp->v_interlock, p));
|
||||
} else {
|
||||
/*
|
||||
* To prevent race conditions involving doing a lookup
|
||||
* on "..", we have to lock the lower node, then lock our
|
||||
* node. Most of the time it won't matter that we lock our
|
||||
* node (as any locking would need the lower one locked
|
||||
* first). But we can LK_DRAIN the upper lock as a step
|
||||
* towards decomissioning it.
|
||||
*/
|
||||
lvp = NULLVPTOLOWERVP(vp);
|
||||
if (lvp == NULL)
|
||||
return (lockmgr(&vp->v_lock, flags, &vp->v_interlock, p));
|
||||
if (flags & LK_INTERLOCK) {
|
||||
mtx_unlock(&vp->v_interlock);
|
||||
flags &= ~LK_INTERLOCK;
|
||||
}
|
||||
if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
|
||||
error = VOP_LOCK(lvp,
|
||||
(flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE, p);
|
||||
} else
|
||||
error = VOP_LOCK(lvp, flags, p);
|
||||
if (error)
|
||||
return (error);
|
||||
error = lockmgr(&vp->v_lock, flags, &vp->v_interlock, p);
|
||||
if (error)
|
||||
VOP_UNLOCK(lvp, 0, p);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode unlock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
static int
|
||||
null_unlock(ap)
|
||||
struct vop_unlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int flags = ap->a_flags;
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *lvp;
|
||||
|
||||
if (vp->v_vnlock != NULL) {
|
||||
if (flags & LK_THISLAYER)
|
||||
return 0; /* the lock is shared across layers */
|
||||
flags &= ~LK_THISLAYER;
|
||||
return (lockmgr(vp->v_vnlock, flags | LK_RELEASE,
|
||||
&vp->v_interlock, p));
|
||||
}
|
||||
lvp = NULLVPTOLOWERVP(vp);
|
||||
if (lvp == NULL)
|
||||
return (lockmgr(&vp->v_lock, flags | LK_RELEASE, &vp->v_interlock, p));
|
||||
if ((flags & LK_THISLAYER) == 0) {
|
||||
if (flags & LK_INTERLOCK) {
|
||||
mtx_unlock(&vp->v_interlock);
|
||||
flags &= ~LK_INTERLOCK;
|
||||
}
|
||||
VOP_UNLOCK(lvp, flags & ~LK_INTERLOCK, p);
|
||||
} else
|
||||
flags &= ~LK_THISLAYER;
|
||||
return (lockmgr(&vp->v_lock, flags | LK_RELEASE, &vp->v_interlock, p));
|
||||
}
|
||||
|
||||
static int
|
||||
null_islocked(ap)
|
||||
struct vop_islocked_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct proc *p = ap->a_p;
|
||||
|
||||
if (vp->v_vnlock != NULL)
|
||||
return (lockstatus(vp->v_vnlock, p));
|
||||
return (lockstatus(&vp->v_lock, p));
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no way to tell that someone issued remove/rmdir operation
|
||||
* on the underlying filesystem. For now we just have to release lowevrp
|
||||
* as soon as possible.
|
||||
*/
|
||||
static int
|
||||
null_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct proc *p = ap->a_p;
|
||||
struct null_node *xp = VTONULL(vp);
|
||||
struct vnode *lowervp = xp->null_lowervp;
|
||||
|
||||
lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
|
||||
LIST_REMOVE(xp, null_hash);
|
||||
lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
|
||||
|
||||
xp->null_lowervp = NULLVP;
|
||||
if (vp->v_vnlock != NULL) {
|
||||
vp->v_vnlock = &vp->v_lock; /* we no longer share the lock */
|
||||
} else
|
||||
VOP_UNLOCK(vp, LK_THISLAYER, p);
|
||||
|
||||
vput(lowervp);
|
||||
/*
|
||||
* Now it is safe to drop references to the lower vnode.
|
||||
* VOP_INACTIVE() will be called by vrele() if necessary.
|
||||
*/
|
||||
vrele (lowervp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can free memory in null_inactive, but we do this
|
||||
* here. (Possible to guard vp->v_data to point somewhere)
|
||||
*/
|
||||
static int
|
||||
null_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
void *vdata = vp->v_data;
|
||||
|
||||
vp->v_data = NULL;
|
||||
FREE(vdata, M_NULLFSNODE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
null_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
printf ("\ttag VT_NULLFS, vp=%p, lowervp=%p\n", vp, NULLVPTOLOWERVP(vp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Let an underlying filesystem do the work
|
||||
*/
|
||||
static int
|
||||
null_createvobject(ap)
|
||||
struct vop_createvobject_args /* {
|
||||
struct vnode *vp;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vnode *lowervp = VTONULL(vp) ? NULLVPTOLOWERVP(vp) : NULL;
|
||||
int error;
|
||||
|
||||
if (vp->v_type == VNON || lowervp == NULL)
|
||||
return 0;
|
||||
error = VOP_CREATEVOBJECT(lowervp, ap->a_cred, ap->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
vp->v_flag |= VOBJBUF;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have nothing to destroy and this operation shouldn't be bypassed.
|
||||
*/
|
||||
static int
|
||||
null_destroyvobject(ap)
|
||||
struct vop_destroyvobject_args /* {
|
||||
struct vnode *vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
vp->v_flag &= ~VOBJBUF;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
null_getvobject(ap)
|
||||
struct vop_getvobject_args /* {
|
||||
struct vnode *vp;
|
||||
struct vm_object **objpp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *lvp = NULLVPTOLOWERVP(ap->a_vp);
|
||||
|
||||
if (lvp == NULL)
|
||||
return EINVAL;
|
||||
return (VOP_GETVOBJECT(lvp, ap->a_objpp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Global vfs data structures
|
||||
*/
|
||||
vop_t **null_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc null_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) null_bypass },
|
||||
|
||||
{ &vop_access_desc, (vop_t *) null_access },
|
||||
{ &vop_bmap_desc, (vop_t *) vop_eopnotsupp },
|
||||
{ &vop_createvobject_desc, (vop_t *) null_createvobject },
|
||||
{ &vop_destroyvobject_desc, (vop_t *) null_destroyvobject },
|
||||
{ &vop_getattr_desc, (vop_t *) null_getattr },
|
||||
{ &vop_getvobject_desc, (vop_t *) null_getvobject },
|
||||
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount},
|
||||
{ &vop_inactive_desc, (vop_t *) null_inactive },
|
||||
{ &vop_islocked_desc, (vop_t *) null_islocked },
|
||||
{ &vop_lock_desc, (vop_t *) null_lock },
|
||||
{ &vop_lookup_desc, (vop_t *) null_lookup },
|
||||
{ &vop_open_desc, (vop_t *) null_open },
|
||||
{ &vop_print_desc, (vop_t *) null_print },
|
||||
{ &vop_reclaim_desc, (vop_t *) null_reclaim },
|
||||
{ &vop_rename_desc, (vop_t *) null_rename },
|
||||
{ &vop_setattr_desc, (vop_t *) null_setattr },
|
||||
{ &vop_strategy_desc, (vop_t *) vop_eopnotsupp },
|
||||
{ &vop_unlock_desc, (vop_t *) null_unlock },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc null_vnodeop_opv_desc =
|
||||
{ &null_vnodeop_p, null_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(null_vnodeop_opv_desc);
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)portal.h 8.4 (Berkeley) 1/21/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct portal_args {
|
||||
char *pa_config; /* Config file */
|
||||
int pa_socket; /* Socket to server */
|
||||
};
|
||||
|
||||
struct portal_cred {
|
||||
int pcr_flag; /* File open mode */
|
||||
uid_t pcr_uid; /* From ucred */
|
||||
short pcr_ngroups; /* From ucred */
|
||||
gid_t pcr_groups[NGROUPS]; /* From ucred */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct portalmount {
|
||||
struct vnode *pm_root; /* Root node */
|
||||
struct file *pm_server; /* Held reference to server socket */
|
||||
};
|
||||
|
||||
struct portalnode {
|
||||
int pt_size; /* Length of Arg */
|
||||
char *pt_arg; /* Arg to send to server */
|
||||
int pt_fileid; /* cookie */
|
||||
};
|
||||
|
||||
#define VFSTOPORTAL(mp) ((struct portalmount *)((mp)->mnt_data))
|
||||
#define VTOPORTAL(vp) ((struct portalnode *)(vp)->v_data)
|
||||
|
||||
#define PORTAL_ROOTFILEID 2
|
||||
|
||||
extern vop_t **portal_vnodeop_p;
|
||||
#endif /* _KERNEL */
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)portal_vfsops.c 8.11 (Berkeley) 5/14/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portal Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/file.h> /* Must come after sys/malloc.h */
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
static MALLOC_DEFINE(M_PORTALFSMNT, "PORTAL mount", "PORTAL mount structure");
|
||||
|
||||
static int portal_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
static int portal_unmount __P((struct mount *mp, int mntflags,
|
||||
struct proc *p));
|
||||
static int portal_root __P((struct mount *mp, struct vnode **vpp));
|
||||
static int portal_statfs __P((struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p));
|
||||
|
||||
/*
|
||||
* Mount the per-process file descriptors (/dev/fd)
|
||||
*/
|
||||
static int
|
||||
portal_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct file *fp;
|
||||
struct portal_args args;
|
||||
struct portalmount *fmp;
|
||||
struct socket *so;
|
||||
struct vnode *rvp;
|
||||
struct portalnode *pn;
|
||||
u_int size;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
error = copyin(data, (caddr_t) &args, sizeof(struct portal_args));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = holdsock(p->p_fd, args.pa_socket, &fp);
|
||||
if (error)
|
||||
return (error);
|
||||
so = (struct socket *) fp->f_data;
|
||||
if (so->so_proto->pr_domain->dom_family != AF_UNIX) {
|
||||
fdrop(fp, p);
|
||||
return (ESOCKTNOSUPPORT);
|
||||
}
|
||||
|
||||
MALLOC(pn, struct portalnode *, sizeof(struct portalnode),
|
||||
M_TEMP, M_WAITOK);
|
||||
|
||||
MALLOC(fmp, struct portalmount *, sizeof(struct portalmount),
|
||||
M_PORTALFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
error = getnewvnode(VT_PORTAL, mp, portal_vnodeop_p, &rvp); /* XXX */
|
||||
if (error) {
|
||||
FREE(fmp, M_PORTALFSMNT);
|
||||
FREE(pn, M_TEMP);
|
||||
fdrop(fp, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
rvp->v_data = pn;
|
||||
rvp->v_type = VDIR;
|
||||
rvp->v_flag |= VROOT;
|
||||
VTOPORTAL(rvp)->pt_arg = 0;
|
||||
VTOPORTAL(rvp)->pt_size = 0;
|
||||
VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID;
|
||||
fmp->pm_root = rvp;
|
||||
fmp->pm_server = fp; fp->f_count++;
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void)copyinstr(args.pa_config,
|
||||
mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
|
||||
#ifdef notdef
|
||||
bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
|
||||
bcopy("portal", mp->mnt_stat.f_mntfromname, sizeof("portal"));
|
||||
#endif
|
||||
|
||||
(void)portal_statfs(mp, &mp->mnt_stat, p);
|
||||
fdrop(fp, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error, flags = 0;
|
||||
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
#ifdef notyet
|
||||
mntflushbuf(mp, 0);
|
||||
if (mntinvalbuf(mp, 1))
|
||||
return (EBUSY);
|
||||
#endif
|
||||
/* There is 1 extra root vnode reference (pm_root). */
|
||||
error = vflush(mp, 1, flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Shutdown the socket. This will cause the select in the
|
||||
* daemon to wake up, and then the accept will get ECONNABORTED
|
||||
* which it interprets as a request to go and bury itself.
|
||||
*/
|
||||
soshutdown((struct socket *) VFSTOPORTAL(mp)->pm_server->f_data, 2);
|
||||
/*
|
||||
* Discard reference to underlying file. Must call closef because
|
||||
* this may be the last reference.
|
||||
*/
|
||||
closef(VFSTOPORTAL(mp)->pm_server, (struct proc *) 0);
|
||||
/*
|
||||
* Finally, throw away the portalmount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_PORTALFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = VFSTOPORTAL(mp)->pm_root;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
sbp->f_flags = 0;
|
||||
sbp->f_bsize = DEV_BSIZE;
|
||||
sbp->f_iosize = DEV_BSIZE;
|
||||
sbp->f_blocks = 2; /* 1K to keep df happy */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = 1; /* Allow for "." */
|
||||
sbp->f_ffree = 0; /* See comments above */
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct vfsops portal_vfsops = {
|
||||
portal_mount,
|
||||
vfs_stdstart,
|
||||
portal_unmount,
|
||||
portal_root,
|
||||
vfs_stdquotactl,
|
||||
portal_statfs,
|
||||
vfs_stdsync,
|
||||
vfs_stdvget,
|
||||
vfs_stdfhtovp,
|
||||
vfs_stdcheckexp,
|
||||
vfs_stdvptofh,
|
||||
vfs_stdinit,
|
||||
vfs_stduninit,
|
||||
vfs_stdextattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(portal_vfsops, portal, VFCF_SYNTHETIC);
|
@ -1,591 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portal Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/unpcb.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
static int portal_fileid = PORTAL_ROOTFILEID+1;
|
||||
|
||||
static int portal_badop __P((void));
|
||||
static void portal_closefd __P((struct proc *p, int fd));
|
||||
static int portal_connect __P((struct socket *so, struct socket *so2));
|
||||
static int portal_getattr __P((struct vop_getattr_args *ap));
|
||||
static int portal_lookup __P((struct vop_lookup_args *ap));
|
||||
static int portal_open __P((struct vop_open_args *ap));
|
||||
static int portal_print __P((struct vop_print_args *ap));
|
||||
static int portal_readdir __P((struct vop_readdir_args *ap));
|
||||
static int portal_reclaim __P((struct vop_reclaim_args *ap));
|
||||
static int portal_setattr __P((struct vop_setattr_args *ap));
|
||||
|
||||
static void
|
||||
portal_closefd(p, fd)
|
||||
struct proc *p;
|
||||
int fd;
|
||||
{
|
||||
int error;
|
||||
struct close_args ua;
|
||||
|
||||
ua.fd = fd;
|
||||
error = close(p, &ua);
|
||||
/*
|
||||
* We should never get an error, and there isn't anything
|
||||
* we could do if we got one, so just print a message.
|
||||
*/
|
||||
if (error)
|
||||
printf("portal_closefd: error = %d\n", error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vp is the current namei directory
|
||||
* cnp is the name to locate in that directory...
|
||||
*/
|
||||
static int
|
||||
portal_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct portalnode *pt;
|
||||
int error;
|
||||
struct vnode *fvp = 0;
|
||||
char *path;
|
||||
int size;
|
||||
|
||||
*vpp = NULLVP;
|
||||
|
||||
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
|
||||
return (EROFS);
|
||||
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
/*VOP_LOCK(dvp);*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the MALLOC before the getnewvnode since doing so afterward
|
||||
* might cause a bogus v_data pointer to get dereferenced
|
||||
* elsewhere if MALLOC should block.
|
||||
*/
|
||||
MALLOC(pt, struct portalnode *, sizeof(struct portalnode),
|
||||
M_TEMP, M_WAITOK);
|
||||
|
||||
error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
|
||||
if (error) {
|
||||
FREE(pt, M_TEMP);
|
||||
goto bad;
|
||||
}
|
||||
fvp->v_type = VREG;
|
||||
fvp->v_data = pt;
|
||||
/*
|
||||
* Save all of the remaining pathname and
|
||||
* advance the namei next pointer to the end
|
||||
* of the string.
|
||||
*/
|
||||
for (size = 0, path = pname; *path; path++)
|
||||
size++;
|
||||
cnp->cn_consume = size - cnp->cn_namelen;
|
||||
|
||||
pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
|
||||
pt->pt_size = size+1;
|
||||
bcopy(pname, pt->pt_arg, pt->pt_size);
|
||||
pt->pt_fileid = portal_fileid++;
|
||||
|
||||
*vpp = fvp;
|
||||
/*VOP_LOCK(fvp);*/
|
||||
return (0);
|
||||
|
||||
bad:;
|
||||
if (fvp)
|
||||
vrele(fvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_connect(so, so2)
|
||||
struct socket *so;
|
||||
struct socket *so2;
|
||||
{
|
||||
/* from unp_connect, bypassing the namei stuff... */
|
||||
struct socket *so3;
|
||||
struct unpcb *unp2;
|
||||
struct unpcb *unp3;
|
||||
|
||||
if (so2 == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
if (so->so_type != so2->so_type)
|
||||
return (EPROTOTYPE);
|
||||
|
||||
if ((so2->so_options & SO_ACCEPTCONN) == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
if ((so3 = sonewconn(so2, 0)) == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
unp2 = sotounpcb(so2);
|
||||
unp3 = sotounpcb(so3);
|
||||
if (unp2->unp_addr)
|
||||
unp3->unp_addr = (struct sockaddr_un *)
|
||||
dup_sockaddr((struct sockaddr *)unp2->unp_addr, 0);
|
||||
so2 = so3;
|
||||
|
||||
return (unp_connect2(so, so2));
|
||||
}
|
||||
|
||||
static int
|
||||
portal_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct socket *so = 0;
|
||||
struct portalnode *pt;
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int s;
|
||||
struct uio auio;
|
||||
struct iovec aiov[2];
|
||||
int res;
|
||||
struct mbuf *cm = 0;
|
||||
struct cmsghdr *cmsg;
|
||||
int newfds;
|
||||
int *ip;
|
||||
int fd;
|
||||
int error;
|
||||
int len;
|
||||
struct portalmount *fmp;
|
||||
struct file *fp;
|
||||
struct portal_cred pcred;
|
||||
|
||||
/*
|
||||
* Nothing to do when opening the root node.
|
||||
*/
|
||||
if (vp->v_flag & VROOT)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Can't be opened unless the caller is set up
|
||||
* to deal with the side effects. Check for this
|
||||
* by testing whether the p_dupfd has been set.
|
||||
*/
|
||||
if (p->p_dupfd >= 0)
|
||||
return (ENODEV);
|
||||
|
||||
pt = VTOPORTAL(vp);
|
||||
fmp = VFSTOPORTAL(vp->v_mount);
|
||||
|
||||
/*
|
||||
* Create a new socket.
|
||||
*/
|
||||
error = socreate(AF_UNIX, &so, SOCK_STREAM, 0, ap->a_p);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Reserve some buffer space
|
||||
*/
|
||||
res = pt->pt_size + sizeof(pcred) + 512; /* XXX */
|
||||
error = soreserve(so, res, res);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Kick off connection
|
||||
*/
|
||||
error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Wait for connection to complete
|
||||
*/
|
||||
/*
|
||||
* XXX: Since the mount point is holding a reference on the
|
||||
* underlying server socket, it is not easy to find out whether
|
||||
* the server process is still running. To handle this problem
|
||||
* we loop waiting for the new socket to be connected (something
|
||||
* which will only happen if the server is still running) or for
|
||||
* the reference count on the server socket to drop to 1, which
|
||||
* will happen if the server dies. Sleep for 5 second intervals
|
||||
* and keep polling the reference count. XXX.
|
||||
*/
|
||||
s = splnet();
|
||||
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
|
||||
if (fmp->pm_server->f_count == 1) {
|
||||
error = ECONNREFUSED;
|
||||
splx(s);
|
||||
goto bad;
|
||||
}
|
||||
(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
if (so->so_error) {
|
||||
error = so->so_error;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set miscellaneous flags
|
||||
*/
|
||||
so->so_rcv.sb_timeo = 0;
|
||||
so->so_snd.sb_timeo = 0;
|
||||
so->so_rcv.sb_flags |= SB_NOINTR;
|
||||
so->so_snd.sb_flags |= SB_NOINTR;
|
||||
|
||||
|
||||
pcred.pcr_flag = ap->a_mode;
|
||||
pcred.pcr_uid = ap->a_cred->cr_uid;
|
||||
pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
|
||||
bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
|
||||
aiov[0].iov_base = (caddr_t) &pcred;
|
||||
aiov[0].iov_len = sizeof(pcred);
|
||||
aiov[1].iov_base = pt->pt_arg;
|
||||
aiov[1].iov_len = pt->pt_size;
|
||||
auio.uio_iov = aiov;
|
||||
auio.uio_iovcnt = 2;
|
||||
auio.uio_rw = UIO_WRITE;
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_procp = p;
|
||||
auio.uio_offset = 0;
|
||||
auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
|
||||
|
||||
error = sosend(so, (struct sockaddr *) 0, &auio,
|
||||
(struct mbuf *) 0, (struct mbuf *) 0, 0, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
len = auio.uio_resid = sizeof(int);
|
||||
do {
|
||||
struct mbuf *m = 0;
|
||||
int flags = MSG_WAITALL;
|
||||
error = soreceive(so, (struct sockaddr **) 0, &auio,
|
||||
&m, &cm, &flags);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Grab an error code from the mbuf.
|
||||
*/
|
||||
if (m) {
|
||||
m = m_pullup(m, sizeof(int)); /* Needed? */
|
||||
if (m) {
|
||||
error = *(mtod(m, int *));
|
||||
m_freem(m);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (cm == 0) {
|
||||
error = ECONNRESET; /* XXX */
|
||||
#ifdef notdef
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} while (cm == 0 && auio.uio_resid == len && !error);
|
||||
|
||||
if (cm == 0)
|
||||
goto bad;
|
||||
|
||||
if (auio.uio_resid) {
|
||||
error = 0;
|
||||
#ifdef notdef
|
||||
error = EMSGSIZE;
|
||||
goto bad;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Break apart the control message, and retrieve the
|
||||
* received file descriptor. Note that more than one descriptor
|
||||
* may have been received, or that the rights chain may have more
|
||||
* than a single mbuf in it. What to do?
|
||||
*/
|
||||
cmsg = mtod(cm, struct cmsghdr *);
|
||||
newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
|
||||
if (newfds == 0) {
|
||||
error = ECONNREFUSED;
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* At this point the rights message consists of a control message
|
||||
* header, followed by a data region containing a vector of
|
||||
* integer file descriptors. The fds were allocated by the action
|
||||
* of receiving the control message.
|
||||
*/
|
||||
ip = (int *) (cmsg + 1);
|
||||
fd = *ip++;
|
||||
if (newfds > 1) {
|
||||
/*
|
||||
* Close extra fds.
|
||||
*/
|
||||
int i;
|
||||
printf("portal_open: %d extra fds\n", newfds - 1);
|
||||
for (i = 1; i < newfds; i++) {
|
||||
portal_closefd(p, *ip);
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the mode the file is being opened for is a subset
|
||||
* of the mode of the existing descriptor.
|
||||
*/
|
||||
fp = p->p_fd->fd_ofiles[fd];
|
||||
if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
|
||||
portal_closefd(p, fd);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the dup fd in the proc structure then return the
|
||||
* special error code (ENXIO) which causes magic things to
|
||||
* happen in vn_open. The whole concept is, well, hmmm.
|
||||
*/
|
||||
p->p_dupfd = fd;
|
||||
error = ENXIO;
|
||||
|
||||
bad:;
|
||||
/*
|
||||
* And discard the control message.
|
||||
*/
|
||||
if (cm) {
|
||||
m_freem(cm);
|
||||
}
|
||||
|
||||
if (so) {
|
||||
soshutdown(so, 2);
|
||||
soclose(so);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
|
||||
bzero(vap, sizeof(*vap));
|
||||
vattr_null(vap);
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_size = DEV_BSIZE;
|
||||
vap->va_blocksize = DEV_BSIZE;
|
||||
nanotime(&vap->va_atime);
|
||||
vap->va_mtime = vap->va_atime;
|
||||
vap->va_ctime = vap->va_mtime;
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
vap->va_rdev = 0;
|
||||
/* vap->va_qbytes = 0; */
|
||||
vap->va_bytes = 0;
|
||||
/* vap->va_qsize = 0; */
|
||||
if (vp->v_flag & VROOT) {
|
||||
vap->va_type = VDIR;
|
||||
vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
|
||||
S_IRGRP|S_IWGRP|S_IXGRP|
|
||||
S_IROTH|S_IWOTH|S_IXOTH;
|
||||
vap->va_nlink = 2;
|
||||
vap->va_fileid = 2;
|
||||
} else {
|
||||
vap->va_type = VREG;
|
||||
vap->va_mode = S_IRUSR|S_IWUSR|
|
||||
S_IRGRP|S_IWGRP|
|
||||
S_IROTH|S_IWOTH;
|
||||
vap->va_nlink = 1;
|
||||
vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* Can't mess with the root vnode
|
||||
*/
|
||||
if (ap->a_vp->v_flag & VROOT)
|
||||
return (EACCES);
|
||||
|
||||
if (ap->a_vap->va_flags != VNOVAL)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fake readdir, just return empty directory.
|
||||
* It is hard to deal with '.' and '..' so don't bother.
|
||||
*/
|
||||
static int
|
||||
portal_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't allow exporting portal mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies)
|
||||
panic("portal_readdir: not hungry");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct portalnode *pt = VTOPORTAL(ap->a_vp);
|
||||
|
||||
if (pt->pt_arg) {
|
||||
free((caddr_t) pt->pt_arg, M_TEMP);
|
||||
pt->pt_arg = 0;
|
||||
}
|
||||
FREE(ap->a_vp->v_data, M_TEMP);
|
||||
ap->a_vp->v_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print out the contents of a Portal vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
portal_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_PORTAL, portal vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Portal "should never get here" operation
|
||||
*/
|
||||
static int
|
||||
portal_badop()
|
||||
{
|
||||
|
||||
panic("portal: bad op");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
vop_t **portal_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *) vop_null },
|
||||
{ &vop_getattr_desc, (vop_t *) portal_getattr },
|
||||
{ &vop_lookup_desc, (vop_t *) portal_lookup },
|
||||
{ &vop_open_desc, (vop_t *) portal_open },
|
||||
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
|
||||
{ &vop_print_desc, (vop_t *) portal_print },
|
||||
{ &vop_readdir_desc, (vop_t *) portal_readdir },
|
||||
{ &vop_reclaim_desc, (vop_t *) portal_reclaim },
|
||||
{ &vop_setattr_desc, (vop_t *) portal_setattr },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc portal_vnodeop_opv_desc =
|
||||
{ &portal_vnodeop_p, portal_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(portal_vnodeop_opv_desc);
|
@ -1,113 +0,0 @@
|
||||
saute procfs lyonnais
|
||||
|
||||
procfs supports two levels of directory. the filesystem root
|
||||
directory contains a representation of the system process table.
|
||||
this consists of an entry for each active and zombie process, and
|
||||
an additional entry "curproc" which always represents the process
|
||||
making the lookup request.
|
||||
|
||||
each of the sub-directories contains several files. these files
|
||||
are used to control and interrogate processes. the files implemented
|
||||
are:
|
||||
|
||||
file - xxx. the exec'ed file.
|
||||
|
||||
status - r/o. returns process status.
|
||||
|
||||
ctl - w/o. sends a control message to the process.
|
||||
for example:
|
||||
echo hup > /proc/curproc/note
|
||||
will send a SIGHUP to the shell.
|
||||
whereas
|
||||
echo attach > /proc/1293/ctl
|
||||
would set up process 1293 for debugging.
|
||||
see below for more details.
|
||||
|
||||
mem - r/w. virtual memory image of the process.
|
||||
parts of the address space are readable
|
||||
only if they exist in the target process.
|
||||
a more reasonable alternative might be
|
||||
to return zero pages instead of an error.
|
||||
comments?
|
||||
|
||||
note - w/o. writing a string here sends the
|
||||
equivalent note to the process.
|
||||
[ not implemented. ]
|
||||
|
||||
notepg - w/o. the same as note, but sends to all
|
||||
members of the process group.
|
||||
[ not implemented. ]
|
||||
|
||||
regs - r/w. process register set. this can be read
|
||||
or written any time even if the process
|
||||
is not stopped. since the bsd kernel
|
||||
is single-processor, this implementation
|
||||
will get the "right" register values.
|
||||
a multi-proc kernel would need to do some
|
||||
synchronisation.
|
||||
|
||||
this then looks like:
|
||||
|
||||
% ls -li /proc
|
||||
total 0
|
||||
9 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 0
|
||||
17 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 1
|
||||
89 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 10
|
||||
25 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 2
|
||||
2065 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 257
|
||||
2481 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 309
|
||||
265 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 32
|
||||
3129 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 390
|
||||
3209 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 400
|
||||
3217 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 401
|
||||
3273 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 408
|
||||
393 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 48
|
||||
409 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 50
|
||||
465 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 57
|
||||
481 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 59
|
||||
537 dr-xr-xr-x 2 root kmem 0 Sep 21 15:06 66
|
||||
545 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 67
|
||||
657 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 81
|
||||
665 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 82
|
||||
673 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 83
|
||||
681 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 84
|
||||
3273 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 curproc
|
||||
% ls -li /proc/curproc
|
||||
total 408
|
||||
3341 --w------- 1 jsp staff 0 Sep 21 15:06 ctl
|
||||
1554 -r-xr-xr-x 1 bin bin 90112 Mar 29 04:52 file
|
||||
3339 -rw------- 1 jsp staff 118784 Sep 21 15:06 mem
|
||||
3343 --w------- 1 jsp staff 0 Sep 21 15:06 note
|
||||
3344 --w------- 1 jsp staff 0 Sep 21 15:06 notepg
|
||||
3340 -rw------- 1 jsp staff 0 Sep 21 15:06 regs
|
||||
3342 -r--r--r-- 1 jsp staff 0 Sep 21 15:06 status
|
||||
% df /proc/curproc /proc/curproc/file
|
||||
Filesystem 512-blocks Used Avail Capacity Mounted on
|
||||
proc 2 2 0 100% /proc
|
||||
/dev/wd0a 16186 13548 1018 93% /
|
||||
% cat /proc/curproc/status
|
||||
cat 446 439 400 81 12,0 ctty 748620684 270000 0 0 0 20000 nochan 11 20 20 20 0 21 117
|
||||
|
||||
|
||||
|
||||
the basic sequence of commands written to "ctl" would be
|
||||
|
||||
attach - this stops the target process and
|
||||
arranges for the sending process
|
||||
to become the debug control process
|
||||
wait - wait for the target process to come to
|
||||
a steady state ready for debugging.
|
||||
step - single step, with no signal delivery.
|
||||
run - continue running, with no signal delivery,
|
||||
until next trap or breakpoint.
|
||||
<signame> - deliver signal <signame> and continue running.
|
||||
detach - continue execution of the target process
|
||||
and remove it from control by the debug process
|
||||
|
||||
in a normal debugging environment, where the target is fork/exec'd by
|
||||
the debugger, the debugger should fork and the child should stop itself
|
||||
(with a self-inflicted SIGSTOP). the parent should do a "wait" then an
|
||||
"attach". as before, the child will hit a breakpoint on the first
|
||||
instruction in any newly exec'd image.
|
||||
|
||||
$FreeBSD$
|
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs.h 8.9 (Berkeley) 5/14/95
|
||||
*
|
||||
* From:
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* The different types of node in a procfs filesystem
|
||||
*/
|
||||
typedef enum {
|
||||
Proot, /* the filesystem root */
|
||||
Pcurproc, /* symbolic link for curproc */
|
||||
Pproc, /* a process-specific sub-directory */
|
||||
Pfile, /* the executable file */
|
||||
Pmem, /* the process's memory image */
|
||||
Pregs, /* the process's register set */
|
||||
Pfpregs, /* the process's FP register set */
|
||||
Pdbregs, /* the process's debug register set */
|
||||
Pctl, /* process control */
|
||||
Pstatus, /* process status */
|
||||
Pnote, /* process notifier */
|
||||
Pnotepg, /* process group notifier */
|
||||
Pmap, /* memory map */
|
||||
Ptype, /* executable type */
|
||||
Pcmdline, /* command line */
|
||||
Prlimit /* resource limits */
|
||||
} pfstype;
|
||||
|
||||
/*
|
||||
* control data for the proc file system.
|
||||
*/
|
||||
struct pfsnode {
|
||||
struct pfsnode *pfs_next; /* next on list */
|
||||
struct vnode *pfs_vnode; /* vnode associated with this pfsnode */
|
||||
pfstype pfs_type; /* type of procfs node */
|
||||
pid_t pfs_pid; /* associated process */
|
||||
u_short pfs_mode; /* mode bits for stat() */
|
||||
u_long pfs_flags; /* open flags */
|
||||
u_long pfs_fileno; /* unique file id */
|
||||
pid_t pfs_lockowner; /* pfs lock owner */
|
||||
};
|
||||
|
||||
#define PROCFS_NOTELEN 64 /* max length of a note (/proc/$pid/note) */
|
||||
#define PROCFS_CTLLEN 8 /* max length of a ctl msg (/proc/$pid/ctl */
|
||||
#define PROCFS_NAMELEN 8 /* max length of a filename component */
|
||||
|
||||
/*
|
||||
* Kernel stuff follows
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
#define CNEQ(cnp, s, len) \
|
||||
((cnp)->cn_namelen == (len) && \
|
||||
(bcmp((s), (cnp)->cn_nameptr, (len)) == 0))
|
||||
|
||||
#define KMEM_GROUP 2
|
||||
|
||||
#define PROCFS_FILENO(pid, type) \
|
||||
(((type) < Pproc) ? \
|
||||
((type) + 2) : \
|
||||
((((pid)+1) << 4) + ((int) (type))))
|
||||
|
||||
/*
|
||||
* Convert between pfsnode vnode
|
||||
*/
|
||||
#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data)
|
||||
#define PFSTOV(pfs) ((pfs)->pfs_vnode)
|
||||
|
||||
typedef struct vfs_namemap vfs_namemap_t;
|
||||
struct vfs_namemap {
|
||||
const char *nm_name;
|
||||
int nm_val;
|
||||
};
|
||||
|
||||
int vfs_getuserstr __P((struct uio *, char *, int *));
|
||||
vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int));
|
||||
|
||||
/* <machine/reg.h> */
|
||||
struct reg;
|
||||
struct fpreg;
|
||||
struct dbreg;
|
||||
|
||||
#define PFIND(pid) (pfind(pid))
|
||||
|
||||
void procfs_exit __P((struct proc *));
|
||||
int procfs_freevp __P((struct vnode *));
|
||||
int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype));
|
||||
struct vnode *procfs_findtextvp __P((struct proc *));
|
||||
int procfs_sstep __P((struct proc *));
|
||||
void procfs_fix_sstep __P((struct proc *));
|
||||
int procfs_read_regs __P((struct proc *, struct reg *));
|
||||
int procfs_write_regs __P((struct proc *, struct reg *));
|
||||
int procfs_read_fpregs __P((struct proc *, struct fpreg *));
|
||||
int procfs_write_fpregs __P((struct proc *, struct fpreg *));
|
||||
int procfs_read_dbregs __P((struct proc *, struct dbreg *));
|
||||
int procfs_write_dbregs __P((struct proc *, struct dbreg *));
|
||||
int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dodbregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_docmdline __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dorlimit __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
|
||||
/* Return 1 if process has special kernel digging privileges */
|
||||
int procfs_kmemaccess __P((struct proc *));
|
||||
|
||||
/* functions to check whether or not files should be displayed */
|
||||
int procfs_validfile __P((struct proc *));
|
||||
int procfs_validfpregs __P((struct proc *));
|
||||
int procfs_validregs __P((struct proc *));
|
||||
int procfs_validdbregs __P((struct proc *));
|
||||
int procfs_validmap __P((struct proc *));
|
||||
int procfs_validtype __P((struct proc *));
|
||||
|
||||
#define PROCFS_LOCKED 0x01
|
||||
#define PROCFS_WANT 0x02
|
||||
|
||||
extern vop_t **procfs_vnodeop_p;
|
||||
|
||||
int procfs_root __P((struct mount *, struct vnode **));
|
||||
int procfs_rw __P((struct vop_read_args *));
|
||||
#endif /* _KERNEL */
|
@ -1,364 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
#ifndef FIX_SSTEP
|
||||
#define FIX_SSTEP(p)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* True iff process (p) is in trace wait state
|
||||
* relative to process (curp)
|
||||
*/
|
||||
#define TRACE_WAIT_P(curp, p) \
|
||||
((p)->p_stat == SSTOP && \
|
||||
(p)->p_pptr == (curp) && \
|
||||
((p)->p_flag & P_TRACED))
|
||||
|
||||
#define PROCFS_CTL_ATTACH 1
|
||||
#define PROCFS_CTL_DETACH 2
|
||||
#define PROCFS_CTL_STEP 3
|
||||
#define PROCFS_CTL_RUN 4
|
||||
#define PROCFS_CTL_WAIT 5
|
||||
|
||||
static vfs_namemap_t ctlnames[] = {
|
||||
/* special /proc commands */
|
||||
{ "attach", PROCFS_CTL_ATTACH },
|
||||
{ "detach", PROCFS_CTL_DETACH },
|
||||
{ "step", PROCFS_CTL_STEP },
|
||||
{ "run", PROCFS_CTL_RUN },
|
||||
{ "wait", PROCFS_CTL_WAIT },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static vfs_namemap_t signames[] = {
|
||||
/* regular signal names */
|
||||
{ "hup", SIGHUP }, { "int", SIGINT },
|
||||
{ "quit", SIGQUIT }, { "ill", SIGILL },
|
||||
{ "trap", SIGTRAP }, { "abrt", SIGABRT },
|
||||
{ "iot", SIGIOT }, { "emt", SIGEMT },
|
||||
{ "fpe", SIGFPE }, { "kill", SIGKILL },
|
||||
{ "bus", SIGBUS }, { "segv", SIGSEGV },
|
||||
{ "sys", SIGSYS }, { "pipe", SIGPIPE },
|
||||
{ "alrm", SIGALRM }, { "term", SIGTERM },
|
||||
{ "urg", SIGURG }, { "stop", SIGSTOP },
|
||||
{ "tstp", SIGTSTP }, { "cont", SIGCONT },
|
||||
{ "chld", SIGCHLD }, { "ttin", SIGTTIN },
|
||||
{ "ttou", SIGTTOU }, { "io", SIGIO },
|
||||
{ "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ },
|
||||
{ "vtalrm", SIGVTALRM }, { "prof", SIGPROF },
|
||||
{ "winch", SIGWINCH }, { "info", SIGINFO },
|
||||
{ "usr1", SIGUSR1 }, { "usr2", SIGUSR2 },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static int procfs_control __P((struct proc *curp, struct proc *p, int op));
|
||||
|
||||
static int
|
||||
procfs_control(curp, p, op)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
int op;
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Authorization check: rely on normal debugging protection, except
|
||||
* allow processes to disengage debugging on a process onto which
|
||||
* they have previously attached, but no longer have permission to
|
||||
* debug.
|
||||
*/
|
||||
if (op != PROCFS_CTL_DETACH &&
|
||||
((error = p_can(curp, p, P_CAN_DEBUG, NULL))))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Attach - attaches the target process for debugging
|
||||
* by the calling process.
|
||||
*/
|
||||
if (op == PROCFS_CTL_ATTACH) {
|
||||
sx_xlock(&proctree_lock);
|
||||
PROC_LOCK(p);
|
||||
if (p->p_flag & P_TRACED) {
|
||||
error = EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Can't trace yourself! */
|
||||
if (p->p_pid == curp->p_pid) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go ahead and set the trace flag.
|
||||
* Save the old parent (it's reset in
|
||||
* _DETACH, and also in kern_exit.c:wait4()
|
||||
* Reparent the process so that the tracing
|
||||
* proc gets to see all the action.
|
||||
* Stop the target.
|
||||
*/
|
||||
p->p_flag |= P_TRACED;
|
||||
faultin(p);
|
||||
p->p_xstat = 0; /* XXX ? */
|
||||
if (p->p_pptr != curp) {
|
||||
p->p_oppid = p->p_pptr->p_pid;
|
||||
proc_reparent(p, curp);
|
||||
}
|
||||
psignal(p, SIGSTOP);
|
||||
out:
|
||||
PROC_UNLOCK(p);
|
||||
sx_xunlock(&proctree_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Target process must be stopped, owned by (curp) and
|
||||
* be set up for tracing (P_TRACED flag set).
|
||||
* Allow DETACH to take place at any time for sanity.
|
||||
* Allow WAIT any time, of course.
|
||||
*/
|
||||
switch (op) {
|
||||
case PROCFS_CTL_DETACH:
|
||||
case PROCFS_CTL_WAIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
PROC_LOCK(p);
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (!TRACE_WAIT_P(curp, p)) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
PROC_UNLOCK(p);
|
||||
return (EBUSY);
|
||||
}
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FIX_SSTEP
|
||||
/*
|
||||
* do single-step fixup if needed
|
||||
*/
|
||||
FIX_SSTEP(p);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't deliver any signal by default.
|
||||
* To continue with a signal, just send
|
||||
* the signal name to the ctl file
|
||||
*/
|
||||
PROC_LOCK(p);
|
||||
p->p_xstat = 0;
|
||||
|
||||
switch (op) {
|
||||
/*
|
||||
* Detach. Cleans up the target process, reparent it if possible
|
||||
* and set it running once more.
|
||||
*/
|
||||
case PROCFS_CTL_DETACH:
|
||||
/* if not being traced, then this is a painless no-op */
|
||||
if ((p->p_flag & P_TRACED) == 0) {
|
||||
PROC_UNLOCK(p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* not being traced any more */
|
||||
p->p_flag &= ~P_TRACED;
|
||||
|
||||
/* remove pending SIGTRAP, else the process will die */
|
||||
SIGDELSET(p->p_siglist, SIGTRAP);
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
/* give process back to original parent */
|
||||
sx_xlock(&proctree_lock);
|
||||
if (p->p_oppid != p->p_pptr->p_pid) {
|
||||
struct proc *pp;
|
||||
|
||||
pp = pfind(p->p_oppid);
|
||||
PROC_LOCK(p);
|
||||
if (pp)
|
||||
proc_reparent(p, pp);
|
||||
} else
|
||||
PROC_LOCK(p);
|
||||
p->p_oppid = 0;
|
||||
p->p_flag &= ~P_WAITED; /* XXX ? */
|
||||
PROC_UNLOCK(p);
|
||||
sx_xunlock(&proctree_lock);
|
||||
|
||||
wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Step. Let the target process execute a single instruction.
|
||||
*/
|
||||
case PROCFS_CTL_STEP:
|
||||
_PHOLD(p);
|
||||
PROC_UNLOCK(p);
|
||||
error = procfs_sstep(p);
|
||||
PRELE(p);
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Run. Let the target process continue running until a breakpoint
|
||||
* or some other trap.
|
||||
*/
|
||||
case PROCFS_CTL_RUN:
|
||||
PROC_UNLOCK(p);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Wait for the target process to stop.
|
||||
* If the target is not being traced then just wait
|
||||
* to enter
|
||||
*/
|
||||
case PROCFS_CTL_WAIT:
|
||||
if (p->p_flag & P_TRACED) {
|
||||
mtx_lock_spin(&sched_lock);
|
||||
while (error == 0 &&
|
||||
(p->p_stat != SSTOP) &&
|
||||
(p->p_flag & P_TRACED) &&
|
||||
(p->p_pptr == curp)) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
error = msleep((caddr_t) p, &p->p_mtx,
|
||||
PWAIT|PCATCH, "procfsx", 0);
|
||||
mtx_lock_spin(&sched_lock);
|
||||
}
|
||||
if (error == 0 && !TRACE_WAIT_P(curp, p))
|
||||
error = EBUSY;
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
PROC_UNLOCK(p);
|
||||
} else {
|
||||
PROC_UNLOCK(p);
|
||||
mtx_lock_spin(&sched_lock);
|
||||
while (error == 0 && p->p_stat != SSTOP) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
error = tsleep((caddr_t) p,
|
||||
PWAIT|PCATCH, "procfs", 0);
|
||||
mtx_lock_spin(&sched_lock);
|
||||
}
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
return (error);
|
||||
|
||||
default:
|
||||
panic("procfs_control");
|
||||
}
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (p->p_stat == SSTOP)
|
||||
setrunnable(p);
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_doctl(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
struct proc *p;
|
||||
{
|
||||
int xlen;
|
||||
int error;
|
||||
char msg[PROCFS_CTLLEN+1];
|
||||
vfs_namemap_t *nm;
|
||||
|
||||
if (uio->uio_rw != UIO_WRITE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
xlen = PROCFS_CTLLEN;
|
||||
error = vfs_getuserstr(uio, msg, &xlen);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Map signal names into signal generation
|
||||
* or debug control. Unknown commands and/or signals
|
||||
* return EOPNOTSUPP.
|
||||
*
|
||||
* Sending a signal while the process is being debugged
|
||||
* also has the side effect of letting the target continue
|
||||
* to run. There is no way to single-step a signal delivery.
|
||||
*/
|
||||
error = EOPNOTSUPP;
|
||||
|
||||
nm = vfs_findname(ctlnames, msg, xlen);
|
||||
if (nm) {
|
||||
error = procfs_control(curp, p, nm->nm_val);
|
||||
} else {
|
||||
nm = vfs_findname(signames, msg, xlen);
|
||||
if (nm) {
|
||||
PROC_LOCK(p);
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (TRACE_WAIT_P(curp, p)) {
|
||||
p->p_xstat = nm->nm_val;
|
||||
#ifdef FIX_SSTEP
|
||||
FIX_SSTEP(p);
|
||||
#endif
|
||||
setrunnable(p);
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
} else {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
psignal(p, nm->nm_val);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Brian Scott Dean, brdean@unx.sas.com.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry under the following copyrights and conditions:
|
||||
*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
int
|
||||
procfs_dodbregs(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
struct dbreg r;
|
||||
char *kv;
|
||||
int kl;
|
||||
|
||||
if (p_can(curp, p, P_CAN_DEBUG, NULL))
|
||||
return (EPERM);
|
||||
kl = sizeof(r);
|
||||
kv = (char *) &r;
|
||||
|
||||
kv += uio->uio_offset;
|
||||
kl -= uio->uio_offset;
|
||||
if (kl > uio->uio_resid)
|
||||
kl = uio->uio_resid;
|
||||
|
||||
PHOLD(p);
|
||||
|
||||
if (kl < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
error = procfs_read_dbregs(p, &r);
|
||||
if (error == 0)
|
||||
error = uiomove(kv, kl, uio);
|
||||
if (error == 0 && uio->uio_rw == UIO_WRITE) {
|
||||
if (p->p_stat != SSTOP)
|
||||
error = EBUSY;
|
||||
else
|
||||
error = procfs_write_dbregs(p, &r);
|
||||
}
|
||||
PRELE(p);
|
||||
|
||||
uio->uio_offset = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validdbregs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_fpregs.c 8.2 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
int
|
||||
procfs_dofpregs(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
struct fpreg r;
|
||||
char *kv;
|
||||
int kl;
|
||||
|
||||
if (p_can(curp, p, P_CAN_DEBUG, NULL))
|
||||
return EPERM;
|
||||
kl = sizeof(r);
|
||||
kv = (char *) &r;
|
||||
|
||||
kv += uio->uio_offset;
|
||||
kl -= uio->uio_offset;
|
||||
if (kl > uio->uio_resid)
|
||||
kl = uio->uio_resid;
|
||||
|
||||
PHOLD(p);
|
||||
|
||||
if (kl < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
error = procfs_read_fpregs(p, &r);
|
||||
if (error == 0)
|
||||
error = uiomove(kv, kl, uio);
|
||||
if (error == 0 && uio->uio_rw == UIO_WRITE) {
|
||||
if (p->p_stat != SSTOP)
|
||||
error = EBUSY;
|
||||
else
|
||||
error = procfs_write_fpregs(p, &r);
|
||||
}
|
||||
PRELE(p);
|
||||
|
||||
uio->uio_offset = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validfpregs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_status.c 8.3 (Berkeley) 2/17/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_object.h>
|
||||
|
||||
|
||||
#define MEBUFFERSIZE 256
|
||||
|
||||
/*
|
||||
* The map entries can *almost* be read with programs like cat. However,
|
||||
* large maps need special programs to read. It is not easy to implement
|
||||
* a program that can sense the required size of the buffer, and then
|
||||
* subsequently do a read with the appropriate size. This operation cannot
|
||||
* be atomic. The best that we can do is to allow the program to do a read
|
||||
* with an arbitrarily large buffer, and return as much as we can. We can
|
||||
* return an error code if the buffer is too small (EFBIG), then the program
|
||||
* can try a bigger buffer.
|
||||
*/
|
||||
int
|
||||
procfs_domap(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int len;
|
||||
int error;
|
||||
vm_map_t map = &p->p_vmspace->vm_map;
|
||||
pmap_t pmap = vmspace_pmap(p->p_vmspace);
|
||||
vm_map_entry_t entry;
|
||||
char mebuffer[MEBUFFERSIZE];
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
if (uio->uio_offset != 0)
|
||||
return (0);
|
||||
|
||||
error = 0;
|
||||
if (map != &curproc->p_vmspace->vm_map)
|
||||
vm_map_lock_read(map);
|
||||
for (entry = map->header.next;
|
||||
((uio->uio_resid > 0) && (entry != &map->header));
|
||||
entry = entry->next) {
|
||||
vm_object_t obj, tobj, lobj;
|
||||
int ref_count, shadow_count, flags;
|
||||
vm_offset_t addr;
|
||||
int resident, privateresident;
|
||||
char *type;
|
||||
|
||||
if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
|
||||
continue;
|
||||
|
||||
obj = entry->object.vm_object;
|
||||
if (obj && (obj->shadow_count == 1))
|
||||
privateresident = obj->resident_page_count;
|
||||
else
|
||||
privateresident = 0;
|
||||
|
||||
resident = 0;
|
||||
addr = entry->start;
|
||||
while (addr < entry->end) {
|
||||
if (pmap_extract( pmap, addr))
|
||||
resident++;
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
for( lobj = tobj = obj; tobj; tobj = tobj->backing_object)
|
||||
lobj = tobj;
|
||||
|
||||
if (lobj) {
|
||||
switch(lobj->type) {
|
||||
|
||||
default:
|
||||
case OBJT_DEFAULT:
|
||||
type = "default";
|
||||
break;
|
||||
case OBJT_VNODE:
|
||||
type = "vnode";
|
||||
break;
|
||||
case OBJT_SWAP:
|
||||
type = "swap";
|
||||
break;
|
||||
case OBJT_DEVICE:
|
||||
type = "device";
|
||||
break;
|
||||
}
|
||||
|
||||
flags = obj->flags;
|
||||
ref_count = obj->ref_count;
|
||||
shadow_count = obj->shadow_count;
|
||||
} else {
|
||||
type = "none";
|
||||
flags = 0;
|
||||
ref_count = 0;
|
||||
shadow_count = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format:
|
||||
* start, end, resident, private resident, cow, access, type.
|
||||
*/
|
||||
snprintf(mebuffer, sizeof(mebuffer),
|
||||
"0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s\n",
|
||||
(u_long)entry->start, (u_long)entry->end,
|
||||
resident, privateresident, obj,
|
||||
(entry->protection & VM_PROT_READ)?"r":"-",
|
||||
(entry->protection & VM_PROT_WRITE)?"w":"-",
|
||||
(entry->protection & VM_PROT_EXECUTE)?"x":"-",
|
||||
ref_count, shadow_count, flags,
|
||||
(entry->eflags & MAP_ENTRY_COW)?"COW":"NCOW",
|
||||
(entry->eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC",
|
||||
type);
|
||||
|
||||
len = strlen(mebuffer);
|
||||
if (len > uio->uio_resid) {
|
||||
error = EFBIG;
|
||||
break;
|
||||
}
|
||||
error = uiomove(mebuffer, len, uio);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (map != &curproc->p_vmspace->vm_map)
|
||||
vm_map_unlock_read(map);
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validmap(p)
|
||||
struct proc *p;
|
||||
{
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993 Sean Eric Fagan
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry and Sean Eric Fagan.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a lightly hacked and merged version
|
||||
* of sef's pread/pwrite functions
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
static int procfs_rwmem __P((struct proc *curp,
|
||||
struct proc *p, struct uio *uio));
|
||||
|
||||
static int
|
||||
procfs_rwmem(curp, p, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
int writing;
|
||||
struct vmspace *vm;
|
||||
vm_map_t map;
|
||||
vm_object_t object = NULL;
|
||||
vm_offset_t pageno = 0; /* page number */
|
||||
vm_prot_t reqprot;
|
||||
vm_offset_t kva;
|
||||
|
||||
/*
|
||||
* if the vmspace is in the midst of being deallocated or the
|
||||
* process is exiting, don't try to grab anything. The page table
|
||||
* usage in that process can be messed up.
|
||||
*/
|
||||
vm = p->p_vmspace;
|
||||
if ((p->p_flag & P_WEXIT))
|
||||
return EFAULT;
|
||||
|
||||
mtx_lock(&vm_mtx);
|
||||
if (vm->vm_refcnt < 1) {
|
||||
mtx_unlock(&vm_mtx);
|
||||
return EFAULT;
|
||||
}
|
||||
++vm->vm_refcnt;
|
||||
/*
|
||||
* The map we want...
|
||||
*/
|
||||
map = &vm->vm_map;
|
||||
|
||||
writing = uio->uio_rw == UIO_WRITE;
|
||||
reqprot = writing ? (VM_PROT_WRITE | VM_PROT_OVERRIDE_WRITE) : VM_PROT_READ;
|
||||
|
||||
kva = kmem_alloc_pageable(kernel_map, PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Only map in one page at a time. We don't have to, but it
|
||||
* makes things easier. This way is trivial - right?
|
||||
*/
|
||||
do {
|
||||
vm_map_t tmap;
|
||||
vm_offset_t uva;
|
||||
int page_offset; /* offset into page */
|
||||
vm_map_entry_t out_entry;
|
||||
vm_prot_t out_prot;
|
||||
boolean_t wired;
|
||||
vm_pindex_t pindex;
|
||||
u_int len;
|
||||
vm_page_t m;
|
||||
|
||||
object = NULL;
|
||||
|
||||
uva = (vm_offset_t) uio->uio_offset;
|
||||
|
||||
/*
|
||||
* Get the page number of this segment.
|
||||
*/
|
||||
pageno = trunc_page(uva);
|
||||
page_offset = uva - pageno;
|
||||
|
||||
/*
|
||||
* How many bytes to copy
|
||||
*/
|
||||
len = min(PAGE_SIZE - page_offset, uio->uio_resid);
|
||||
|
||||
/*
|
||||
* Fault the page on behalf of the process
|
||||
*/
|
||||
error = vm_fault(map, pageno, reqprot, VM_FAULT_NORMAL);
|
||||
if (error) {
|
||||
error = EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to get the page. out_entry, out_prot, wired,
|
||||
* and single_use aren't used. One would think the vm code
|
||||
* would be a *bit* nicer... We use tmap because
|
||||
* vm_map_lookup() can change the map argument.
|
||||
*/
|
||||
tmap = map;
|
||||
error = vm_map_lookup(&tmap, pageno, reqprot,
|
||||
&out_entry, &object, &pindex, &out_prot,
|
||||
&wired);
|
||||
|
||||
if (error) {
|
||||
error = EFAULT;
|
||||
|
||||
/*
|
||||
* Make sure that there is no residue in 'object' from
|
||||
* an error return on vm_map_lookup.
|
||||
*/
|
||||
object = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
m = vm_page_lookup(object, pindex);
|
||||
|
||||
/* Allow fallback to backing objects if we are reading */
|
||||
|
||||
while (m == NULL && !writing && object->backing_object) {
|
||||
|
||||
pindex += OFF_TO_IDX(object->backing_object_offset);
|
||||
object = object->backing_object;
|
||||
|
||||
m = vm_page_lookup(object, pindex);
|
||||
}
|
||||
|
||||
if (m == NULL) {
|
||||
error = EFAULT;
|
||||
|
||||
/*
|
||||
* Make sure that there is no residue in 'object' from
|
||||
* an error return on vm_map_lookup.
|
||||
*/
|
||||
object = NULL;
|
||||
|
||||
vm_map_lookup_done(tmap, out_entry);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wire the page into memory
|
||||
*/
|
||||
vm_page_wire(m);
|
||||
|
||||
/*
|
||||
* We're done with tmap now.
|
||||
* But reference the object first, so that we won't loose
|
||||
* it.
|
||||
*/
|
||||
vm_object_reference(object);
|
||||
vm_map_lookup_done(tmap, out_entry);
|
||||
|
||||
pmap_kenter(kva, VM_PAGE_TO_PHYS(m));
|
||||
|
||||
/*
|
||||
* Now do the i/o move.
|
||||
*/
|
||||
mtx_unlock(&vm_mtx);
|
||||
error = uiomove((caddr_t)(kva + page_offset), len, uio);
|
||||
mtx_lock(&vm_mtx);
|
||||
|
||||
pmap_kremove(kva);
|
||||
|
||||
/*
|
||||
* release the page and the object
|
||||
*/
|
||||
vm_page_unwire(m, 1);
|
||||
vm_object_deallocate(object);
|
||||
|
||||
object = NULL;
|
||||
|
||||
} while (error == 0 && uio->uio_resid > 0);
|
||||
|
||||
if (object)
|
||||
vm_object_deallocate(object);
|
||||
|
||||
kmem_free(kernel_map, kva, PAGE_SIZE);
|
||||
vmspace_free(vm);
|
||||
mtx_unlock(&vm_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data in and out of the target process.
|
||||
* We do this by mapping the process's page into
|
||||
* the kernel and then doing a uiomove direct
|
||||
* from the kernel address space.
|
||||
*/
|
||||
int
|
||||
procfs_domem(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We need to check for KMEM_GROUP because ps is sgid kmem;
|
||||
* not allowing it here causes ps to not work properly. Arguably,
|
||||
* this is a bug with what ps does. We only need to do this
|
||||
* for Pmem nodes, and only if it's reading. This is still not
|
||||
* good, as it may still be possible to grab illicit data if
|
||||
* a process somehow gets to be KMEM_GROUP. Note that this also
|
||||
* means that KMEM_GROUP can't change without editing procfs.h!
|
||||
* All in all, quite yucky.
|
||||
*/
|
||||
|
||||
if (p_can(curp, p, P_CAN_DEBUG, NULL) &&
|
||||
!(uio->uio_rw == UIO_READ &&
|
||||
procfs_kmemaccess(curp)))
|
||||
return EPERM;
|
||||
|
||||
return (procfs_rwmem(curp, p, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* Given process (p), find the vnode from which
|
||||
* its text segment is being executed.
|
||||
*
|
||||
* It would be nice to grab this information from
|
||||
* the VM system, however, there is no sure-fire
|
||||
* way of doing that. Instead, fork(), exec() and
|
||||
* wait() all maintain the p_textvp field in the
|
||||
* process proc structure which contains a held
|
||||
* reference to the exec'ed vnode.
|
||||
*
|
||||
* XXX - Currently, this is not not used, as the
|
||||
* /proc/pid/file object exposes an information leak
|
||||
* that shouldn't happen. Using a mount option would
|
||||
* make it configurable on a per-system (or, at least,
|
||||
* per-mount) basis; however, that's not really best.
|
||||
* The best way to do it, I think, would be as an
|
||||
* ioctl; this would restrict it to the uid running
|
||||
* program, or root, which seems a reasonable compromise.
|
||||
* However, the number of applications for this is
|
||||
* minimal, if it can't be seen in the filesytem space,
|
||||
* and doint it as an ioctl makes it somewhat less
|
||||
* useful due to the, well, inelegance.
|
||||
*
|
||||
*/
|
||||
struct vnode *
|
||||
procfs_findtextvp(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (p->p_textvp);
|
||||
}
|
||||
|
||||
int procfs_kmemaccess(curp)
|
||||
struct proc *curp;
|
||||
{
|
||||
int i;
|
||||
struct ucred *cred;
|
||||
|
||||
cred = curp->p_ucred;
|
||||
if (suser(curp))
|
||||
return 1;
|
||||
|
||||
/* XXX: Why isn't this done with file-perms ??? */
|
||||
for (i = 0; i < cred->cr_ngroups; i++)
|
||||
if (cred->cr_groups[i] == KMEM_GROUP)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_note.c 8.2 (Berkeley) 1/21/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_donote(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int xlen;
|
||||
int error;
|
||||
char note[PROCFS_NOTELEN+1];
|
||||
|
||||
if (uio->uio_rw != UIO_WRITE)
|
||||
return (EINVAL);
|
||||
|
||||
xlen = PROCFS_NOTELEN;
|
||||
error = vfs_getuserstr(uio, note, &xlen);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* send to process's notify function */
|
||||
return (EOPNOTSUPP);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_regs.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_doregs(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
struct reg r;
|
||||
char *kv;
|
||||
int kl;
|
||||
|
||||
if (p_can(curp, p, P_CAN_DEBUG, NULL))
|
||||
return EPERM;
|
||||
kl = sizeof(r);
|
||||
kv = (char *) &r;
|
||||
|
||||
kv += uio->uio_offset;
|
||||
kl -= uio->uio_offset;
|
||||
if (kl > uio->uio_resid)
|
||||
kl = uio->uio_resid;
|
||||
|
||||
PHOLD(p);
|
||||
|
||||
if (kl < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
error = procfs_read_regs(p, &r);
|
||||
if (error == 0)
|
||||
error = uiomove(kv, kl, uio);
|
||||
if (error == 0 && uio->uio_rw == UIO_WRITE) {
|
||||
if (p->p_stat != SSTOP)
|
||||
error = EBUSY;
|
||||
else
|
||||
error = procfs_write_regs(p, &r);
|
||||
}
|
||||
PRELE(p);
|
||||
|
||||
uio->uio_offset = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validregs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Adrian Chadd
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* To get resource.h to include our rlimit_ident[] array of rlimit identifiers
|
||||
*/
|
||||
|
||||
#define _RLIMIT_IDENT
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
|
||||
int
|
||||
procfs_dorlimit(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
char *ps;
|
||||
int i;
|
||||
int xlen;
|
||||
int error;
|
||||
char psbuf[512]; /* XXX - conservative */
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
|
||||
ps = psbuf;
|
||||
|
||||
for (i = 0; i < RLIM_NLIMITS; i++) {
|
||||
|
||||
/*
|
||||
* Add the rlimit ident
|
||||
*/
|
||||
|
||||
ps += sprintf(ps, "%s ", rlimit_ident[i]);
|
||||
|
||||
/*
|
||||
* Replace RLIM_INFINITY with -1 in the string
|
||||
*/
|
||||
|
||||
/*
|
||||
* current limit
|
||||
*/
|
||||
|
||||
if (p->p_rlimit[i].rlim_cur == RLIM_INFINITY) {
|
||||
ps += sprintf(ps, "-1 ");
|
||||
} else {
|
||||
ps += sprintf(ps, "%llu ",
|
||||
(unsigned long long)p->p_rlimit[i].rlim_cur);
|
||||
}
|
||||
|
||||
/*
|
||||
* maximum limit
|
||||
*/
|
||||
|
||||
if (p->p_rlimit[i].rlim_max == RLIM_INFINITY) {
|
||||
ps += sprintf(ps, "-1\n");
|
||||
} else {
|
||||
ps += sprintf(ps, "%llu\n",
|
||||
(unsigned long long)p->p_rlimit[i].rlim_max);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This logic is rather tasty - but its from procfs_status.c, so
|
||||
* I guess I'll use it here.
|
||||
*/
|
||||
|
||||
xlen = ps - psbuf;
|
||||
xlen -= uio->uio_offset;
|
||||
ps = psbuf + uio->uio_offset;
|
||||
xlen = imin(xlen, uio->uio_resid);
|
||||
if (xlen <= 0)
|
||||
error = 0;
|
||||
else
|
||||
error = uiomove(ps, xlen, uio);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_param.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#define DOCHECK() do { if (ps >= psbuf+sizeof(psbuf)) goto bailout; } while (0)
|
||||
int
|
||||
procfs_dostatus(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
struct session *sess;
|
||||
struct tty *tp;
|
||||
struct ucred *cr;
|
||||
char *ps;
|
||||
char *sep;
|
||||
int pid, ppid, pgid, sid;
|
||||
int i;
|
||||
int xlen;
|
||||
int error;
|
||||
char psbuf[256]; /* XXX - conservative */
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
pid = p->p_pid;
|
||||
PROC_LOCK(p);
|
||||
ppid = p->p_pptr ? p->p_pptr->p_pid : 0;
|
||||
PROC_UNLOCK(p);
|
||||
pgid = p->p_pgrp->pg_id;
|
||||
sess = p->p_pgrp->pg_session;
|
||||
sid = sess->s_leader ? sess->s_leader->p_pid : 0;
|
||||
|
||||
/* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg
|
||||
euid ruid rgid,egid,groups[1 .. NGROUPS]
|
||||
*/
|
||||
KASSERT(sizeof(psbuf) > MAXCOMLEN,
|
||||
("Too short buffer for new MAXCOMLEN"));
|
||||
|
||||
ps = psbuf;
|
||||
bcopy(p->p_comm, ps, MAXCOMLEN);
|
||||
ps[MAXCOMLEN] = '\0';
|
||||
ps += strlen(ps);
|
||||
DOCHECK();
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
" %d %d %d %d ", pid, ppid, pgid, sid);
|
||||
DOCHECK();
|
||||
if ((p->p_flag&P_CONTROLT) && (tp = sess->s_ttyp))
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
"%d,%d ", major(tp->t_dev), minor(tp->t_dev));
|
||||
else
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
"%d,%d ", -1, -1);
|
||||
DOCHECK();
|
||||
|
||||
sep = "";
|
||||
if (sess->s_ttyvp) {
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%sctty", sep);
|
||||
sep = ",";
|
||||
DOCHECK();
|
||||
}
|
||||
if (SESS_LEADER(p)) {
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%ssldr", sep);
|
||||
sep = ",";
|
||||
DOCHECK();
|
||||
}
|
||||
if (*sep != ',') {
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "noflags");
|
||||
DOCHECK();
|
||||
}
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (p->p_sflag & PS_INMEM) {
|
||||
struct timeval ut, st;
|
||||
|
||||
calcru(p, &ut, &st, (struct timeval *) NULL);
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
" %ld,%ld %ld,%ld %ld,%ld",
|
||||
p->p_stats->p_start.tv_sec,
|
||||
p->p_stats->p_start.tv_usec,
|
||||
ut.tv_sec, ut.tv_usec,
|
||||
st.tv_sec, st.tv_usec);
|
||||
} else {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
" -1,-1 -1,-1 -1,-1");
|
||||
}
|
||||
DOCHECK();
|
||||
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s",
|
||||
(p->p_wchan && p->p_wmesg) ? p->p_wmesg : "nochan");
|
||||
DOCHECK();
|
||||
|
||||
cr = p->p_ucred;
|
||||
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %lu %lu %lu",
|
||||
(u_long)cr->cr_uid,
|
||||
(u_long)p->p_cred->p_ruid,
|
||||
(u_long)p->p_cred->p_rgid);
|
||||
DOCHECK();
|
||||
|
||||
/* egid (p->p_cred->p_svgid) is equal to cr_ngroups[0]
|
||||
see also getegid(2) in /sys/kern/kern_prot.c */
|
||||
|
||||
for (i = 0; i < cr->cr_ngroups; i++) {
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
",%lu", (u_long)cr->cr_groups[i]);
|
||||
DOCHECK();
|
||||
}
|
||||
|
||||
if (jailed(p->p_ucred))
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
|
||||
" %s", p->p_ucred->cr_prison->pr_host);
|
||||
else
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -");
|
||||
DOCHECK();
|
||||
ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n");
|
||||
DOCHECK();
|
||||
|
||||
xlen = ps - psbuf;
|
||||
xlen -= uio->uio_offset;
|
||||
ps = psbuf + uio->uio_offset;
|
||||
xlen = imin(xlen, uio->uio_resid);
|
||||
if (xlen <= 0)
|
||||
error = 0;
|
||||
else
|
||||
error = uiomove(ps, xlen, uio);
|
||||
|
||||
return (error);
|
||||
|
||||
bailout:
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_docmdline(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
char *ps;
|
||||
int xlen;
|
||||
int error;
|
||||
char *buf, *bp;
|
||||
int buflen;
|
||||
struct ps_strings pstr;
|
||||
int i;
|
||||
size_t bytes_left, done;
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
/*
|
||||
* If we are using the ps/cmdline caching, use that. Otherwise
|
||||
* revert back to the old way which only implements full cmdline
|
||||
* for the currept process and just p->p_comm for all other
|
||||
* processes.
|
||||
* Note that if the argv is no longer available, we deliberately
|
||||
* don't fall back on p->p_comm or return an error: the authentic
|
||||
* Linux behaviour is to return zero-length in this case.
|
||||
*/
|
||||
|
||||
if (p->p_args && (ps_argsopen || !p_can(curp, p, P_CAN_SEE, NULL))) {
|
||||
bp = p->p_args->ar_args;
|
||||
buflen = p->p_args->ar_length;
|
||||
buf = 0;
|
||||
} else if (p != curp) {
|
||||
bp = p->p_comm;
|
||||
buflen = MAXCOMLEN;
|
||||
buf = 0;
|
||||
} else {
|
||||
buflen = 256;
|
||||
MALLOC(buf, char *, buflen + 1, M_TEMP, M_WAITOK);
|
||||
bp = buf;
|
||||
ps = buf;
|
||||
error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
|
||||
if (error) {
|
||||
FREE(buf, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
bytes_left = buflen;
|
||||
for (i = 0; bytes_left && (i < pstr.ps_nargvstr); i++) {
|
||||
error = copyinstr(pstr.ps_argvstr[i], ps,
|
||||
bytes_left, &done);
|
||||
/* If too long or malformed, just truncate */
|
||||
if (error) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
ps += done;
|
||||
bytes_left -= done;
|
||||
}
|
||||
buflen = ps - buf;
|
||||
}
|
||||
|
||||
buflen -= uio->uio_offset;
|
||||
ps = bp + uio->uio_offset;
|
||||
xlen = min(buflen, uio->uio_resid);
|
||||
if (xlen <= 0)
|
||||
error = 0;
|
||||
else
|
||||
error = uiomove(ps, xlen, uio);
|
||||
if (buf)
|
||||
FREE(buf, M_TEMP);
|
||||
return (error);
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
static struct pfsnode *pfshead;
|
||||
static int pfsvplock;
|
||||
|
||||
/*
|
||||
* allocate a pfsnode/vnode pair. the vnode is
|
||||
* referenced, but not locked.
|
||||
*
|
||||
* the pid, pfs_type, and mount point uniquely
|
||||
* identify a pfsnode. the mount point is needed
|
||||
* because someone might mount this filesystem
|
||||
* twice.
|
||||
*
|
||||
* all pfsnodes are maintained on a singly-linked
|
||||
* list. new nodes are only allocated when they cannot
|
||||
* be found on this list. entries on the list are
|
||||
* removed when the vfs reclaim entry is called.
|
||||
*
|
||||
* a single lock is kept for the entire list. this is
|
||||
* needed because the getnewvnode() function can block
|
||||
* waiting for a vnode to become free, in which case there
|
||||
* may be more than one process trying to get the same
|
||||
* vnode. this lock is only taken if we are going to
|
||||
* call getnewvnode, since the kernel itself is single-threaded.
|
||||
*
|
||||
* if an entry is found on the list, then call vget() to
|
||||
* take a reference. this is done because there may be
|
||||
* zero references to it and so it needs to removed from
|
||||
* the vnode free list.
|
||||
*/
|
||||
int
|
||||
procfs_allocvp(mp, vpp, pid, pfs_type)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
long pid;
|
||||
pfstype pfs_type;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct pfsnode *pfs;
|
||||
struct vnode *vp;
|
||||
struct pfsnode **pp;
|
||||
int error;
|
||||
|
||||
loop:
|
||||
for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
|
||||
vp = PFSTOV(pfs);
|
||||
if (pfs->pfs_pid == pid &&
|
||||
pfs->pfs_type == pfs_type &&
|
||||
vp->v_mount == mp) {
|
||||
if (vget(vp, 0, p))
|
||||
goto loop;
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* otherwise lock the vp list while we call getnewvnode
|
||||
* since that can block.
|
||||
*/
|
||||
if (pfsvplock & PROCFS_LOCKED) {
|
||||
pfsvplock |= PROCFS_WANT;
|
||||
(void) tsleep((caddr_t) &pfsvplock, PINOD, "pfsavp", 0);
|
||||
goto loop;
|
||||
}
|
||||
pfsvplock |= PROCFS_LOCKED;
|
||||
|
||||
/*
|
||||
* Do the MALLOC before the getnewvnode since doing so afterward
|
||||
* might cause a bogus v_data pointer to get dereferenced
|
||||
* elsewhere if MALLOC should block.
|
||||
*/
|
||||
MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
|
||||
|
||||
if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0) {
|
||||
FREE(pfs, M_TEMP);
|
||||
goto out;
|
||||
}
|
||||
vp = *vpp;
|
||||
|
||||
vp->v_data = pfs;
|
||||
|
||||
pfs->pfs_next = 0;
|
||||
pfs->pfs_pid = (pid_t) pid;
|
||||
pfs->pfs_type = pfs_type;
|
||||
pfs->pfs_vnode = vp;
|
||||
pfs->pfs_flags = 0;
|
||||
pfs->pfs_lockowner = 0;
|
||||
pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
|
||||
|
||||
switch (pfs_type) {
|
||||
case Proot: /* /proc = dr-xr-xr-x */
|
||||
pfs->pfs_mode = (VREAD|VEXEC) |
|
||||
(VREAD|VEXEC) >> 3 |
|
||||
(VREAD|VEXEC) >> 6;
|
||||
vp->v_type = VDIR;
|
||||
vp->v_flag = VROOT;
|
||||
break;
|
||||
|
||||
case Pcurproc: /* /proc/curproc = lr--r--r-- */
|
||||
pfs->pfs_mode = (VREAD) |
|
||||
(VREAD >> 3) |
|
||||
(VREAD >> 6);
|
||||
vp->v_type = VLNK;
|
||||
break;
|
||||
|
||||
case Pproc:
|
||||
pfs->pfs_mode = (VREAD|VEXEC) |
|
||||
(VREAD|VEXEC) >> 3 |
|
||||
(VREAD|VEXEC) >> 6;
|
||||
vp->v_type = VDIR;
|
||||
break;
|
||||
|
||||
case Pfile:
|
||||
pfs->pfs_mode = (VREAD|VEXEC) |
|
||||
(VREAD|VEXEC) >> 3 |
|
||||
(VREAD|VEXEC) >> 6;
|
||||
vp->v_type = VLNK;
|
||||
break;
|
||||
|
||||
case Pmem:
|
||||
pfs->pfs_mode = (VREAD|VWRITE) |
|
||||
(VREAD) >> 3;;
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
case Pregs:
|
||||
case Pfpregs:
|
||||
case Pdbregs:
|
||||
pfs->pfs_mode = (VREAD|VWRITE);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
case Pctl:
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
pfs->pfs_mode = (VWRITE);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
case Ptype:
|
||||
case Pmap:
|
||||
case Pstatus:
|
||||
case Pcmdline:
|
||||
case Prlimit:
|
||||
pfs->pfs_mode = (VREAD) |
|
||||
(VREAD >> 3) |
|
||||
(VREAD >> 6);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("procfs_allocvp");
|
||||
}
|
||||
|
||||
/* add to procfs vnode list */
|
||||
for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
|
||||
continue;
|
||||
*pp = pfs;
|
||||
|
||||
out:
|
||||
pfsvplock &= ~PROCFS_LOCKED;
|
||||
|
||||
if (pfsvplock & PROCFS_WANT) {
|
||||
pfsvplock &= ~PROCFS_WANT;
|
||||
wakeup((caddr_t) &pfsvplock);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_freevp(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
struct pfsnode **pfspp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
|
||||
for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
|
||||
if (*pfspp == pfs) {
|
||||
*pfspp = pfs->pfs_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_rw(ap)
|
||||
struct vop_read_args *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct proc *curp = uio->uio_procp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
struct proc *p;
|
||||
int rtval;
|
||||
|
||||
p = PFIND(pfs->pfs_pid);
|
||||
if (p == NULL)
|
||||
return (EINVAL);
|
||||
PROC_UNLOCK(p);
|
||||
if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE)
|
||||
return (EACCES);
|
||||
|
||||
mp_fixme("pfs_lockowner needs a lock");
|
||||
while (pfs->pfs_lockowner) {
|
||||
tsleep(&pfs->pfs_lockowner, PRIBIO, "pfslck", 0);
|
||||
}
|
||||
pfs->pfs_lockowner = curproc->p_pid;
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
rtval = procfs_donote(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pregs:
|
||||
rtval = procfs_doregs(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pfpregs:
|
||||
rtval = procfs_dofpregs(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pdbregs:
|
||||
rtval = procfs_dodbregs(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pctl:
|
||||
rtval = procfs_doctl(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pstatus:
|
||||
rtval = procfs_dostatus(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pmap:
|
||||
rtval = procfs_domap(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pmem:
|
||||
rtval = procfs_domem(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Ptype:
|
||||
rtval = procfs_dotype(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Pcmdline:
|
||||
rtval = procfs_docmdline(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
case Prlimit:
|
||||
rtval = procfs_dorlimit(curp, p, pfs, uio);
|
||||
break;
|
||||
|
||||
default:
|
||||
rtval = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
pfs->pfs_lockowner = 0;
|
||||
wakeup(&pfs->pfs_lockowner);
|
||||
return rtval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a string from userland into (buf). Strip a trailing
|
||||
* nl character (to allow easy access from the shell).
|
||||
* The buffer should be *buflenp + 1 chars long. vfs_getuserstr
|
||||
* will automatically add a nul char at the end.
|
||||
*
|
||||
* Returns 0 on success or the following errors
|
||||
*
|
||||
* EINVAL: file offset is non-zero.
|
||||
* EMSGSIZE: message is longer than kernel buffer
|
||||
* EFAULT: user i/o buffer is not addressable
|
||||
*/
|
||||
int
|
||||
vfs_getuserstr(uio, buf, buflenp)
|
||||
struct uio *uio;
|
||||
char *buf;
|
||||
int *buflenp;
|
||||
{
|
||||
int xlen;
|
||||
int error;
|
||||
|
||||
if (uio->uio_offset != 0)
|
||||
return (EINVAL);
|
||||
|
||||
xlen = *buflenp;
|
||||
|
||||
/* must be able to read the whole string in one go */
|
||||
if (xlen < uio->uio_resid)
|
||||
return (EMSGSIZE);
|
||||
xlen = uio->uio_resid;
|
||||
|
||||
if ((error = uiomove(buf, xlen, uio)) != 0)
|
||||
return (error);
|
||||
|
||||
/* allow multiple writes without seeks */
|
||||
uio->uio_offset = 0;
|
||||
|
||||
/* cleanup string and remove trailing newline */
|
||||
buf[xlen] = '\0';
|
||||
xlen = strlen(buf);
|
||||
if (xlen > 0 && buf[xlen-1] == '\n')
|
||||
buf[--xlen] = '\0';
|
||||
*buflenp = xlen;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
vfs_namemap_t *
|
||||
vfs_findname(nm, buf, buflen)
|
||||
vfs_namemap_t *nm;
|
||||
char *buf;
|
||||
int buflen;
|
||||
{
|
||||
|
||||
for (; nm->nm_name; nm++)
|
||||
if (bcmp(buf, nm->nm_name, buflen+1) == 0)
|
||||
return (nm);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
procfs_exit(struct proc *p)
|
||||
{
|
||||
struct pfsnode *pfs;
|
||||
pid_t pid = p->p_pid;
|
||||
|
||||
/*
|
||||
* The reason for this loop is not obvious -- basicly,
|
||||
* procfs_freevp(), which is called via vgone() (eventually),
|
||||
* removes the specified procfs node from the pfshead list.
|
||||
* It does this by *pfsp = pfs->pfs_next, meaning that it
|
||||
* overwrites the node. So when we do pfs = pfs->next, we
|
||||
* end up skipping the node that replaces the one that was
|
||||
* vgone'd. Since it may have been the last one on the list,
|
||||
* it may also have been set to null -- but *our* pfs pointer,
|
||||
* here, doesn't see this. So the loop starts from the beginning
|
||||
* again.
|
||||
*
|
||||
* This is not a for() loop because the final event
|
||||
* would be "pfs = pfs->pfs_next"; in the case where
|
||||
* pfs is set to pfshead again, that would mean that
|
||||
* pfshead is skipped over.
|
||||
*
|
||||
*/
|
||||
pfs = pfshead;
|
||||
while (pfs) {
|
||||
if (pfs->pfs_pid == pid) {
|
||||
vgone(PFSTOV(pfs));
|
||||
pfs = pfshead;
|
||||
} else
|
||||
pfs = pfs->pfs_next;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_dotype(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int len;
|
||||
int error;
|
||||
/*
|
||||
* buffer for emulation type
|
||||
*/
|
||||
char mebuffer[256];
|
||||
char *none = "Not Available";
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
if (uio->uio_offset != 0)
|
||||
return (0);
|
||||
|
||||
if (p && p->p_sysent && p->p_sysent->sv_name) {
|
||||
len = strlen(p->p_sysent->sv_name);
|
||||
bcopy(p->p_sysent->sv_name, mebuffer, len);
|
||||
} else {
|
||||
len = strlen(none);
|
||||
bcopy(none, mebuffer, len);
|
||||
}
|
||||
mebuffer[len++] = '\n';
|
||||
error = uiomove(mebuffer, len, uio);
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validtype(p)
|
||||
struct proc *p;
|
||||
{
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* procfs VFS interface
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
static int procfs_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
static int procfs_statfs __P((struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p));
|
||||
static int procfs_unmount __P((struct mount *mp, int mntflags,
|
||||
struct proc *p));
|
||||
|
||||
/*
|
||||
* VFS Operations.
|
||||
*
|
||||
* mount system call
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
procfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
size_t size;
|
||||
int error;
|
||||
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
if (mp->mnt_vfc->vfc_refcount == 1 && (error = at_exit(procfs_exit))) {
|
||||
printf("procfs: cannot register procfs_exit with at_exit\n");
|
||||
return(error);
|
||||
}
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = 0;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
size = sizeof("procfs") - 1;
|
||||
bcopy("procfs", mp->mnt_stat.f_mntfromname, size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
(void)procfs_statfs(mp, &mp->mnt_stat, p);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* unmount system call
|
||||
*/
|
||||
static int
|
||||
procfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
error = vflush(mp, 0, flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (mp->mnt_vfc->vfc_refcount == 1)
|
||||
rm_at_exit(procfs_exit);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return (procfs_allocvp(mp, vpp, 0, Proot));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get file system statistics.
|
||||
*/
|
||||
static int
|
||||
procfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
sbp->f_bsize = PAGE_SIZE;
|
||||
sbp->f_iosize = PAGE_SIZE;
|
||||
sbp->f_blocks = 1; /* avoid divide by zero in some df's */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = maxproc; /* approx */
|
||||
sbp->f_ffree = maxproc - nprocs; /* approx */
|
||||
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct vfsops procfs_vfsops = {
|
||||
procfs_mount,
|
||||
vfs_stdstart,
|
||||
procfs_unmount,
|
||||
procfs_root,
|
||||
vfs_stdquotactl,
|
||||
procfs_statfs,
|
||||
vfs_stdsync,
|
||||
vfs_stdvget,
|
||||
vfs_stdfhtovp,
|
||||
vfs_stdcheckexp,
|
||||
vfs_stdvptofh,
|
||||
vfs_stdinit,
|
||||
vfs_stduninit,
|
||||
vfs_stdextattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(procfs_vfsops, procfs, VFCF_SYNTHETIC);
|
||||
MODULE_VERSION(procfs, 1);
|
File diff suppressed because it is too large
Load Diff
@ -1,838 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1989, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <sys/tty.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pager.h>
|
||||
|
||||
static int spec_advlock __P((struct vop_advlock_args *));
|
||||
static int spec_bmap __P((struct vop_bmap_args *));
|
||||
static int spec_close __P((struct vop_close_args *));
|
||||
static int spec_freeblks __P((struct vop_freeblks_args *));
|
||||
static int spec_fsync __P((struct vop_fsync_args *));
|
||||
static int spec_getpages __P((struct vop_getpages_args *));
|
||||
static int spec_ioctl __P((struct vop_ioctl_args *));
|
||||
static int spec_open __P((struct vop_open_args *));
|
||||
static int spec_poll __P((struct vop_poll_args *));
|
||||
static int spec_kqfilter __P((struct vop_kqfilter_args *));
|
||||
static int spec_print __P((struct vop_print_args *));
|
||||
static int spec_read __P((struct vop_read_args *));
|
||||
static int spec_strategy __P((struct vop_strategy_args *));
|
||||
static int spec_write __P((struct vop_write_args *));
|
||||
|
||||
vop_t **spec_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_advlock_desc, (vop_t *) spec_advlock },
|
||||
{ &vop_bmap_desc, (vop_t *) spec_bmap },
|
||||
{ &vop_close_desc, (vop_t *) spec_close },
|
||||
{ &vop_create_desc, (vop_t *) vop_panic },
|
||||
{ &vop_freeblks_desc, (vop_t *) spec_freeblks },
|
||||
{ &vop_fsync_desc, (vop_t *) spec_fsync },
|
||||
{ &vop_getpages_desc, (vop_t *) spec_getpages },
|
||||
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
|
||||
{ &vop_ioctl_desc, (vop_t *) spec_ioctl },
|
||||
{ &vop_lease_desc, (vop_t *) vop_null },
|
||||
{ &vop_link_desc, (vop_t *) vop_panic },
|
||||
{ &vop_mkdir_desc, (vop_t *) vop_panic },
|
||||
{ &vop_mknod_desc, (vop_t *) vop_panic },
|
||||
{ &vop_open_desc, (vop_t *) spec_open },
|
||||
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
|
||||
{ &vop_poll_desc, (vop_t *) spec_poll },
|
||||
{ &vop_kqfilter_desc, (vop_t *) spec_kqfilter },
|
||||
{ &vop_print_desc, (vop_t *) spec_print },
|
||||
{ &vop_read_desc, (vop_t *) spec_read },
|
||||
{ &vop_readdir_desc, (vop_t *) vop_panic },
|
||||
{ &vop_readlink_desc, (vop_t *) vop_panic },
|
||||
{ &vop_reallocblks_desc, (vop_t *) vop_panic },
|
||||
{ &vop_reclaim_desc, (vop_t *) vop_null },
|
||||
{ &vop_remove_desc, (vop_t *) vop_panic },
|
||||
{ &vop_rename_desc, (vop_t *) vop_panic },
|
||||
{ &vop_rmdir_desc, (vop_t *) vop_panic },
|
||||
{ &vop_setattr_desc, (vop_t *) vop_ebadf },
|
||||
{ &vop_strategy_desc, (vop_t *) spec_strategy },
|
||||
{ &vop_symlink_desc, (vop_t *) vop_panic },
|
||||
{ &vop_write_desc, (vop_t *) spec_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc spec_vnodeop_opv_desc =
|
||||
{ &spec_vnodeop_p, spec_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(spec_vnodeop_opv_desc);
|
||||
|
||||
int
|
||||
spec_vnoperate(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
return (VOCALL(spec_vnodeop_p, ap->a_desc->vdesc_offset, ap));
|
||||
}
|
||||
|
||||
static void spec_getpages_iodone __P((struct buf *bp));
|
||||
|
||||
/*
|
||||
* Open a special file.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
dev_t dev = vp->v_rdev;
|
||||
int error;
|
||||
struct cdevsw *dsw;
|
||||
const char *cp;
|
||||
|
||||
if (vp->v_type == VBLK)
|
||||
return ENXIO;
|
||||
/*
|
||||
* Don't allow open if fs is mounted -nodev.
|
||||
*/
|
||||
if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
|
||||
return (ENXIO);
|
||||
|
||||
dsw = devsw(dev);
|
||||
if ( (dsw == NULL) || (dsw->d_open == NULL))
|
||||
return ENXIO;
|
||||
|
||||
/* Make this field valid before any I/O in ->d_open */
|
||||
if (!dev->si_iosize_max)
|
||||
dev->si_iosize_max = DFLTPHYS;
|
||||
|
||||
/*
|
||||
* XXX: Disks get special billing here, but it is mostly wrong.
|
||||
* XXX: diskpartitions can overlap and the real checks should
|
||||
* XXX: take this into account, and consequently they need to
|
||||
* XXX: live in the diskslicing code. Some checks do.
|
||||
*/
|
||||
if (vn_isdisk(vp, NULL) && ap->a_cred != FSCRED &&
|
||||
(ap->a_mode & FWRITE)) {
|
||||
/*
|
||||
* Never allow opens for write if the device is mounted R/W
|
||||
*/
|
||||
if (vp->v_rdev->si_mountpoint != NULL &&
|
||||
!(vp->v_rdev->si_mountpoint->mnt_flag & MNT_RDONLY))
|
||||
return (EBUSY);
|
||||
|
||||
/*
|
||||
* When running in secure mode, do not allow opens
|
||||
* for writing if the device is mounted
|
||||
*/
|
||||
if (securelevel >= 1 && vfs_mountedon(vp))
|
||||
return (EPERM);
|
||||
|
||||
/*
|
||||
* When running in very secure mode, do not allow
|
||||
* opens for writing of any devices.
|
||||
*/
|
||||
if (securelevel >= 2)
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/* XXX: Special casing of ttys for deadfs. Probably redundant */
|
||||
if (dsw->d_flags & D_TTY)
|
||||
vp->v_flag |= VISTTY;
|
||||
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*dsw->d_open)(dev, ap->a_mode, S_IFCHR, p);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (dsw->d_flags & D_TTY) {
|
||||
if (dev->si_tty) {
|
||||
struct tty *tp;
|
||||
tp = dev->si_tty;
|
||||
if (!tp->t_stop) {
|
||||
printf("Warning:%s: no t_stop, using nottystop\n", devtoname(dev));
|
||||
tp->t_stop = nottystop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vn_isdisk(vp, NULL)) {
|
||||
if (!dev->si_bsize_phys)
|
||||
dev->si_bsize_phys = DEV_BSIZE;
|
||||
}
|
||||
if ((dsw->d_flags & D_DISK) == 0) {
|
||||
cp = devtoname(dev);
|
||||
if (*cp == '#' && (dsw->d_flags & D_NAGGED) == 0) {
|
||||
printf("WARNING: driver %s should register devices with make_dev() (dev_t = \"%s\")\n",
|
||||
dsw->d_name, cp);
|
||||
dsw->d_flags |= D_NAGGED;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp;
|
||||
struct proc *p;
|
||||
struct uio *uio;
|
||||
dev_t dev;
|
||||
int error, resid;
|
||||
|
||||
vp = ap->a_vp;
|
||||
dev = vp->v_rdev;
|
||||
uio = ap->a_uio;
|
||||
p = uio->uio_procp;
|
||||
resid = uio->uio_resid;
|
||||
|
||||
if (resid == 0)
|
||||
return (0);
|
||||
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*devsw(dev)->d_read) (dev, uio, ap->a_ioflag);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0))
|
||||
getnanotime(&dev->si_atime);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp;
|
||||
struct proc *p;
|
||||
struct uio *uio;
|
||||
dev_t dev;
|
||||
int error, resid;
|
||||
|
||||
vp = ap->a_vp;
|
||||
dev = vp->v_rdev;
|
||||
uio = ap->a_uio;
|
||||
p = uio->uio_procp;
|
||||
resid = uio->uio_resid;
|
||||
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*devsw(dev)->d_write) (dev, uio, ap->a_ioflag);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
|
||||
getnanotime(&dev->si_ctime);
|
||||
dev->si_mtime = dev->si_ctime;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
return ((*devsw(dev)->d_ioctl)(dev, ap->a_command,
|
||||
ap->a_data, ap->a_fflag, ap->a_p));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_poll(ap)
|
||||
struct vop_poll_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_events;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
return (*devsw(dev)->d_poll)(dev, ap->a_events, ap->a_p);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_kqfilter(ap)
|
||||
struct vop_kqfilter_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct knote *a_kn;
|
||||
} */ *ap;
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
if (devsw(dev)->d_flags & D_KQFILTER)
|
||||
return (*devsw(dev)->d_kqfilter)(dev, ap->a_kn);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synch buffers associated with a block device
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_fsync(ap)
|
||||
struct vop_fsync_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct ucred *a_cred;
|
||||
int a_waitfor;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct buf *bp;
|
||||
struct buf *nbp;
|
||||
int s;
|
||||
int maxretry = 10000; /* large, arbitrarily chosen */
|
||||
|
||||
if (!vn_isdisk(vp, NULL))
|
||||
return (0);
|
||||
|
||||
loop1:
|
||||
/*
|
||||
* MARK/SCAN initialization to avoid infinite loops
|
||||
*/
|
||||
s = splbio();
|
||||
TAILQ_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
|
||||
bp->b_flags &= ~B_SCANNED;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Flush all dirty buffers associated with a block device.
|
||||
*/
|
||||
loop2:
|
||||
s = splbio();
|
||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||
if ((bp->b_flags & B_SCANNED) != 0)
|
||||
continue;
|
||||
bp->b_flags |= B_SCANNED;
|
||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
|
||||
continue;
|
||||
if ((bp->b_flags & B_DELWRI) == 0)
|
||||
panic("spec_fsync: not dirty");
|
||||
if ((vp->v_flag & VOBJBUF) && (bp->b_flags & B_CLUSTEROK)) {
|
||||
BUF_UNLOCK(bp);
|
||||
vfs_bio_awrite(bp);
|
||||
splx(s);
|
||||
} else {
|
||||
bremfree(bp);
|
||||
splx(s);
|
||||
bawrite(bp);
|
||||
}
|
||||
goto loop2;
|
||||
}
|
||||
|
||||
/*
|
||||
* If synchronous the caller expects us to completely resolve all
|
||||
* dirty buffers in the system. Wait for in-progress I/O to
|
||||
* complete (which could include background bitmap writes), then
|
||||
* retry if dirty blocks still exist.
|
||||
*/
|
||||
if (ap->a_waitfor == MNT_WAIT) {
|
||||
while (vp->v_numoutput) {
|
||||
vp->v_flag |= VBWAIT;
|
||||
(void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0);
|
||||
}
|
||||
if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
|
||||
if (--maxretry != 0) {
|
||||
splx(s);
|
||||
goto loop1;
|
||||
}
|
||||
vprint("spec_fsync: giving up on dirty", vp);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just call the device strategy routine
|
||||
*/
|
||||
static int
|
||||
spec_strategy(ap)
|
||||
struct vop_strategy_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct buf *bp;
|
||||
struct vnode *vp;
|
||||
struct mount *mp;
|
||||
int error;
|
||||
|
||||
bp = ap->a_bp;
|
||||
vp = ap->a_vp;
|
||||
if ((bp->b_iocmd == BIO_WRITE)) {
|
||||
if ((bp->b_flags & B_VALIDSUSPWRT) == 0 &&
|
||||
bp->b_vp != NULL && bp->b_vp->v_mount != NULL &&
|
||||
(bp->b_vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) != 0)
|
||||
panic("spec_strategy: bad I/O");
|
||||
bp->b_flags &= ~B_VALIDSUSPWRT;
|
||||
if (LIST_FIRST(&bp->b_dep) != NULL)
|
||||
buf_start(bp);
|
||||
if ((vp->v_flag & VCOPYONWRITE) && vp->v_rdev->si_copyonwrite &&
|
||||
(error = (*vp->v_rdev->si_copyonwrite)(vp, bp)) != 0 &&
|
||||
error != EOPNOTSUPP) {
|
||||
bp->b_io.bio_error = error;
|
||||
bp->b_io.bio_flags |= BIO_ERROR;
|
||||
biodone(&bp->b_io);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Collect statistics on synchronous and asynchronous read
|
||||
* and write counts for disks that have associated filesystems.
|
||||
*/
|
||||
if (vn_isdisk(vp, NULL) && (mp = vp->v_rdev->si_mountpoint) != NULL) {
|
||||
if (bp->b_iocmd == BIO_WRITE) {
|
||||
if (bp->b_lock.lk_lockholder == LK_KERNPROC)
|
||||
mp->mnt_stat.f_asyncwrites++;
|
||||
else
|
||||
mp->mnt_stat.f_syncwrites++;
|
||||
} else {
|
||||
if (bp->b_lock.lk_lockholder == LK_KERNPROC)
|
||||
mp->mnt_stat.f_asyncreads++;
|
||||
else
|
||||
mp->mnt_stat.f_syncreads++;
|
||||
}
|
||||
}
|
||||
KASSERT(devsw(bp->b_dev) != NULL,
|
||||
("No devsw on dev %s responsible for buffer %p\n",
|
||||
devtoname(bp->b_dev), bp));
|
||||
KASSERT(devsw(bp->b_dev)->d_strategy != NULL,
|
||||
("No strategy on dev %s responsible for buffer %p\n",
|
||||
devtoname(bp->b_dev), bp));
|
||||
DEV_STRATEGY(bp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
spec_freeblks(ap)
|
||||
struct vop_freeblks_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_addr;
|
||||
daddr_t a_length;
|
||||
} */ *ap;
|
||||
{
|
||||
struct cdevsw *bsw;
|
||||
struct buf *bp;
|
||||
|
||||
/*
|
||||
* XXX: This assumes that strategy does the deed right away.
|
||||
* XXX: this may not be TRTTD.
|
||||
*/
|
||||
bsw = devsw(ap->a_vp->v_rdev);
|
||||
if ((bsw->d_flags & D_CANFREE) == 0)
|
||||
return (0);
|
||||
bp = geteblk(ap->a_length);
|
||||
bp->b_iocmd = BIO_DELETE;
|
||||
bp->b_dev = ap->a_vp->v_rdev;
|
||||
bp->b_blkno = ap->a_addr;
|
||||
bp->b_offset = dbtob(ap->a_addr);
|
||||
bp->b_bcount = ap->a_length;
|
||||
BUF_KERNPROC(bp);
|
||||
DEV_STRATEGY(bp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement degenerate case where the block requested is the block
|
||||
* returned, and assume that the entire device is contiguous in regards
|
||||
* to the contiguous block range (runp and runb).
|
||||
*/
|
||||
static int
|
||||
spec_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
int *a_runb;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int runp = 0;
|
||||
int runb = 0;
|
||||
|
||||
if (ap->a_vpp != NULL)
|
||||
*ap->a_vpp = vp;
|
||||
if (ap->a_bnp != NULL)
|
||||
*ap->a_bnp = ap->a_bn;
|
||||
if (vp->v_mount != NULL)
|
||||
runp = runb = MAXBSIZE / vp->v_mount->mnt_stat.f_iosize;
|
||||
if (ap->a_runp != NULL)
|
||||
*ap->a_runp = runp;
|
||||
if (ap->a_runb != NULL)
|
||||
*ap->a_runb = runb;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device close routine
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct proc *p = ap->a_p;
|
||||
dev_t dev = vp->v_rdev;
|
||||
|
||||
/*
|
||||
* Hack: a tty device that is a controlling terminal
|
||||
* has a reference from the session structure.
|
||||
* We cannot easily tell that a character device is
|
||||
* a controlling terminal, unless it is the closing
|
||||
* process' controlling terminal. In that case,
|
||||
* if the reference count is 2 (this last descriptor
|
||||
* plus the session), release the reference from the session.
|
||||
*/
|
||||
if (vcount(vp) == 2 && p && (vp->v_flag & VXLOCK) == 0 &&
|
||||
vp == p->p_session->s_ttyvp) {
|
||||
vrele(vp);
|
||||
p->p_session->s_ttyvp = NULL;
|
||||
}
|
||||
/*
|
||||
* We do not want to really close the device if it
|
||||
* is still in use unless we are trying to close it
|
||||
* forcibly. Since every use (buffer, vnode, swap, cmap)
|
||||
* holds a reference to the vnode, and because we mark
|
||||
* any other vnodes that alias this device, when the
|
||||
* sum of the reference counts on all the aliased
|
||||
* vnodes descends to one, we are on last close.
|
||||
*/
|
||||
if (vp->v_flag & VXLOCK) {
|
||||
/* Forced close */
|
||||
} else if (devsw(dev)->d_flags & D_TRACKCLOSE) {
|
||||
/* Keep device updated on status */
|
||||
} else if (vcount(vp) > 1) {
|
||||
return (0);
|
||||
}
|
||||
return (devsw(dev)->d_close(dev, ap->a_fflag, S_IFCHR, p));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a special device vnode.
|
||||
*/
|
||||
static int
|
||||
spec_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, dev %s\n", devtoname(ap->a_vp->v_rdev));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special device advisory byte-level locks.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
spec_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
caddr_t a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
spec_getpages_iodone(bp)
|
||||
struct buf *bp;
|
||||
{
|
||||
|
||||
bp->b_flags |= B_DONE;
|
||||
wakeup(bp);
|
||||
}
|
||||
|
||||
static int
|
||||
spec_getpages(ap)
|
||||
struct vop_getpages_args *ap;
|
||||
{
|
||||
vm_offset_t kva;
|
||||
int error;
|
||||
int i, pcount, size, s;
|
||||
daddr_t blkno;
|
||||
struct buf *bp;
|
||||
vm_page_t m;
|
||||
vm_ooffset_t offset;
|
||||
int toff, nextoff, nread;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int blksiz;
|
||||
int gotreqpage;
|
||||
|
||||
error = 0;
|
||||
pcount = round_page(ap->a_count) / PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* Calculate the offset of the transfer and do sanity check.
|
||||
* FreeBSD currently only supports an 8 TB range due to b_blkno
|
||||
* being in DEV_BSIZE ( usually 512 ) byte chunks on call to
|
||||
* VOP_STRATEGY. XXX
|
||||
*/
|
||||
offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset;
|
||||
|
||||
#define DADDR_T_BIT (sizeof(daddr_t)*8)
|
||||
#define OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1)
|
||||
|
||||
if (offset < 0 || offset > OFFSET_MAX) {
|
||||
/* XXX still no %q in kernel. */
|
||||
printf("spec_getpages: preposterous offset 0x%x%08x\n",
|
||||
(u_int)((u_quad_t)offset >> 32),
|
||||
(u_int)(offset & 0xffffffff));
|
||||
return (VM_PAGER_ERROR);
|
||||
}
|
||||
|
||||
blkno = btodb(offset);
|
||||
|
||||
/*
|
||||
* Round up physical size for real devices. We cannot round using
|
||||
* v_mount's block size data because v_mount has nothing to do with
|
||||
* the device. i.e. it's usually '/dev'. We need the physical block
|
||||
* size for the device itself.
|
||||
*
|
||||
* We can't use v_rdev->si_mountpoint because it only exists when the
|
||||
* block device is mounted. However, we can use v_rdev.
|
||||
*/
|
||||
|
||||
if (vn_isdisk(vp, NULL))
|
||||
blksiz = vp->v_rdev->si_bsize_phys;
|
||||
else
|
||||
blksiz = DEV_BSIZE;
|
||||
|
||||
size = (ap->a_count + blksiz - 1) & ~(blksiz - 1);
|
||||
|
||||
bp = getpbuf(NULL);
|
||||
kva = (vm_offset_t)bp->b_data;
|
||||
|
||||
/*
|
||||
* Map the pages to be read into the kva.
|
||||
*/
|
||||
pmap_qenter(kva, ap->a_m, pcount);
|
||||
|
||||
/* Build a minimal buffer header. */
|
||||
bp->b_iocmd = BIO_READ;
|
||||
bp->b_iodone = spec_getpages_iodone;
|
||||
|
||||
/* B_PHYS is not set, but it is nice to fill this in. */
|
||||
bp->b_rcred = bp->b_wcred = curproc->p_ucred;
|
||||
if (bp->b_rcred != NOCRED)
|
||||
crhold(bp->b_rcred);
|
||||
if (bp->b_wcred != NOCRED)
|
||||
crhold(bp->b_wcred);
|
||||
bp->b_blkno = blkno;
|
||||
bp->b_lblkno = blkno;
|
||||
pbgetvp(ap->a_vp, bp);
|
||||
bp->b_bcount = size;
|
||||
bp->b_bufsize = size;
|
||||
bp->b_resid = 0;
|
||||
bp->b_runningbufspace = bp->b_bufsize;
|
||||
runningbufspace += bp->b_runningbufspace;
|
||||
|
||||
cnt.v_vnodein++;
|
||||
cnt.v_vnodepgsin += pcount;
|
||||
|
||||
mtx_unlock(&vm_mtx);
|
||||
mtx_lock(&Giant);
|
||||
/* Do the input. */
|
||||
BUF_STRATEGY(bp);
|
||||
|
||||
s = splbio();
|
||||
|
||||
/* We definitely need to be at splbio here. */
|
||||
while ((bp->b_flags & B_DONE) == 0)
|
||||
tsleep(bp, PVM, "spread", 0);
|
||||
|
||||
splx(s);
|
||||
mtx_unlock(&Giant);
|
||||
mtx_lock(&vm_mtx);
|
||||
|
||||
if ((bp->b_ioflags & BIO_ERROR) != 0) {
|
||||
if (bp->b_error)
|
||||
error = bp->b_error;
|
||||
else
|
||||
error = EIO;
|
||||
}
|
||||
|
||||
nread = size - bp->b_resid;
|
||||
|
||||
if (nread < ap->a_count) {
|
||||
bzero((caddr_t)kva + nread,
|
||||
ap->a_count - nread);
|
||||
}
|
||||
pmap_qremove(kva, pcount);
|
||||
|
||||
|
||||
gotreqpage = 0;
|
||||
for (i = 0, toff = 0; i < pcount; i++, toff = nextoff) {
|
||||
nextoff = toff + PAGE_SIZE;
|
||||
m = ap->a_m[i];
|
||||
|
||||
m->flags &= ~PG_ZERO;
|
||||
|
||||
if (nextoff <= nread) {
|
||||
m->valid = VM_PAGE_BITS_ALL;
|
||||
vm_page_undirty(m);
|
||||
} else if (toff < nread) {
|
||||
/*
|
||||
* Since this is a VM request, we have to supply the
|
||||
* unaligned offset to allow vm_page_set_validclean()
|
||||
* to zero sub-DEV_BSIZE'd portions of the page.
|
||||
*/
|
||||
vm_page_set_validclean(m, 0, nread - toff);
|
||||
} else {
|
||||
m->valid = 0;
|
||||
vm_page_undirty(m);
|
||||
}
|
||||
|
||||
if (i != ap->a_reqpage) {
|
||||
/*
|
||||
* Just in case someone was asking for this page we
|
||||
* now tell them that it is ok to use.
|
||||
*/
|
||||
if (!error || (m->valid == VM_PAGE_BITS_ALL)) {
|
||||
if (m->valid) {
|
||||
if (m->flags & PG_WANTED) {
|
||||
vm_page_activate(m);
|
||||
} else {
|
||||
vm_page_deactivate(m);
|
||||
}
|
||||
vm_page_wakeup(m);
|
||||
} else {
|
||||
vm_page_free(m);
|
||||
}
|
||||
} else {
|
||||
vm_page_free(m);
|
||||
}
|
||||
} else if (m->valid) {
|
||||
gotreqpage = 1;
|
||||
/*
|
||||
* Since this is a VM request, we need to make the
|
||||
* entire page presentable by zeroing invalid sections.
|
||||
*/
|
||||
if (m->valid != VM_PAGE_BITS_ALL)
|
||||
vm_page_zero_invalid(m, FALSE);
|
||||
}
|
||||
}
|
||||
if (!gotreqpage) {
|
||||
m = ap->a_m[ap->a_reqpage];
|
||||
printf(
|
||||
"spec_getpages:(%s) I/O read failure: (error=%d) bp %p vp %p\n",
|
||||
devtoname(bp->b_dev), error, bp, bp->b_vp);
|
||||
printf(
|
||||
" size: %d, resid: %ld, a_count: %d, valid: 0x%x\n",
|
||||
size, bp->b_resid, ap->a_count, m->valid);
|
||||
printf(
|
||||
" nread: %d, reqpage: %d, pindex: %lu, pcount: %d\n",
|
||||
nread, ap->a_reqpage, (u_long)m->pindex, pcount);
|
||||
/*
|
||||
* Free the buffer header back to the swap buffer pool.
|
||||
*/
|
||||
relpbuf(bp, NULL);
|
||||
return VM_PAGER_ERROR;
|
||||
}
|
||||
/*
|
||||
* Free the buffer header back to the swap buffer pool.
|
||||
*/
|
||||
relpbuf(bp, NULL);
|
||||
return VM_PAGER_OK;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)umap.h 8.4 (Berkeley) 8/20/94
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define MAPFILEENTRIES 64
|
||||
#define GMAPFILEENTRIES 16
|
||||
#define NOBODY 32767
|
||||
#define NULLGROUP 65534
|
||||
|
||||
struct umap_args {
|
||||
char *target; /* Target of loopback */
|
||||
int nentries; /* # of entries in user map array */
|
||||
int gnentries; /* # of entries in group map array */
|
||||
u_long (*mapdata)[2]; /* pointer to array of user mappings */
|
||||
u_long (*gmapdata)[2]; /* pointer to array of group mappings */
|
||||
};
|
||||
|
||||
struct umap_mount {
|
||||
struct mount *umapm_vfs;
|
||||
struct vnode *umapm_rootvp; /* Reference to root umap_node */
|
||||
int info_nentries; /* number of uid mappings */
|
||||
int info_gnentries; /* number of gid mappings */
|
||||
u_long info_mapdata[MAPFILEENTRIES][2]; /* mapping data for
|
||||
user mapping in ficus */
|
||||
u_long info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for
|
||||
group mapping in ficus */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* A cache of vnode references
|
||||
*/
|
||||
struct umap_node {
|
||||
LIST_ENTRY(umap_node) umap_hash; /* Hash list */
|
||||
struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */
|
||||
struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */
|
||||
};
|
||||
|
||||
extern int umapfs_init __P((struct vfsconf *vfsp));
|
||||
extern int umap_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp));
|
||||
extern u_long umap_reverse_findid __P((u_long id, u_long map[][2], int nentries));
|
||||
extern void umap_mapids __P((struct mount *v_mount, struct ucred *credp));
|
||||
|
||||
#define MOUNTTOUMAPMOUNT(mp) ((struct umap_mount *)((mp)->mnt_data))
|
||||
#define VTOUMAP(vp) ((struct umap_node *)(vp)->v_data)
|
||||
#define UMAPTOV(xp) ((xp)->umap_vnode)
|
||||
#ifdef DIAGNOSTIC
|
||||
extern struct vnode *umap_checkvp __P((struct vnode *vp, char *fil, int lno));
|
||||
#define UMAPVPTOLOWERVP(vp) umap_checkvp((vp), __FILE__, __LINE__)
|
||||
#else
|
||||
#define UMAPVPTOLOWERVP(vp) (VTOUMAP(vp)->umap_lowervp)
|
||||
#endif
|
||||
|
||||
extern vop_t **umap_vnodeop_p;
|
||||
#endif /* _KERNEL */
|
@ -1,405 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)umap_subr.c 8.9 (Berkeley) 5/14/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NUMAPNODECACHE 16
|
||||
|
||||
/*
|
||||
* Null layer cache:
|
||||
* Each cache entry holds a reference to the target vnode
|
||||
* along with a pointer to the alias vnode. When an
|
||||
* entry is added the target vnode is VREF'd. When the
|
||||
* alias is removed the target vnode is vrele'd.
|
||||
*/
|
||||
|
||||
#define UMAP_NHASH(vp) \
|
||||
(&umap_node_hashtbl \
|
||||
[((uintptr_t)(void *)(vp) >> LOG2_SIZEVNODE) & umap_node_hash])
|
||||
static LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
|
||||
static u_long umap_node_hash;
|
||||
|
||||
static u_long umap_findid __P((u_long id, u_long map[][2], int nentries));
|
||||
static int umap_node_alloc __P((struct mount *mp, struct vnode *lowervp,
|
||||
struct vnode **vpp));
|
||||
static struct vnode *
|
||||
umap_node_find __P((struct mount *mp, struct vnode *targetvp));
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
int
|
||||
umapfs_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_init\n"); /* printed during system boot */
|
||||
#endif
|
||||
umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* umap_findid is called by various routines in umap_vnodeops.c to
|
||||
* find a user or group id in a map.
|
||||
*/
|
||||
static u_long
|
||||
umap_findid(id, map, nentries)
|
||||
u_long id;
|
||||
u_long map[][2];
|
||||
int nentries;
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Find uid entry in map */
|
||||
i = 0;
|
||||
while ((i<nentries) && ((map[i][0]) != id))
|
||||
i++;
|
||||
|
||||
if (i < nentries)
|
||||
return (map[i][1]);
|
||||
else
|
||||
return (-1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
|
||||
* find a user or group id in a map, in reverse.
|
||||
*/
|
||||
u_long
|
||||
umap_reverse_findid(id, map, nentries)
|
||||
u_long id;
|
||||
u_long map[][2];
|
||||
int nentries;
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Find uid entry in map */
|
||||
i = 0;
|
||||
while ((i<nentries) && ((map[i][1]) != id))
|
||||
i++;
|
||||
|
||||
if (i < nentries)
|
||||
return (map[i][0]);
|
||||
else
|
||||
return (-1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return alias for target vnode if already exists, else 0.
|
||||
*/
|
||||
static struct vnode *
|
||||
umap_node_find(mp, targetvp)
|
||||
struct mount *mp;
|
||||
struct vnode *targetvp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct umap_node_hashhead *hd;
|
||||
struct umap_node *a;
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umap_node_find(mp = %p, target = %p)\n",
|
||||
(void *)mp, (void *)targetvp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find hash base, and then search the (two-way) linked
|
||||
* list looking for a umap_node structure which is referencing
|
||||
* the target vnode. If found, the increment the umap_node
|
||||
* reference count (but NOT the target vnode's VREF counter).
|
||||
*/
|
||||
hd = UMAP_NHASH(targetvp);
|
||||
loop:
|
||||
LIST_FOREACH(a, hd, umap_hash) {
|
||||
if (a->umap_lowervp == targetvp &&
|
||||
a->umap_vnode->v_mount == mp) {
|
||||
vp = UMAPTOV(a);
|
||||
/*
|
||||
* We need vget for the VXLOCK
|
||||
* stuff, but we don't want to lock
|
||||
* the lower node.
|
||||
*/
|
||||
if (vget(vp, 0, p)) {
|
||||
#ifdef DEBUG
|
||||
printf ("umap_node_find: vget failed.\n");
|
||||
#endif
|
||||
goto loop;
|
||||
}
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umap_node_find(%p, %p): NOT found\n",
|
||||
(void *)mp, (void *)targetvp);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a new umap_node node.
|
||||
* Vp is the alias vnode, lofsvp is the target vnode.
|
||||
* Maintain a reference to (targetvp).
|
||||
*/
|
||||
static int
|
||||
umap_node_alloc(mp, lowervp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct umap_node_hashhead *hd;
|
||||
struct umap_node *xp;
|
||||
struct vnode *othervp, *vp;
|
||||
int error;
|
||||
|
||||
/* XXX This routine probably needs a node_alloc lock */
|
||||
|
||||
/*
|
||||
* Do the MALLOC before the getnewvnode since doing so afterward
|
||||
* might cause a bogus v_data pointer to get dereferenced
|
||||
* elsewhere if MALLOC should block.
|
||||
*/
|
||||
MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
|
||||
M_TEMP, M_WAITOK);
|
||||
|
||||
error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp);
|
||||
if (error) {
|
||||
FREE(xp, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
vp = *vpp;
|
||||
|
||||
vp->v_type = lowervp->v_type;
|
||||
xp->umap_vnode = vp;
|
||||
vp->v_data = xp;
|
||||
xp->umap_lowervp = lowervp;
|
||||
/*
|
||||
* Before we insert our new node onto the hash chains,
|
||||
* check to see if someone else has beaten us to it.
|
||||
* (We could have slept in MALLOC.)
|
||||
*/
|
||||
othervp = umap_node_find(mp, lowervp);
|
||||
if (othervp) {
|
||||
FREE(xp, M_TEMP);
|
||||
vp->v_type = VBAD; /* node is discarded */
|
||||
vp->v_usecount = 0; /* XXX */
|
||||
*vpp = othervp;
|
||||
return (0);
|
||||
}
|
||||
VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */
|
||||
hd = UMAP_NHASH(lowervp);
|
||||
LIST_INSERT_HEAD(hd, xp, umap_hash);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to find an existing umap_node vnode refering
|
||||
* to it, otherwise make a new umap_node vnode which
|
||||
* contains a reference to the target vnode.
|
||||
*/
|
||||
int
|
||||
umap_node_create(mp, targetvp, newvpp)
|
||||
struct mount *mp;
|
||||
struct vnode *targetvp;
|
||||
struct vnode **newvpp;
|
||||
{
|
||||
struct vnode *aliasvp;
|
||||
|
||||
aliasvp = umap_node_find(mp, targetvp);
|
||||
if (aliasvp) {
|
||||
/*
|
||||
* Take another reference to the alias vnode
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
vprint("umap_node_create: exists", aliasvp);
|
||||
#endif
|
||||
/* VREF(aliasvp); */
|
||||
} else {
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Get new vnode.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf("umap_node_create: create new alias vnode\n");
|
||||
#endif
|
||||
/*
|
||||
* Make new vnode reference the umap_node.
|
||||
*/
|
||||
error = umap_node_alloc(mp, targetvp, &aliasvp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* aliasvp is already VREF'd by getnewvnode()
|
||||
*/
|
||||
}
|
||||
|
||||
vrele(targetvp);
|
||||
|
||||
#ifdef DEBUG
|
||||
vprint("umap_node_create: alias", aliasvp);
|
||||
vprint("umap_node_create: target", targetvp);
|
||||
#endif
|
||||
|
||||
*newvpp = aliasvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
int umap_checkvp_barrier = 1;
|
||||
struct vnode *
|
||||
umap_checkvp(vp, fil, lno)
|
||||
struct vnode *vp;
|
||||
char *fil;
|
||||
int lno;
|
||||
{
|
||||
struct umap_node *a = VTOUMAP(vp);
|
||||
#if 0
|
||||
/*
|
||||
* Can't do this check because vop_reclaim runs
|
||||
* with funny vop vector.
|
||||
*/
|
||||
if (vp->v_op != umap_vnodeop_p) {
|
||||
printf ("umap_checkvp: on non-umap-node\n");
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("umap_checkvp");
|
||||
}
|
||||
#endif
|
||||
if (a->umap_lowervp == NULL) {
|
||||
/* Should never happen */
|
||||
int i; u_long *p;
|
||||
printf("vp = %p, ZERO ptr\n", (void *)vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %p", (void *)p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("umap_checkvp");
|
||||
}
|
||||
if (a->umap_lowervp->v_usecount < 1) {
|
||||
int i; u_long *p;
|
||||
printf("vp = %p, unref'ed lowervp\n", (void *)vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %p", (void *)p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic ("umap with unref'ed lowervp");
|
||||
}
|
||||
#if 0
|
||||
printf("umap %x/%d -> %x/%d [%s, %d]\n",
|
||||
a->umap_vnode, a->umap_vnode->v_usecount,
|
||||
a->umap_lowervp, a->umap_lowervp->v_usecount,
|
||||
fil, lno);
|
||||
#endif
|
||||
return (a->umap_lowervp);
|
||||
}
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
/* umap_mapids maps all of the ids in a credential, both user and group. */
|
||||
|
||||
void
|
||||
umap_mapids(v_mount, credp)
|
||||
struct mount *v_mount;
|
||||
struct ucred *credp;
|
||||
{
|
||||
int i;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (credp == NOCRED)
|
||||
return;
|
||||
|
||||
/* Find uid entry in map */
|
||||
|
||||
uid = (uid_t) umap_findid(credp->cr_uid,
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_mapdata,
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_nentries);
|
||||
|
||||
if (uid != -1)
|
||||
credp->cr_uid = uid;
|
||||
else
|
||||
credp->cr_uid = (uid_t) NOBODY;
|
||||
|
||||
#ifdef notdef
|
||||
/* cr_gid is the same as cr_groups[0] in 4BSD */
|
||||
|
||||
/* Find gid entry in map */
|
||||
|
||||
gid = (gid_t) umap_findid(credp->cr_gid,
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata,
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_gnentries);
|
||||
|
||||
if (gid != -1)
|
||||
credp->cr_gid = gid;
|
||||
else
|
||||
credp->cr_gid = NULLGROUP;
|
||||
#endif
|
||||
|
||||
/* Now we must map each of the set of groups in the cr_groups
|
||||
structure. */
|
||||
|
||||
i = 0;
|
||||
while (credp->cr_groups[i] != 0) {
|
||||
gid = (gid_t) umap_findid(credp->cr_groups[i],
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata,
|
||||
MOUNTTOUMAPMOUNT(v_mount)->info_gnentries);
|
||||
|
||||
if (gid != -1)
|
||||
credp->cr_groups[i++] = gid;
|
||||
else
|
||||
credp->cr_groups[i++] = NULLGROUP;
|
||||
}
|
||||
}
|
@ -1,454 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Umap Layer
|
||||
* (See mount_umap(8) for a description of this layer.)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
static MALLOC_DEFINE(M_UMAPFSMNT, "UMAP mount", "UMAP mount structure");
|
||||
|
||||
static int umapfs_fhtovp __P((struct mount *mp, struct fid *fidp,
|
||||
struct vnode **vpp));
|
||||
static int umapfs_checkexp __P((struct mount *mp, struct sockaddr *nam,
|
||||
int *extflagsp, struct ucred **credanonp));
|
||||
static int umapfs_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
static int umapfs_quotactl __P((struct mount *mp, int cmd, uid_t uid,
|
||||
caddr_t arg, struct proc *p));
|
||||
static int umapfs_root __P((struct mount *mp, struct vnode **vpp));
|
||||
static int umapfs_start __P((struct mount *mp, int flags, struct proc *p));
|
||||
static int umapfs_statfs __P((struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p));
|
||||
static int umapfs_sync __P((struct mount *mp, int waitfor,
|
||||
struct ucred *cred, struct proc *p));
|
||||
static int umapfs_unmount __P((struct mount *mp, int mntflags,
|
||||
struct proc *p));
|
||||
static int umapfs_vget __P((struct mount *mp, ino_t ino,
|
||||
struct vnode **vpp));
|
||||
static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp));
|
||||
static int umapfs_extattrctl __P((struct mount *mp, int cmd,
|
||||
struct vnode *filename_vp,
|
||||
int namespace, const char *attrname,
|
||||
struct proc *p));
|
||||
|
||||
/*
|
||||
* Mount umap layer
|
||||
*/
|
||||
static int
|
||||
umapfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct umap_args args;
|
||||
struct vnode *lowerrootvp, *vp;
|
||||
struct vnode *umapm_rootvp;
|
||||
struct umap_mount *amp;
|
||||
u_int size;
|
||||
int error;
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Only for root
|
||||
*/
|
||||
if ((error = suser(p)) != 0)
|
||||
return (error);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_mount(mp = %p)\n", (void *)mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
return (EOPNOTSUPP);
|
||||
/* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
error = copyin(data, (caddr_t)&args, sizeof(struct umap_args));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Find lower node
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
error = namei(ndp);
|
||||
if (error)
|
||||
return (error);
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
|
||||
/*
|
||||
* Sanity check on lower vnode
|
||||
*/
|
||||
lowerrootvp = ndp->ni_vp;
|
||||
#ifdef DEBUG
|
||||
printf("vp = %p, check for VDIR...\n", (void *)lowerrootvp);
|
||||
#endif
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = 0;
|
||||
|
||||
if (lowerrootvp->v_type != VDIR) {
|
||||
vput(lowerrootvp);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("mp = %p\n", (void *)mp);
|
||||
#endif
|
||||
|
||||
amp = (struct umap_mount *) malloc(sizeof(struct umap_mount),
|
||||
M_UMAPFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
/*
|
||||
* Save reference to underlying FS
|
||||
*/
|
||||
amp->umapm_vfs = lowerrootvp->v_mount;
|
||||
|
||||
/*
|
||||
* Now copy in the number of entries and maps for umap mapping.
|
||||
*/
|
||||
amp->info_nentries = args.nentries;
|
||||
amp->info_gnentries = args.gnentries;
|
||||
error = copyin(args.mapdata, (caddr_t)amp->info_mapdata,
|
||||
2*sizeof(u_long)*args.nentries);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umap_mount:nentries %d\n",args.nentries);
|
||||
for (i = 0; i < args.nentries; i++)
|
||||
printf(" %lu maps to %lu\n", amp->info_mapdata[i][0],
|
||||
amp->info_mapdata[i][1]);
|
||||
#endif
|
||||
|
||||
error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata,
|
||||
2*sizeof(u_long)*args.gnentries);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umap_mount:gnentries %d\n",args.gnentries);
|
||||
for (i = 0; i < args.gnentries; i++)
|
||||
printf(" group %lu maps to %lu\n",
|
||||
amp->info_gmapdata[i][0],
|
||||
amp->info_gmapdata[i][1]);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Save reference. Each mount also holds
|
||||
* a reference on the root vnode.
|
||||
*/
|
||||
error = umap_node_create(mp, lowerrootvp, &vp);
|
||||
/*
|
||||
* Unlock the node (either the lower or the alias)
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
/*
|
||||
* Make sure the node alias worked
|
||||
*/
|
||||
if (error) {
|
||||
vrele(lowerrootvp);
|
||||
free(amp, M_UMAPFSMNT); /* XXX */
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep a held reference to the root vnode.
|
||||
* It is vrele'd in umapfs_unmount.
|
||||
*/
|
||||
umapm_rootvp = vp;
|
||||
umapm_rootvp->v_flag |= VROOT;
|
||||
amp->umapm_rootvp = umapm_rootvp;
|
||||
if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) amp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
|
||||
&size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
(void)umapfs_statfs(mp, &mp->mnt_stat, p);
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_mount: lower %s, alias at %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS start. Nothing needed here - the start routine
|
||||
* on the underlying filesystem will have been called
|
||||
* when that filesystem was mounted.
|
||||
*/
|
||||
static int
|
||||
umapfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
/* return (VFS_START(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, flags, p)); */
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to umap layer
|
||||
*/
|
||||
static int
|
||||
umapfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_unmount(mp = %p)\n", (void *)mp);
|
||||
#endif
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
#ifdef notyet
|
||||
mntflushbuf(mp, 0);
|
||||
if (mntinvalbuf(mp, 1))
|
||||
return (EBUSY);
|
||||
#endif
|
||||
/* There is 1 extra root vnode reference (umapm_rootvp). */
|
||||
error = vflush(mp, 1, flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Finally, throw away the umap_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UMAPFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_root(mp = %p, vp = %p->%p)\n",
|
||||
(void *)mp, (void *)MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
|
||||
(void *)UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_quotactl(mp, cmd, uid, arg, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
caddr_t arg;
|
||||
struct proc *p;
|
||||
{
|
||||
return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p));
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct statfs mstat;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("umapfs_statfs(mp = %p, vp = %p->%p)\n",
|
||||
(void *)mp, (void *)MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
|
||||
(void *)UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp));
|
||||
#endif
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_sync(mp, waitfor, cred, p)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
{
|
||||
/*
|
||||
* XXX - Assumes no data cached at umap layer.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_vget(mp, ino, vpp)
|
||||
struct mount *mp;
|
||||
ino_t ino;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp));
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_fhtovp(mp, fidp, vpp)
|
||||
struct mount *mp;
|
||||
struct fid *fidp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return (VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, vpp));
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_checkexp(mp, nam, exflagsp, credanonp)
|
||||
struct mount *mp;
|
||||
struct sockaddr *nam;
|
||||
int *exflagsp;
|
||||
struct ucred **credanonp;
|
||||
{
|
||||
|
||||
return (VFS_CHECKEXP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, nam,
|
||||
exflagsp, credanonp));
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_vptofh(vp, fhp)
|
||||
struct vnode *vp;
|
||||
struct fid *fhp;
|
||||
{
|
||||
return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp));
|
||||
}
|
||||
|
||||
static int
|
||||
umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
struct vnode *filename_vp;
|
||||
int namespace;
|
||||
const char *attrname;
|
||||
struct proc *p;
|
||||
{
|
||||
return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd,
|
||||
filename_vp, namespace, attrname, p));
|
||||
}
|
||||
|
||||
|
||||
static struct vfsops umap_vfsops = {
|
||||
umapfs_mount,
|
||||
umapfs_start,
|
||||
umapfs_unmount,
|
||||
umapfs_root,
|
||||
umapfs_quotactl,
|
||||
umapfs_statfs,
|
||||
umapfs_sync,
|
||||
umapfs_vget,
|
||||
umapfs_fhtovp,
|
||||
umapfs_checkexp,
|
||||
umapfs_vptofh,
|
||||
umapfs_init,
|
||||
vfs_stduninit,
|
||||
umapfs_extattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(umap_vfsops, umap, VFCF_LOOPBACK);
|
@ -1,519 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Umap Layer
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
static int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
|
||||
SYSCTL_INT(_debug, OID_AUTO, umapfs_bug_bypass, CTLFLAG_RW,
|
||||
&umap_bug_bypass, 0, "");
|
||||
|
||||
static int umap_bypass __P((struct vop_generic_args *ap));
|
||||
static int umap_getattr __P((struct vop_getattr_args *ap));
|
||||
static int umap_inactive __P((struct vop_inactive_args *ap));
|
||||
static int umap_lock __P((struct vop_lock_args *ap));
|
||||
static int umap_print __P((struct vop_print_args *ap));
|
||||
static int umap_reclaim __P((struct vop_reclaim_args *ap));
|
||||
static int umap_rename __P((struct vop_rename_args *ap));
|
||||
static int umap_unlock __P((struct vop_unlock_args *ap));
|
||||
|
||||
/*
|
||||
* This is the 10-Apr-92 bypass routine.
|
||||
* See null_vnops.c:null_bypass for more details.
|
||||
*/
|
||||
static int
|
||||
umap_bypass(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
struct ucred **credpp = 0, *credp = 0;
|
||||
struct ucred *savecredp = 0, *savecompcredp = 0;
|
||||
struct ucred *compcredp = 0;
|
||||
struct vnode **this_vp_p;
|
||||
int error;
|
||||
struct vnode *old_vps[VDESC_MAX_VPS];
|
||||
struct vnode *vp1 = 0;
|
||||
struct vnode **vps_p[VDESC_MAX_VPS];
|
||||
struct vnode ***vppp;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
int reles, i;
|
||||
struct componentname **compnamepp = 0;
|
||||
|
||||
if (umap_bug_bypass)
|
||||
printf ("umap_bypass: %s\n", descp->vdesc_name);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* We require at least one vp.
|
||||
*/
|
||||
if (descp->vdesc_vp_offsets == NULL ||
|
||||
descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
|
||||
panic ("umap_bypass: no vp's in map");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Map the vnodes going in.
|
||||
* Later, we'll invoke the operation based on
|
||||
* the first mapped vnode's operation vector.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
vps_p[i] = this_vp_p =
|
||||
VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap);
|
||||
|
||||
if (i == 0) {
|
||||
vp1 = *vps_p[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* We're not guaranteed that any but the first vnode
|
||||
* are of our type. Check for and don't map any
|
||||
* that aren't. (Must map first vp or vclean fails.)
|
||||
*/
|
||||
|
||||
if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
|
||||
old_vps[i] = NULL;
|
||||
} else {
|
||||
old_vps[i] = *this_vp_p;
|
||||
*(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
|
||||
if (reles & 1)
|
||||
VREF(*this_vp_p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix the credentials. (That's the purpose of this layer.)
|
||||
*/
|
||||
|
||||
if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
|
||||
|
||||
credpp = VOPARG_OFFSETTO(struct ucred**,
|
||||
descp->vdesc_cred_offset, ap);
|
||||
|
||||
/* Save old values */
|
||||
|
||||
savecredp = (*credpp);
|
||||
if (savecredp != NOCRED)
|
||||
(*credpp) = crdup(savecredp);
|
||||
credp = *credpp;
|
||||
|
||||
if (umap_bug_bypass && credp->cr_uid != 0)
|
||||
printf("umap_bypass: user was %lu, group %lu\n",
|
||||
(u_long)credp->cr_uid, (u_long)credp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp1->v_mount, credp);
|
||||
|
||||
if (umap_bug_bypass && credp->cr_uid != 0)
|
||||
printf("umap_bypass: user now %lu, group %lu\n",
|
||||
(u_long)credp->cr_uid, (u_long)credp->cr_gid);
|
||||
}
|
||||
|
||||
/* BSD often keeps a credential in the componentname structure
|
||||
* for speed. If there is one, it better get mapped, too.
|
||||
*/
|
||||
|
||||
if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
|
||||
|
||||
compnamepp = VOPARG_OFFSETTO(struct componentname**,
|
||||
descp->vdesc_componentname_offset, ap);
|
||||
|
||||
compcredp = (*compnamepp)->cn_cred;
|
||||
savecompcredp = compcredp;
|
||||
if (savecompcredp != NOCRED)
|
||||
(*compnamepp)->cn_cred = crdup(savecompcredp);
|
||||
compcredp = (*compnamepp)->cn_cred;
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf(
|
||||
"umap_bypass: component credit user was %lu, group %lu\n",
|
||||
(u_long)compcredp->cr_uid,
|
||||
(u_long)compcredp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp1->v_mount, compcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf(
|
||||
"umap_bypass: component credit user now %lu, group %lu\n",
|
||||
(u_long)compcredp->cr_uid,
|
||||
(u_long)compcredp->cr_gid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the operation on the lower layer
|
||||
* with the modified argument structure.
|
||||
*/
|
||||
error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
|
||||
|
||||
/*
|
||||
* Maintain the illusion of call-by-value
|
||||
* by restoring vnodes in the argument structure
|
||||
* to their original value.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
if (old_vps[i]) {
|
||||
*(vps_p[i]) = old_vps[i];
|
||||
if (reles & 1)
|
||||
vrele(*(vps_p[i]));
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Map the possible out-going vpp
|
||||
* (Assumes that the lower layer always returns
|
||||
* a VREF'ed vpp unless it gets an error.)
|
||||
*/
|
||||
if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
|
||||
!(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
|
||||
!error) {
|
||||
if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
|
||||
goto out;
|
||||
vppp = VOPARG_OFFSETTO(struct vnode***,
|
||||
descp->vdesc_vpp_offset, ap);
|
||||
if (*vppp)
|
||||
error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
|
||||
};
|
||||
|
||||
out:
|
||||
/*
|
||||
* Free duplicate cred structure and restore old one.
|
||||
*/
|
||||
if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
|
||||
if (umap_bug_bypass && credp && credp->cr_uid != 0)
|
||||
printf("umap_bypass: returning-user was %lu\n",
|
||||
(u_long)credp->cr_uid);
|
||||
|
||||
if (savecredp != NOCRED) {
|
||||
crfree(credp);
|
||||
(*credpp) = savecredp;
|
||||
if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
|
||||
printf(
|
||||
"umap_bypass: returning-user now %lu\n\n",
|
||||
(u_long)(*credpp)->cr_uid);
|
||||
}
|
||||
}
|
||||
|
||||
if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
|
||||
if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0)
|
||||
printf(
|
||||
"umap_bypass: returning-component-user was %lu\n",
|
||||
(u_long)compcredp->cr_uid);
|
||||
|
||||
if (savecompcredp != NOCRED) {
|
||||
crfree(compcredp);
|
||||
(*compnamepp)->cn_cred = savecompcredp;
|
||||
if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
|
||||
printf(
|
||||
"umap_bypass: returning-component-user now %lu\n",
|
||||
(u_long)compcredp->cr_uid);
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We handle getattr to change the fsid.
|
||||
*/
|
||||
static int
|
||||
umap_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
short uid, gid;
|
||||
int error, tmpid, nentries, gnentries;
|
||||
u_long (*mapdata)[2], (*gmapdata)[2];
|
||||
struct vnode **vp1p;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
|
||||
error = umap_bypass((struct vop_generic_args *)ap);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Umap needs to map the uid and gid returned by a stat
|
||||
* into the proper values for this site. This involves
|
||||
* finding the returned uid in the mapping information,
|
||||
* translating it into the uid on the other end,
|
||||
* and filling in the proper field in the vattr
|
||||
* structure pointed to by ap->a_vap. The group
|
||||
* is easier, since currently all groups will be
|
||||
* translate to the NULLGROUP.
|
||||
*/
|
||||
|
||||
/* Find entry in map */
|
||||
|
||||
uid = ap->a_vap->va_uid;
|
||||
gid = ap->a_vap->va_gid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid,
|
||||
gid);
|
||||
|
||||
vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap);
|
||||
nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries;
|
||||
mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata);
|
||||
gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries;
|
||||
gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata);
|
||||
|
||||
/* Reverse map the uid for the vnode. Since it's a reverse
|
||||
map, we can't use umap_mapids() to do it. */
|
||||
|
||||
tmpid = umap_reverse_findid(uid, mapdata, nentries);
|
||||
|
||||
if (tmpid != -1) {
|
||||
|
||||
ap->a_vap->va_uid = (uid_t) tmpid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: original uid = %d\n", uid);
|
||||
} else
|
||||
ap->a_vap->va_uid = (uid_t) NOBODY;
|
||||
|
||||
/* Reverse map the gid for the vnode. */
|
||||
|
||||
tmpid = umap_reverse_findid(gid, gmapdata, gnentries);
|
||||
|
||||
if (tmpid != -1) {
|
||||
|
||||
ap->a_vap->va_gid = (gid_t) tmpid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: original gid = %d\n", gid);
|
||||
} else
|
||||
ap->a_vap->va_gid = (gid_t) NULLGROUP;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode lock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
static int
|
||||
umap_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
vop_nolock(ap);
|
||||
if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
|
||||
return (0);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode unlock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
int
|
||||
umap_unlock(ap)
|
||||
struct vop_unlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
vop_nounlock(ap);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass((struct vop_generic_args *)ap));
|
||||
}
|
||||
|
||||
static int
|
||||
umap_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct umap_node *xp = VTOUMAP(vp);
|
||||
struct vnode *lowervp = xp->umap_lowervp;
|
||||
/*
|
||||
* Do nothing (and _don't_ bypass).
|
||||
* Wait to vrele lowervp until reclaim,
|
||||
* so that until then our umap_node is in the
|
||||
* cache and reusable.
|
||||
*
|
||||
*/
|
||||
VOP_INACTIVE(lowervp, ap->a_p);
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umap_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct umap_node *xp = VTOUMAP(vp);
|
||||
struct vnode *lowervp = xp->umap_lowervp;
|
||||
|
||||
/* After this assignment, this node will not be re-used. */
|
||||
xp->umap_lowervp = NULL;
|
||||
LIST_REMOVE(xp, umap_hash);
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = NULL;
|
||||
vrele(lowervp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umap_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
printf("\ttag VT_UMAPFS, vp=%p, lowervp=%p\n", vp, UMAPVPTOLOWERVP(vp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
umap_rename(ap)
|
||||
struct vop_rename_args /* {
|
||||
struct vnode *a_fdvp;
|
||||
struct vnode *a_fvp;
|
||||
struct componentname *a_fcnp;
|
||||
struct vnode *a_tdvp;
|
||||
struct vnode *a_tvp;
|
||||
struct componentname *a_tcnp;
|
||||
} */ *ap;
|
||||
{
|
||||
int error;
|
||||
struct componentname *compnamep;
|
||||
struct ucred *compcredp, *savecompcredp;
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Rename is irregular, having two componentname structures.
|
||||
* We need to map the cre in the second structure,
|
||||
* and then bypass takes care of the rest.
|
||||
*/
|
||||
|
||||
vp = ap->a_fdvp;
|
||||
compnamep = ap->a_tcnp;
|
||||
compcredp = compnamep->cn_cred;
|
||||
|
||||
savecompcredp = compcredp;
|
||||
compcredp = compnamep->cn_cred = crdup(savecompcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf(
|
||||
"umap_rename: rename component credit user was %lu, group %lu\n",
|
||||
(u_long)compcredp->cr_uid, (u_long)compcredp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp->v_mount, compcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf(
|
||||
"umap_rename: rename component credit user now %lu, group %lu\n",
|
||||
(u_long)compcredp->cr_uid, (u_long)compcredp->cr_gid);
|
||||
|
||||
error = umap_bypass((struct vop_generic_args *)ap);
|
||||
|
||||
/* Restore the additional mapped componentname cred structure. */
|
||||
|
||||
crfree(compcredp);
|
||||
compnamep->cn_cred = savecompcredp;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Global vfs data structures
|
||||
*/
|
||||
/*
|
||||
* XXX - strategy, bwrite are hand coded currently. They should
|
||||
* go away with a merged buffer/block cache.
|
||||
*
|
||||
*/
|
||||
vop_t **umap_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc umap_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *) umap_bypass },
|
||||
{ &vop_getattr_desc, (vop_t *) umap_getattr },
|
||||
{ &vop_inactive_desc, (vop_t *) umap_inactive },
|
||||
{ &vop_lock_desc, (vop_t *) umap_lock },
|
||||
{ &vop_print_desc, (vop_t *) umap_print },
|
||||
{ &vop_reclaim_desc, (vop_t *) umap_reclaim },
|
||||
{ &vop_rename_desc, (vop_t *) umap_rename },
|
||||
{ &vop_unlock_desc, (vop_t *) umap_unlock },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc umap_vnodeop_opv_desc =
|
||||
{ &umap_vnodeop_p, umap_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(umap_vnodeop_opv_desc);
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1994 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Jan-Simon Pendry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)union.h 8.9 (Berkeley) 12/10/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct union_args {
|
||||
char *target; /* Target of loopback */
|
||||
int mntflags; /* Options on the mount */
|
||||
};
|
||||
|
||||
#define UNMNT_ABOVE 0x0001 /* Target appears below mount point */
|
||||
#define UNMNT_BELOW 0x0002 /* Target appears below mount point */
|
||||
#define UNMNT_REPLACE 0x0003 /* Target replaces mount point */
|
||||
#define UNMNT_OPMASK 0x0003
|
||||
|
||||
struct union_mount {
|
||||
struct vnode *um_uppervp; /* UN_ULOCK holds locking state */
|
||||
struct vnode *um_lowervp; /* Left unlocked */
|
||||
struct ucred *um_cred; /* Credentials of user calling mount */
|
||||
int um_cmode; /* cmask from mount process */
|
||||
int um_op; /* Operation mode */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#ifndef DIAGNOSTIC
|
||||
#define DIAGNOSTIC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DEFDIRMODE is the mode bits used to create a shadow directory.
|
||||
*/
|
||||
#define VRWXMODE (VREAD|VWRITE|VEXEC)
|
||||
#define VRWMODE (VREAD|VWRITE)
|
||||
#define UN_DIRMODE ((VRWXMODE)|(VRWXMODE>>3)|(VRWXMODE>>6))
|
||||
#define UN_FILEMODE ((VRWMODE)|(VRWMODE>>3)|(VRWMODE>>6))
|
||||
|
||||
/*
|
||||
* A cache of vnode references (hangs off v_data)
|
||||
*
|
||||
* Placing un_lock as the first elements theoretically allows us to
|
||||
* use the vop_stdlock functions. However, we need to make sure of
|
||||
* certain side effects so we will still punch in our own code.
|
||||
*/
|
||||
struct union_node {
|
||||
struct lock un_lock;
|
||||
LIST_ENTRY(union_node) un_cache; /* Hash chain */
|
||||
struct vnode *un_vnode; /* Back pointer */
|
||||
struct vnode *un_uppervp; /* overlaying object */
|
||||
struct vnode *un_lowervp; /* underlying object */
|
||||
struct vnode *un_dirvp; /* Parent dir of uppervp */
|
||||
struct vnode *un_pvp; /* Parent vnode */
|
||||
char *un_path; /* saved component name */
|
||||
int un_openl; /* # of opens on lowervp */
|
||||
int un_exclcnt; /* exclusive count */
|
||||
unsigned int un_flags;
|
||||
struct vnode **un_dircache; /* cached union stack */
|
||||
off_t un_uppersz; /* size of upper object */
|
||||
off_t un_lowersz; /* size of lower object */
|
||||
#ifdef DIAGNOSTIC
|
||||
pid_t un_pid;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX UN_ULOCK - indicates that the uppervp is locked
|
||||
*
|
||||
* UN_CACHED - node is in the union cache
|
||||
*/
|
||||
|
||||
/*#define UN_ULOCK 0x04*/ /* Upper node is locked */
|
||||
#define UN_CACHED 0x10 /* In union cache */
|
||||
|
||||
/*
|
||||
* Hash table locking flags
|
||||
*/
|
||||
|
||||
#define UNVP_WANT 0x01
|
||||
#define UNVP_LOCKED 0x02
|
||||
|
||||
extern int union_allocvp __P((struct vnode **, struct mount *,
|
||||
struct vnode *,
|
||||
struct vnode *,
|
||||
struct componentname *, struct vnode *,
|
||||
struct vnode *, int));
|
||||
extern int union_freevp __P((struct vnode *));
|
||||
extern struct vnode *union_dircache __P((struct vnode *, struct proc *));
|
||||
extern int union_copyup __P((struct union_node *, int, struct ucred *,
|
||||
struct proc *));
|
||||
extern int union_dowhiteout __P((struct union_node *, struct ucred *,
|
||||
struct proc *));
|
||||
extern int union_mkshadow __P((struct union_mount *, struct vnode *,
|
||||
struct componentname *, struct vnode **));
|
||||
extern int union_mkwhiteout __P((struct union_mount *, struct vnode *,
|
||||
struct componentname *, char *));
|
||||
extern int union_cn_close __P((struct vnode *, int, struct ucred *,
|
||||
struct proc *));
|
||||
extern void union_removed_upper __P((struct union_node *un));
|
||||
extern struct vnode *union_lowervp __P((struct vnode *));
|
||||
extern void union_newsize __P((struct vnode *, off_t, off_t));
|
||||
|
||||
extern int (*union_dircheckp) __P((struct proc *, struct vnode **,
|
||||
struct file *));
|
||||
|
||||
#define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data))
|
||||
#define VTOUNION(vp) ((struct union_node *)(vp)->v_data)
|
||||
#define UNIONTOV(un) ((un)->un_vnode)
|
||||
#define LOWERVP(vp) (VTOUNION(vp)->un_lowervp)
|
||||
#define UPPERVP(vp) (VTOUNION(vp)->un_uppervp)
|
||||
#define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp))
|
||||
|
||||
#define UDEBUG(x) if (uniondebug) printf x
|
||||
#define UDEBUG_ENABLED 1
|
||||
|
||||
extern vop_t **union_vnodeop_p;
|
||||
extern struct vfsops union_vfsops;
|
||||
extern int uniondebug;
|
||||
|
||||
#endif /* _KERNEL */
|
File diff suppressed because it is too large
Load Diff
@ -1,485 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 1995 The Regents of the University of California.
|
||||
* Copyright (c) 1994, 1995 Jan-Simon Pendry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Union Layer
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <miscfs/union/union.h>
|
||||
|
||||
static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure");
|
||||
|
||||
extern int union_init __P((struct vfsconf *));
|
||||
static int union_mount __P((struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p));
|
||||
static int union_root __P((struct mount *mp, struct vnode **vpp));
|
||||
static int union_statfs __P((struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p));
|
||||
static int union_unmount __P((struct mount *mp, int mntflags,
|
||||
struct proc *p));
|
||||
|
||||
/*
|
||||
* Mount union filesystem
|
||||
*/
|
||||
static int
|
||||
union_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct union_args args;
|
||||
struct vnode *lowerrootvp = NULLVP;
|
||||
struct vnode *upperrootvp = NULLVP;
|
||||
struct union_mount *um = 0;
|
||||
struct ucred *cred = 0;
|
||||
char *cp = 0;
|
||||
int len;
|
||||
u_int size;
|
||||
|
||||
UDEBUG(("union_mount(mp = %p)\n", (void *)mp));
|
||||
|
||||
/*
|
||||
* Disable clustered write, otherwise system becomes unstable.
|
||||
*/
|
||||
mp->mnt_flag |= MNT_NOCLUSTERW;
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
/*
|
||||
* Need to provide.
|
||||
* 1. a way to convert between rdonly and rdwr mounts.
|
||||
* 2. support for nfs exports.
|
||||
*/
|
||||
error = EOPNOTSUPP;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
error = copyin(data, (caddr_t)&args, sizeof(struct union_args));
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Obtain lower vnode. Vnode is stored in mp->mnt_vnodecovered.
|
||||
* We need to reference it but not lock it.
|
||||
*/
|
||||
|
||||
lowerrootvp = mp->mnt_vnodecovered;
|
||||
VREF(lowerrootvp);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Unlock lower node to avoid deadlock.
|
||||
*/
|
||||
if (lowerrootvp->v_op == union_vnodeop_p)
|
||||
VOP_UNLOCK(lowerrootvp, 0, p);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Obtain upper vnode by calling namei() on the path. The
|
||||
* upperrootvp will be turned referenced but not locked.
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
|
||||
error = namei(ndp);
|
||||
|
||||
#if 0
|
||||
if (lowerrootvp->v_op == union_vnodeop_p)
|
||||
vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
#endif
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
upperrootvp = ndp->ni_vp;
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULL;
|
||||
|
||||
UDEBUG(("mount_root UPPERVP %p locked = %d\n", upperrootvp,
|
||||
VOP_ISLOCKED(upperrootvp, NULL)));
|
||||
|
||||
/*
|
||||
* Check multi union mount to avoid `lock myself again' panic.
|
||||
* Also require that it be a directory.
|
||||
*/
|
||||
if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) {
|
||||
#ifdef DIAGNOSTIC
|
||||
printf("union_mount: multi union mount?\n");
|
||||
#endif
|
||||
error = EDEADLK;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (upperrootvp->v_type != VDIR) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate our union_mount structure and populate the fields.
|
||||
* The vnode references are stored in the union_mount as held,
|
||||
* unlocked references. Depending on the _BELOW flag, the
|
||||
* filesystems are viewed in a different order. In effect this
|
||||
* is the same as providing a mount-under option to the mount
|
||||
* syscall.
|
||||
*/
|
||||
|
||||
um = (struct union_mount *) malloc(sizeof(struct union_mount),
|
||||
M_UNIONFSMNT, M_WAITOK | M_ZERO);
|
||||
|
||||
um->um_op = args.mntflags & UNMNT_OPMASK;
|
||||
|
||||
switch (um->um_op) {
|
||||
case UNMNT_ABOVE:
|
||||
um->um_lowervp = lowerrootvp;
|
||||
um->um_uppervp = upperrootvp;
|
||||
upperrootvp = NULL;
|
||||
lowerrootvp = NULL;
|
||||
break;
|
||||
|
||||
case UNMNT_BELOW:
|
||||
um->um_lowervp = upperrootvp;
|
||||
um->um_uppervp = lowerrootvp;
|
||||
upperrootvp = NULL;
|
||||
lowerrootvp = NULL;
|
||||
break;
|
||||
|
||||
case UNMNT_REPLACE:
|
||||
vrele(lowerrootvp);
|
||||
lowerrootvp = NULL;
|
||||
um->um_uppervp = upperrootvp;
|
||||
um->um_lowervp = lowerrootvp;
|
||||
upperrootvp = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless the mount is readonly, ensure that the top layer
|
||||
* supports whiteout operations
|
||||
*/
|
||||
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
|
||||
error = VOP_WHITEOUT(um->um_uppervp, NULL, LOOKUP);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
um->um_cred = p->p_ucred;
|
||||
crhold(um->um_cred);
|
||||
um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
|
||||
|
||||
/*
|
||||
* Depending on what you think the MNT_LOCAL flag might mean,
|
||||
* you may want the && to be || on the conditional below.
|
||||
* At the moment it has been defined that the filesystem is
|
||||
* only local if it is all local, ie the MNT_LOCAL flag implies
|
||||
* that the entire namespace is local. If you think the MNT_LOCAL
|
||||
* flag implies that some of the files might be stored locally
|
||||
* then you will want to change the conditional.
|
||||
*/
|
||||
if (um->um_op == UNMNT_ABOVE) {
|
||||
if (((um->um_lowervp == NULLVP) ||
|
||||
(um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) &&
|
||||
(um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in the upper layer's RDONLY flag. This is for the benefit
|
||||
* of lookup() which explicitly checks the flag, rather than asking
|
||||
* the filesystem for its own opinion. This means, that an update
|
||||
* mount of the underlying filesystem to go from rdonly to rdwr
|
||||
* will leave the unioned view as read-only.
|
||||
*/
|
||||
mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
|
||||
|
||||
mp->mnt_data = (qaddr_t) um;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
switch (um->um_op) {
|
||||
case UNMNT_ABOVE:
|
||||
cp = "<above>:";
|
||||
break;
|
||||
case UNMNT_BELOW:
|
||||
cp = "<below>:";
|
||||
break;
|
||||
case UNMNT_REPLACE:
|
||||
cp = "";
|
||||
break;
|
||||
}
|
||||
len = strlen(cp);
|
||||
bcopy(cp, mp->mnt_stat.f_mntfromname, len);
|
||||
|
||||
cp = mp->mnt_stat.f_mntfromname + len;
|
||||
len = MNAMELEN - len;
|
||||
|
||||
(void) copyinstr(args.target, cp, len - 1, &size);
|
||||
bzero(cp + size, len - size);
|
||||
|
||||
(void)union_statfs(mp, &mp->mnt_stat, p);
|
||||
|
||||
UDEBUG(("union_mount: from %s, on %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname));
|
||||
return (0);
|
||||
|
||||
bad:
|
||||
if (um) {
|
||||
if (um->um_uppervp)
|
||||
vrele(um->um_uppervp);
|
||||
if (um->um_lowervp)
|
||||
vrele(um->um_lowervp);
|
||||
/* XXX other fields */
|
||||
free(um, M_UNIONFSMNT);
|
||||
}
|
||||
if (cred)
|
||||
crfree(cred);
|
||||
if (upperrootvp)
|
||||
vrele(upperrootvp);
|
||||
if (lowerrootvp)
|
||||
vrele(lowerrootvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to union layer
|
||||
*/
|
||||
static int
|
||||
union_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
int error;
|
||||
int freeing;
|
||||
int flags = 0;
|
||||
|
||||
UDEBUG(("union_unmount(mp = %p)\n", (void *)mp));
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Keep flushing vnodes from the mount list.
|
||||
* This is needed because of the un_pvp held
|
||||
* reference to the parent vnode.
|
||||
* If more vnodes have been freed on a given pass,
|
||||
* the try again. The loop will iterate at most
|
||||
* (d) times, where (d) is the maximum tree depth
|
||||
* in the filesystem.
|
||||
*/
|
||||
for (freeing = 0; (error = vflush(mp, 0, flags)) != 0;) {
|
||||
struct vnode *vp;
|
||||
int n;
|
||||
|
||||
/* count #vnodes held on mount list */
|
||||
n = 0;
|
||||
LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes)
|
||||
n++;
|
||||
|
||||
/* if this is unchanged then stop */
|
||||
if (n == freeing)
|
||||
break;
|
||||
|
||||
/* otherwise try once more time */
|
||||
freeing = n;
|
||||
}
|
||||
|
||||
/* If the most recent vflush failed, the filesystem is still busy. */
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Discard references to upper and lower target vnodes.
|
||||
*/
|
||||
if (um->um_lowervp)
|
||||
vrele(um->um_lowervp);
|
||||
vrele(um->um_uppervp);
|
||||
crfree(um->um_cred);
|
||||
/*
|
||||
* Finally, throw away the union_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UNIONFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
union_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Supply an unlocked reference to um_uppervp and to um_lowervp. It
|
||||
* is possible for um_uppervp to be locked without the associated
|
||||
* root union_node being locked. We let union_allocvp() deal with
|
||||
* it.
|
||||
*/
|
||||
UDEBUG(("union_root UPPERVP %p locked = %d\n", um->um_uppervp,
|
||||
VOP_ISLOCKED(um->um_uppervp, NULL)));
|
||||
|
||||
VREF(um->um_uppervp);
|
||||
if (um->um_lowervp)
|
||||
VREF(um->um_lowervp);
|
||||
|
||||
error = union_allocvp(vpp, mp, NULLVP, NULLVP, NULL,
|
||||
um->um_uppervp, um->um_lowervp, 1);
|
||||
UDEBUG(("error %d\n", error));
|
||||
UDEBUG(("union_root2 UPPERVP %p locked = %d\n", um->um_uppervp,
|
||||
VOP_ISLOCKED(um->um_uppervp, NULL)));
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
union_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
struct statfs mstat;
|
||||
int lbsize;
|
||||
|
||||
UDEBUG(("union_statfs(mp = %p, lvp = %p, uvp = %p)\n",
|
||||
(void *)mp, (void *)um->um_lowervp, (void *)um->um_uppervp));
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
if (um->um_lowervp) {
|
||||
error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
#if 0
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
#endif
|
||||
lbsize = mstat.f_bsize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
|
||||
error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
|
||||
/*
|
||||
* if the lower and upper blocksizes differ, then frig the
|
||||
* block counts so that the sizes reported by df make some
|
||||
* kind of sense. none of this makes sense though.
|
||||
*/
|
||||
|
||||
if (mstat.f_bsize != lbsize)
|
||||
sbp->f_blocks = ((off_t) sbp->f_blocks * lbsize) / mstat.f_bsize;
|
||||
|
||||
/*
|
||||
* The "total" fields count total resources in all layers,
|
||||
* the "free" fields count only those resources which are
|
||||
* free in the upper layer (since only the upper layer
|
||||
* is writeable).
|
||||
*/
|
||||
sbp->f_blocks += mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files += mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct vfsops union_vfsops = {
|
||||
union_mount,
|
||||
vfs_stdstart, /* underlying start already done */
|
||||
union_unmount,
|
||||
union_root,
|
||||
vfs_stdquotactl,
|
||||
union_statfs,
|
||||
vfs_stdsync, /* XXX assumes no cached data on union level */
|
||||
vfs_stdvget,
|
||||
vfs_stdfhtovp,
|
||||
vfs_stdcheckexp,
|
||||
vfs_stdvptofh,
|
||||
union_init,
|
||||
vfs_stduninit,
|
||||
vfs_stdextattrctl,
|
||||
};
|
||||
|
||||
VFS_SET(union_vfsops, union, VFCF_LOOPBACK);
|
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,12 @@ _random= random
|
||||
.endif
|
||||
|
||||
SUBDIR= 3dfx accf_data accf_http agp aha amr an aue \
|
||||
cam ccd cd9660 coda cue dc de dgm digi ed fdesc fxp if_disc if_ef \
|
||||
cam ccd cd9660 coda cue dc de dgm digi ed fdescfs fxp if_disc if_ef \
|
||||
if_ppp if_sl if_tap if_tun ip6fw ipfilter ipfw ispfw joy kue \
|
||||
libmchain linux lnc md mfs mii mlx msdos ncp netgraph nfs nge ntfs \
|
||||
nullfs nwfs pcn portal procfs ${_random} \
|
||||
nullfs nwfs pcn portalfs procfs ${_random} \
|
||||
rl rp sf sis sk sn sound sppp ste sym syscons sysvipc ti tl twe tx \
|
||||
udbp ugen uhid ukbd ulpt umapfs umass umodem ums union urio usb \
|
||||
udbp ugen uhid ukbd ulpt umapfs umass umodem ums unionfs urio usb \
|
||||
uscanner \
|
||||
vinum vpo vr vx wb wx xl
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user