This commit is contained in:
Pavel 2023-05-10 18:07:46 +03:00
parent 86bb82ed62
commit 253d683766
44 changed files with 3398 additions and 172464 deletions

2
.gitignore vendored
View File

@ -12,9 +12,11 @@
*.prx
*.sprx
*.dump
*.h
link.res
lib/
backup/
shader_dump/*
avplayer_dump/*
savedata/*
tools/vop_generator/vnode_if.*

View File

@ -6,7 +6,7 @@ unit dead_vnops;
interface
uses
vfs_vnode,
vnode,
vfs_default,
vnode_if;

View File

@ -10,7 +10,7 @@ uses
mqueue,
vfile,
vdirent,
vfs_vnode,
vnode,
vmount,
time,
kern_conf,

View File

@ -41,7 +41,7 @@ implementation
uses
time,
vdirent,
vfs_vnode,
vnode,
kern_mtx,
kern_sx,
vfs_vnops,
@ -145,7 +145,11 @@ begin
end;
break;
end;
Assert((de=nil) or ((de^.de_flags and DE_DOOMED)=0),'devfs_find: Exiting a doomed entry');
if (de<>nil) then
begin
Assert((de^.de_flags and DE_DOOMED)=0,'devfs_find: Exiting a doomed entry');
end;
Exit(de);
end;

View File

@ -6,7 +6,7 @@ unit devfs_vfsops;
interface
uses
vfs_vnode,
vnode,
vmount,
devfs,
kern_id;
@ -41,8 +41,6 @@ const
vfs_extattrctl :nil;
vfs_sysctl :nil;
vfs_susp_clean :nil;
vfs_reclaim_lowervp:nil;
vfs_unlink_lowervp :nil;
);
var

View File

@ -16,7 +16,7 @@ uses
vstat,
vuio,
vfcntl,
vfs_vnode,
vnode,
vnamei,
vnode_if,
vfs_default,
@ -71,7 +71,7 @@ function devfs_stat_f(fp:p_file;sb:p_stat):Integer;
function devfs_symlink(ap:p_vop_symlink_args):Integer;
function devfs_truncate_f(fp:p_file;length:Int64):Integer;
function devfs_write_f(fp:p_file;uio:p_uio;flags:Integer):Integer;
function dev2udev(x:p_cdev):DWORD;
function dev2udev(x:p_cdev):Integer;
const
devfs_vnodeops:vop_vector=(
@ -370,6 +370,7 @@ begin
sx_xunlock(@dmp^.dm_lock);
vn_lock(vp, locked or LK_RETRY);
sx_xlock(@dmp^.dm_lock);
if DEVFS_DMP_DROP(dmp) then
begin
sx_xunlock(@dmp^.dm_lock);
@ -640,8 +641,13 @@ loop:
Inc(dev^.si_usecount,vp^.v_usecount);
{ Special casing of ttys for deadfs. Probably redundant. }
dsw:=dev^.si_devsw;
if (dsw<>nil) and ((dsw^.d_flags and D_TTY)<>0) then
if (dsw<>nil) then
if ((dsw^.d_flags and D_TTY)<>0) then
begin
vp^.v_vflag:=vp^.v_vflag or VV_ISTTY;
end;
dev_unlock();
VI_UNLOCK(vp);
if ((dev^.si_flags and SI_ETERNAL)<>0) then
@ -739,7 +745,8 @@ begin
}
oldvp:=nil;
//sx_xlock(@proctree_lock);
//if (td<>nil) and (vp=td^.td_proc^.p_session^.s_ttyvp) then
//if (td<>nil) then
//if (vp=td^.td_proc^.p_session^.s_ttyvp) then
//begin
// SESS_LOCK(td^.td_proc^.p_session);
// VI_LOCK(vp);
@ -1041,6 +1048,8 @@ begin
end;
function devfs_lookupx(ap:p_vop_lookup_args;dm_unlock:PInteger):Integer;
label
_or;
var
td:p_kthread;
cnp:p_componentname;
@ -1157,15 +1166,23 @@ begin
dev_lock();
dde:=@cdev2priv(cdev)^.cdp_dirents[dmp^.dm_idx];
if (dde<>nil) and (dde^<>nil) then
if (dde<>nil) then
if (dde^<>nil) then
begin
de:=dde^;
end;
dev_unlock();
dev_rel(cdev);
break;
end;
if (de=nil) or ((de^.de_flags and DE_WHITEOUT)<>0) then
if (de=nil) then goto _or;
if ((de^.de_flags and DE_WHITEOUT)<>0) then
begin
_or:
if ((nameiop=CREATE) or (nameiop=RENAME)) and
((flags and (LOCKPARENT or WANTPARENT))<>0) and
((flags and ISLASTCN)<>0) then
@ -1943,7 +1960,7 @@ begin
Exit(error);
end;
function dev2udev(x:p_cdev):DWORD;
function dev2udev(x:p_cdev):Integer;
begin
if (x=nil) then
Exit(NODEV);

View File

@ -8,8 +8,8 @@ interface
uses
vmount,
vfs_mount,
vfs_vnode,
fdesc;
vnode,
fdescfs;
{
* /dev/fd Filesystem
@ -37,8 +37,6 @@ const
vfs_extattrctl :nil;
vfs_sysctl :nil;
vfs_susp_clean :nil;
vfs_reclaim_lowervp:nil;
vfs_unlink_lowervp :nil;
);
//VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC);

View File

@ -8,10 +8,10 @@ interface
uses
mqueue,
vmount,
vfs_vnode,
vnode,
vfs_default,
vnode_if,
fdesc;
fdescfs;
{
* /dev/fd Filesystem
@ -156,6 +156,7 @@ end;
function fdesc_allocvp(ftype:fdntype;fd_fd,ix:Integer;mp:p_mount;vpp:pp_vnode):Integer;
label
_or,
loop;
var
fmp:p_fdescmount;
@ -174,7 +175,14 @@ loop:
* protected by the hashmtx.
}
fmp:=p_fdescmount(mp^.mnt_data);
if (fmp=nil) or ((fmp^.flags and FMNT_UNMOUNTF)<>0) then
if (fmp=nil) then
begin
mtx_unlock(fdesc_hashmtx);
Exit(-1);
end;
if ((fmp^.flags and FMNT_UNMOUNTF)<>0) then
begin
mtx_unlock(fdesc_hashmtx);
Exit(-1);
@ -230,8 +238,12 @@ loop:
* protected by the hashmtx.
}
fmp:=p_fdescmount(mp^.mnt_data);
if (fmp=nil) or ((fmp^.flags and FMNT_UNMOUNTF)<>0) then
if (fmp=nil) then goto _or;
if ((fmp^.flags and FMNT_UNMOUNTF)<>0) then
begin
_or:
mtx_unlock(fdesc_hashmtx);
vgone(vp);
vput(vp);

View File

@ -1,4 +1,4 @@
unit fdesc;
unit fdescfs;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
@ -8,7 +8,7 @@ interface
uses
mqueue,
vmount,
vfs_vnode,
vnode,
kern_mtx,
subr_hash;

280
sys/fs/nullfs/null_subr.pas Normal file
View File

@ -0,0 +1,280 @@
unit null_subr;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
vmount,
vnode,
nullfs,
kern_mtx,
subr_hash;
{
* 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.
}
function nullfs_init(vfsp:p_vfsconf):Integer;
function nullfs_uninit(vfsp:p_vfsconf):Integer;
function null_hashget(mp:p_mount;lowervp:p_vnode):p_vnode;
function null_hashins(mp:p_mount;xp:p_null_node):p_vnode;
procedure null_destroy_proto(vp:p_vnode;xp:Pointer);
procedure null_insmntque_dtr(vp:p_vnode;xp:Pointer);
function null_nodeget(mp:p_mount;lowervp:p_vnode;vpp:pp_vnode):Integer;
procedure null_hashrem(xp:p_null_node);
type
p_null_node_hashhead=^t_null_node_hashhead;
t_null_node_hashhead=LIST_HEAD; //null_node
var
null_node_hashtbl:p_null_node_hashhead=nil;
null_hash_mask :QWORD=0;
null_hashmtx:mtx;
implementation
uses
errno,
vfs_subr,
vfs_vnops,
dead_vnops,
vnode_if,
null_vnops;
function vfs_hash_index(vp:p_vnode):DWORD;
begin
Result:=(vp^.v_hash + p_mount(vp^.v_mount)^.mnt_hashseed);
end;
function NULL_NHASH(vp:p_vnode):Pointer;
begin
Result:=@null_node_hashtbl[vfs_hash_index(vp) and null_hash_mask];
end;
{
* Initialise cache headers
}
function nullfs_init(vfsp:p_vfsconf):Integer;
const
desiredvnodes=64;
begin
null_node_hashtbl:=hashinit(desiredvnodes, @null_hash_mask);
mtx_init(null_hashmtx, 'nullhs');
Exit(0);
end;
function nullfs_uninit(vfsp:p_vfsconf):Integer;
begin
mtx_destroy(null_hashmtx);
hashdestroy(null_node_hashtbl, null_hash_mask);
Exit(0);
end;
{
* Exita 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.
}
function null_hashget(mp:p_mount;lowervp:p_vnode):p_vnode;
var
hd:Pointer;
a:p_null_node;
vp:p_vnode;
begin
ASSERT_VOP_LOCKED(lowervp, 'nil_hashget');
{
* Find hash base, and then search the (two-way) linked
* list looking for a nil_node structure which is referencing
* the lower vnode. If found, the increment the nil_node
* reference count (but NOT the lower vnode's VREF counter).
}
hd:=NULL_NHASH(lowervp);
mtx_lock(null_hashmtx);
a:=LIST_FIRST(hd);
while (a<>nil) do
begin
if (a^.null_lowervp=lowervp) and (NULLTOV(a)^.v_mount=mp) then
begin
{
* Since we have the lower node locked the nilfs
* node can not be in the process of recycling. If
* it had been recycled before we grabed the lower
* lock it would not have been found on the hash.
}
vp:=NULLTOV(a);
vref(vp);
mtx_unlock(null_hashmtx);
Exit(vp);
end;
a:=LIST_NEXT(a,@a^.null_hash);
end;
mtx_unlock(null_hashmtx);
Exit(nil);
end;
{
* Act like nil_hashget, but add passed null_node to hash if no existing
* node found.
}
function null_hashins(mp:p_mount;xp:p_null_node):p_vnode;
var
hd:Pointer;
oxp:p_null_node;
ovp:p_vnode;
begin
hd:=NULL_NHASH(xp^.null_lowervp);
mtx_lock(null_hashmtx);
oxp:=LIST_FIRST(hd);
while (oxp<>nil) do
begin
if (oxp^.null_lowervp=xp^.null_lowervp) and
(NULLTOV(oxp)^.v_mount=mp) then
begin
{
* See nil_hashget for a description of this
* operation.
}
ovp:=NULLTOV(oxp);
vref(ovp);
mtx_unlock(null_hashmtx);
Exit(ovp);
end;
oxp:=LIST_NEXT(oxp,@oxp^.null_hash);
end;
LIST_INSERT_HEAD(hd, xp,@xp^.null_hash);
mtx_unlock(null_hashmtx);
Exit(nil);
end;
procedure null_destroy_proto(vp:p_vnode;xp:Pointer);
begin
mtx_lock(vp^.v_lock);
//lockmgr(@vp^.v_lock, LK_EXCLUSIVE, nil);
VI_LOCK(vp);
vp^.v_data :=nil;
vp^.v_vnlock:=@vp^.v_lock;
vp^.v_op :=@dead_vnodeops;
VI_UNLOCK(vp);
vgone(vp);
vput(vp);
FreeMem(xp);
end;
procedure null_insmntque_dtr(vp:p_vnode;xp:Pointer);
begin
vput(p_null_node(xp)^.null_lowervp);
null_destroy_proto(vp, xp);
end;
{
* Make a new or get existing nilfs node.
* Vp is the alias vnode, lowervp is the lower vnode.
*
* The lowervp assumed to be locked and having 'spare' reference. This routine
* vrele lowervp if nilfs node was taken from hash. Otherwise it 'transfers'
* the caller's 'spare' reference to created nilfs vnode.
}
function null_nodeget(mp:p_mount;lowervp:p_vnode;vpp:pp_vnode):Integer;
var
xp:p_null_node;
vp:p_vnode;
error:Integer;
begin
ASSERT_VOP_LOCKED(lowervp, 'lowervp');
Assert(lowervp^.v_usecount >= 1,'Unreferenced vnode %p');
{ Lookup the hash firstly. }
vpp^:=null_hashget(mp, lowervp);
if (vpp^<>nil) then
begin
vrele(lowervp);
Exit(0);
end;
{
* The insmntque1() call below requires the exclusive lock on
* the nilfs vnode. Upgrade the lock now if hash failed to
* provide ready to use vnode.
}
if (VOP_ISLOCKED(lowervp)<>LK_EXCLUSIVE) then
begin
Assert((MOUNTTONULLMOUNT(mp)^.nullm_flags and NULLM_CACHE)<>0,'lowervp %p is not excl locked and cache is disabled');
vn_lock(lowervp, LK_UPGRADE or LK_RETRY);
if ((lowervp^.v_iflag and VI_DOOMED)<>0) then
begin
vput(lowervp);
Exit(ENOENT);
end;
end;
{
* We do not serialize vnode creation, instead we will check for
* duplicates later, when adding new vnode to hash.
* Note that duplicate can only appear in hash if the lowervp is
* locked LK_SHARED.
*
* 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.
}
xp:=AllocMem(sizeof(t_null_node));
error:=getnewvnode('nil', mp, @null_vnodeops, @vp);
if (error<>0) then
begin
vput(lowervp);
FreeMem(xp);
Exit(error);
end;
xp^.null_vnode :=vp;
xp^.null_lowervp:=lowervp;
xp^.null_flags :=0;
vp^.v_type :=lowervp^.v_type;
vp^.v_data :=xp;
vp^.v_vnlock:=lowervp^.v_vnlock;
error:=insmntque1(vp, mp, @null_insmntque_dtr, xp);
if (error<>0) then
Exit(error);
{
* Atomically insert our new node into the hash or vget existing
* if someone else has beaten us to it.
}
vpp^:=null_hashins(mp, xp);
if (vpp^<>nil) then
begin
vrele(lowervp);
null_destroy_proto(vp, xp);
Exit(0);
end;
vpp^:=vp;
Exit(0);
end;
{
* Remove node from hash.
}
procedure null_hashrem(xp:p_null_node);
begin
mtx_lock(null_hashmtx);
LIST_REMOVE(xp,@xp^.null_hash);
mtx_unlock(null_hashmtx);
end;
end.

View File

@ -0,0 +1,350 @@
unit null_vfsops;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
vnode,
vmount,
nullfs,
null_subr;
function nullfs_mount(mp:p_mount):Integer;
function nullfs_unmount(mp:p_mount;mntflags:Integer):Integer;
function nullfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
function nullfs_quotactl(mp:p_mount;cmd,uid:Integer;arg:Pointer):Integer;
function nullfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
function nullfs_sync(mp:p_mount;waitfor:Integer):Integer;
function nullfs_vget(mp:p_mount;ino:DWORD;flags:Integer;vpp:pp_vnode):Integer;
function nullfs_fhtovp(mp:p_mount;fidp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
function nullfs_extattrctl(mp:p_mount;cmd:Integer;filename_vp:p_vnode;namespace:Integer;attrname:PChar):Integer;
const
_null_vfsops:vfsops=(
vfs_mount :@nullfs_mount;
vfs_cmount :nil;
vfs_unmount :@nullfs_unmount;
vfs_root :@nullfs_root;
vfs_quotactl :@nullfs_quotactl;
vfs_statfs :@nullfs_statfs;
vfs_sync :@nullfs_sync;
vfs_vget :@nullfs_vget;
vfs_fhtovp :@nullfs_fhtovp;
vfs_checkexp :nil;
vfs_init :@nullfs_init;
vfs_uninit :@nullfs_uninit;
vfs_extattrctl :@nullfs_extattrctl;
vfs_sysctl :nil;
vfs_susp_clean :nil;
);
//VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK or VFCF_JAIL);
nullfs_vfsconf:vfsconf=(
vfc_version :VFS_VERSION;
vfc_name :'nullfs';
vfc_vfsops :@_null_vfsops;
vfc_typenum :-1;
vfc_refcount:0;
vfc_flags :VFCF_LOOPBACK or VFCF_JAIL;
vfc_opts :nil;
vfc_list :(tqe_next:nil;tqe_prev:nil)
);
implementation
uses
errno,
vuio,
vnamei,
vfs_mount,
vfs_lookup,
vfs_vnops,
vfs_subr,
vnode_if,
null_vnops,
kern_thr,
kern_mtx,
kern_synch;
{
* Mount null layer
}
function nullfs_mount(mp:p_mount):Integer;
var
error:Integer;
lowerrootvp,vp,nullm_rootvp:p_vnode;
xmp:p_null_mount;
target:PChar;
isvnunlocked,len:Integer;
nd:t_nameidata;
ndp:p_nameidata;
begin
error:=0;
isvnunlocked:=0;
ndp:=@nd;
//if (prison_allow(td^.td_ucred, PR_ALLOW_MOUNT_NULLFS)=0) then
// Exit(EPERM);
//if ((mp^.mnt_flag and MNT_ROOTFS)<>0) then
// Exit(EOPNOTSUPP);
{
* Update is a no-op
}
if ((mp^.mnt_flag and MNT_UPDATE)<>0) then
begin
{
* Only support update mounts for NFS export.
}
if (vfs_flagopt(mp^.mnt_optnew, 'export', nil, 0)<>0) then
Exit(0)
else
Exit(EOPNOTSUPP);
end;
{
* Get argument
}
error:=vfs_getopt(mp^.mnt_optnew, {'target'} 'fspath', @target, @len);
if (error<>0) or (target[len - 1]<>#0) then
Exit(EINVAL);
{
* Unlock lower node to avoid possible deadlock.
}
if (mp^.mnt_vnodecovered^.v_op=@null_vnodeops) and
(VOP_ISLOCKED(mp^.mnt_vnodecovered)=LK_EXCLUSIVE) then
begin
VOP_UNLOCK(mp^.mnt_vnodecovered, 0);
isvnunlocked:=1;
end;
{
* Find lower node
}
NDINIT(ndp, LOOKUP, FOLLOW or LOCKLEAF, UIO_SYSSPACE, target, curkthread);
error:=nd_namei(ndp);
{
* Re-lock vnode.
* XXXKIB This is deadlock-prone as well.
}
if (isvnunlocked<>0) then
vn_lock(mp^.mnt_vnodecovered, LK_EXCLUSIVE or LK_RETRY);
if (error<>0) then
Exit(error);
NDFREE(ndp, NDF_ONLY_PNBUF);
{
* Sanity check on lower vnode
}
lowerrootvp:=ndp^.ni_vp;
{
* Check multi null mount to avoid `lock against myself' panic.
}
if (lowerrootvp=VTONULL(mp^.mnt_vnodecovered)^.null_lowervp) then
begin
vput(lowerrootvp);
Exit(EDEADLK);
end;
xmp:=AllocMem(sizeof(t_null_mount));
{
* 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_nodeget(mp, lowerrootvp, @vp);
{
* Make sure the node alias worked
}
if (error<>0) then
begin
FreeMem(xmp);
Exit(error);
end;
{
* Keep a held reference to the root vnode.
* It is vrele'd in nullfs_unmount.
}
nullm_rootvp:=vp;
nullm_rootvp^.v_vflag:=nullm_rootvp^.v_vflag or VV_ROOT;
xmp^.nullm_rootvp:=nullm_rootvp;
{
* Unlock the node (either the lower or the alias)
}
VOP_UNLOCK(vp, 0);
if ((p_mount(NULLVPTOLOWERVP(nullm_rootvp)^.v_mount)^.mnt_flag and MNT_LOCAL)<>0) then
begin
MNT_ILOCK(mp);
mp^.mnt_flag:=mp^.mnt_flag or MNT_LOCAL;
MNT_IUNLOCK(mp);
end;
xmp^.nullm_flags:=xmp^.nullm_flags or NULLM_CACHE;
if (vfs_getopt(mp^.mnt_optnew, 'nocache', nil, nil)=0) then
xmp^.nullm_flags:=xmp^.nullm_flags and (not NULLM_CACHE);
MNT_ILOCK(mp);
if ((xmp^.nullm_flags and NULLM_CACHE)<>0) then
begin
mp^.mnt_kern_flag:=mp^.mnt_kern_flag or
(p_mount(lowerrootvp^.v_mount)^.mnt_kern_flag and (MNTK_MPSAFE or MNTK_SHARED_WRITES or MNTK_LOOKUP_SHARED or MNTK_EXTENDED_SHARED));
end;
mp^.mnt_kern_flag:=mp^.mnt_kern_flag or MNTK_LOOKUP_EXCL_DOTDOT;
MNT_IUNLOCK(mp);
mp^.mnt_data:= xmp;
vfs_getnewfsid(mp);
if ((xmp^.nullm_flags and NULLM_CACHE)<>0) then
begin
MNT_ILOCK(xmp^.nullm_vfs);
TAILQ_INSERT_TAIL(@xmp^.nullm_vfs^.mnt_uppers,mp,@mp^.mnt_upper_link);
MNT_IUNLOCK(xmp^.nullm_vfs);
end;
vfs_mountedfrom(mp, target);
Exit(0);
end;
{
* Free reference to null layer
}
function nullfs_unmount(mp:p_mount;mntflags:Integer):Integer;
var
mntdata:p_null_mount;
ump:p_mount;
error,flags:Integer;
begin
if ((mntflags and MNT_FORCE)<>0) then
flags:=FORCECLOSE
else
flags:=0;
{ There is 1 extra root vnode reference (nullm_rootvp). }
error:=vflush(mp, 1, flags);
if (error<>0) then
Exit(error);
{
* Finally, throw away the null_mount structure
}
mntdata:=mp^.mnt_data;
ump:=mntdata^.nullm_vfs;
if ((mntdata^.nullm_flags and NULLM_CACHE)<>0) then
begin
MNT_ILOCK(ump);
while ((ump^.mnt_kern_flag and MNTK_VGONE_UPPER)<>0) do
begin
ump^.mnt_kern_flag:=ump^.mnt_kern_flag or MNTK_VGONE_WAITER;
msleep(@ump^.mnt_uppers, @ump^.mnt_mtx, 0, 'vgnupw', 0);
end;
TAILQ_REMOVE(@ump^.mnt_uppers,mp,@mp^.mnt_upper_link);
MNT_IUNLOCK(ump);
end;
mp^.mnt_data:=nil;
FreeMem(mntdata);
Exit(0);
end;
function nullfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
var
vp:p_vnode;
begin
{
* Exitlocked reference to root.
}
vp:=MOUNTTONULLMOUNT(mp)^.nullm_rootvp;
VREF(vp);
//ASSERT_VOP_UNLOCKED(vp, 'root vnode is locked');
vn_lock(vp, flags or LK_RETRY);
vpp^:=vp;
Exit(0);
end;
function nullfs_quotactl(mp:p_mount;cmd,uid:Integer;arg:Pointer):Integer;
begin
Exit(VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)^.nullm_vfs, cmd, uid, arg));
end;
function nullfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
var
error:Integer;
mstat:t_statfs;
begin
FillChar(mstat,sizeof(mstat),0);
error:=VFS_STATFS(MOUNTTONULLMOUNT(mp)^.nullm_vfs, @mstat);
if (error<>0) then
Exit(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;
Exit(0);
end;
function nullfs_sync(mp:p_mount;waitfor:Integer):Integer;
begin
{
* XXX - Assumes no data cached at null layer.
}
Exit(0);
end;
function nullfs_vget(mp:p_mount;ino:DWORD;flags:Integer;vpp:pp_vnode):Integer;
var
error:Integer;
begin
Assert((flags and LK_TYPE_MASK)<>0,
('nullfs_vget: no lock requested'));
error:=VFS_VGET(MOUNTTONULLMOUNT(mp)^.nullm_vfs, ino, flags, vpp);
if (error<>0) then
Exit(error);
Exit(null_nodeget(mp, vpp^, vpp));
end;
function nullfs_fhtovp(mp:p_mount;fidp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
var
error:Integer;
begin
error:=VFS_FHTOVP(MOUNTTONULLMOUNT(mp)^.nullm_vfs, fidp, flags, vpp);
if (error<>0) then
Exit(error);
Exit(null_nodeget(mp, vpp^, vpp));
end;
function nullfs_extattrctl(mp:p_mount;cmd:Integer;filename_vp:p_vnode;namespace:Integer;attrname:PChar):Integer;
begin
Exit(VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)^.nullm_vfs, cmd, filename_vp, namespace, attrname));
end;
end.

View File

@ -0,0 +1,888 @@
unit null_vnops;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
vnode,
vnode_if,
vfs_default;
function null_bypass(ap:p_vop_generic_args):Integer;
function null_add_writecount(ap:p_vop_add_writecount_args):Integer;
function null_lookup(ap:p_vop_lookup_args):Integer;
function null_open(ap:p_vop_open_args):Integer;
function null_setattr(ap:p_vop_setattr_args):Integer;
function null_getattr(ap:p_vop_getattr_args):Integer;
function null_access(ap:p_vop_access_args):Integer;
function null_accessx(ap:p_vop_accessx_args):Integer;
function null_remove(ap:p_vop_remove_args):Integer;
function null_rename(ap:p_vop_rename_args):Integer;
function null_rmdir(ap:p_vop_rmdir_args):Integer;
function null_lock(ap:p_vop_lock1_args):Integer;
function null_unlock(ap:p_vop_unlock_args):Integer;
function null_inactive(ap:p_vop_inactive_args):Integer;
function null_reclaim(ap:p_vop_reclaim_args):Integer;
function null_print(ap:p_vop_print_args):Integer;
function null_getwritemount(ap:p_vop_getwritemount_args):Integer;
function null_vptofh(ap:p_vop_vptofh_args):Integer;
function null_vptocnp(ap:p_vop_vptocnp_args):Integer;
function null_link(ap:p_vop_link_args):Integer;
const
null_vnodeops:vop_vector=(
vop_default :nil;
vop_bypass :@null_bypass;
vop_islocked :@vop_stdislocked;
vop_lookup :@null_lookup;
vop_cachedlookup :nil;
vop_create :nil;
vop_whiteout :nil;
vop_mknod :nil;
vop_open :@null_open;
vop_close :nil;
vop_access :@null_access;
vop_accessx :@null_accessx;
vop_getattr :@null_getattr;
vop_setattr :@null_setattr;
vop_markatime :nil;
vop_read :nil;
vop_write :nil;
vop_ioctl :nil;
vop_poll :nil;
vop_kqfilter :nil;
vop_revoke :nil;
vop_fsync :nil;
vop_remove :@null_remove;
vop_link :@null_link;
vop_rename :@null_rename;
vop_mkdir :nil;
vop_rmdir :@null_rmdir;
vop_symlink :nil;
vop_readdir :nil;
vop_readlink :nil;
vop_inactive :@null_inactive;
vop_reclaim :@null_reclaim;
vop_lock1 :@null_lock;
vop_unlock :@null_unlock;
vop_bmap :@VOP_EOPNOTSUPP;
vop_strategy :@VOP_EOPNOTSUPP;
vop_getwritemount :@null_getwritemount;
vop_print :@null_print;
vop_pathconf :nil;
vop_advlock :nil;
vop_advlockasync :nil;
vop_advlockpurge :@vop_stdadvlockpurge;
vop_reallocblks :nil;
vop_getpages :nil;
vop_putpages :nil;
vop_getacl :nil;
vop_setacl :nil;
vop_aclcheck :nil;
vop_closeextattr :nil;
vop_getextattr :nil;
vop_listextattr :nil;
vop_openextattr :nil;
vop_deleteextattr :nil;
vop_setextattr :nil;
vop_setlabel :nil;
vop_vptofh :@null_vptofh;
vop_vptocnp :@null_vptocnp;
vop_allocate :nil;
vop_advise :nil;
vop_unp_bind :nil;
vop_unp_connect :nil;
vop_unp_detach :nil;
vop_is_text :nil;
vop_set_text :nil;
vop_unset_text :nil;
vop_get_writecount:nil;
vop_add_writecount:@null_add_writecount;
);
implementation
uses
sysutils,
nullfs,
null_subr,
errno,
vnamei,
vmount,
vfs_subr,
vfs_vnops,
kern_mtx;
type
ppp_vnode=^pp_vnode;
function null_bypass(ap:p_vop_generic_args):Integer;
label
_out,
_nxt,
_err;
var
this_vp_p:pp_vnode;
error:Integer;
old_vps:array[0..VDESC_MAX_VPS-1] of p_vnode;
vps_p :array[0..VDESC_MAX_VPS-1] of pp_vnode;
vppp:ppp_vnode;
descp:p_vnodeop_desc;
reles,i:Integer;
begin
descp:=ap^.a_desc;
{
* Map the vnodes going in.
* Later, we'll invoke the operation based on
* the first mapped vnode's operation vector.
}
reles:=descp^.vdesc_flags;
i:=0;
while (i < VDESC_MAX_VPS) do
begin
if (descp^.vdesc_vp_offsets[i]=Byte(-1)) then
break; { bail out at end of list }
this_vp_p:=VOPARG_OFFSETTO(descp^.vdesc_vp_offsets[i],ap);
vps_p[i]:=this_vp_p;
{
* 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<>0) then
begin
if (this_vp_p^=nil) then
begin
old_vps[i]:=nil;
goto _nxt;
end;
if (this_vp_p^^.v_op<>@null_vnodeops) then
begin
old_vps[i]:=nil;
goto _nxt;
end;
end;
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 and VDESC_VP0_WILLRELE)<>0) then
VREF(this_vp_p^);
//
_nxt:
reles:=reles shr 1;
Inc(i);
end;
{
* Call the operation on the lower layer
* with the modified argument structure.
}
if (vps_p[0]=nil) then goto _err;
if (vps_p[0]^<>nil) then
begin
error:=VCALL(ap);
end else
begin
_err:
Writeln(Format('null_bypass: no map for %s',[descp^.vdesc_name]));
error:=EINVAL;
end;
{
* Maintain the illusion of call-by-value
* by restoring vnodes in the argument structure
* to their original value.
}
reles:=descp^.vdesc_flags;
i:=0;
while (i < VDESC_MAX_VPS) do
begin
if (descp^.vdesc_vp_offsets[i]=Byte(-1)) then
break; { bail out at end of list }
if (old_vps[i]<>nil) then
begin
vps_p[i]^:=old_vps[i];
if ((reles and VDESC_VP0_WILLRELE)<>0) then
vrele((vps_p[i])^);
end;
//
reles:=reles shr 1;
Inc(i);
end;
{
* Map the possible out-going vpp
* (Assumes that the lower layer always Exits
* a VREF'ed vpp unless it gets an error.)
}
if (descp^.vdesc_vpp_offset<>VDESC_NO_OFFSET) and
((descp^.vdesc_flags and VDESC_NOMAP_VPP)=0) and
(error=0) then
begin
{
* XXX - even though some ops have vpp Exited vp's,
* several ops actually vrele this before Exiting.
* We must avoid these ops.
* (This should go away when these ops are regularized.)
}
if ((descp^.vdesc_flags and VDESC_VPP_WILLRELE)<>0) then
goto _out;
vppp:=VOPARG_OFFSETTO(descp^.vdesc_vpp_offset,ap);
if (vppp^<>nil) then
error:=null_nodeget(old_vps[0]^.v_mount,vppp^^,vppp^);
end;
_out:
Exit(error);
end;
function null_add_writecount(ap:p_vop_add_writecount_args):Integer;
var
lvp,vp:p_vnode;
error:Integer;
begin
vp:=ap^.a_vp;
lvp:=NULLVPTOLOWERVP(vp);
Assert(vp^.v_writecount + ap^.a_inc >= 0,'wrong writecount inc');
if (vp^.v_writecount > 0) and (vp^.v_writecount + ap^.a_inc=0) then
error:=VOP_ADD_WRITECOUNT(lvp, -1)
else
if (vp^.v_writecount=0) and (vp^.v_writecount + ap^.a_inc > 0) then
error:=VOP_ADD_WRITECOUNT(lvp, 1)
else
error:=0;
if (error=0) then
Inc(vp^.v_writecount,ap^.a_inc);
Exit(error);
end;
{
* 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.
}
function null_lookup(ap:p_vop_lookup_args):Integer;
var
cnp:p_componentname;
dvp:p_vnode;
flags:Integer;
vp,ldvp,lvp:p_vnode;
error:Integer;
begin
cnp:=ap^.a_cnp;
dvp:=ap^.a_dvp;
flags:=cnp^.cn_flags;
if ((flags and ISLASTCN)<>0) and
((p_mount(dvp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) and
((cnp^.cn_nameiop=DELETE) or (cnp^.cn_nameiop=RENAME)) then
Exit(EROFS);
{
* Although it is possible to call null_bypass(), we'll do
* a direct call to reduce overhead
}
ldvp:=NULLVPTOLOWERVP(dvp);
vp:=nil;
lvp:=nil;
error:=VOP_LOOKUP(ldvp, @lvp, cnp);
if (error=EJUSTRETURN) and
((flags and ISLASTCN)<>0) and
((p_mount(dvp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) and
((cnp^.cn_nameiop=CREATE) or (cnp^.cn_nameiop=RENAME)) then
error:=EROFS;
if ((error=0) or (error=EJUSTRETURN)) and (lvp<>nil) then
begin
if (ldvp=lvp) then
begin
ap^.a_vpp^:=dvp;
VREF(dvp);
vrele(lvp);
end else
begin
error:=null_nodeget(dvp^.v_mount, lvp, @vp);
if (error=0) then
ap^.a_vpp^:=vp;
end;
end;
Exit(error);
end;
function null_open(ap:p_vop_open_args):Integer;
var
retval:Integer;
vp,ldvp:p_vnode;
begin
vp:=ap^.a_vp;
ldvp:=NULLVPTOLOWERVP(vp);
retval:=null_bypass(Pointer(ap));
//if (retval=0) then
// vp^.v_object:=ldvp^.v_object;
Exit(retval);
end;
{
* Setattr call. Disallow write attempts if the layer is mounted read-only.
}
function null_setattr(ap:p_vop_setattr_args):Integer;
var
vp:p_vnode;
vap:p_vattr;
begin
vp:=ap^.a_vp;
vap:=ap^.a_vap;
if ((vap^.va_flags<>QWORD(VNOVAL)) or
(vap^.va_uid<>Integer(VNOVAL)) or
(vap^.va_gid<>Integer(VNOVAL)) or
(vap^.va_atime.tv_sec<>VNOVAL) or
(vap^.va_mtime.tv_sec<>VNOVAL) or
(vap^.va_mode<>Word(VNOVAL))
) and
((p_mount(vp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) then
Exit(EROFS);
if (vap^.va_size<>QWORD(VNOVAL)) then
begin
case (vp^.v_type) of
VDIR:
begin
Exit(EISDIR);
end;
VCHR,
VBLK,
VSOCK,
VFIFO:
begin
if (vap^.va_flags<>QWORD(VNOVAL)) then
Exit(EOPNOTSUPP);
Exit(0);
end;
else
begin
{
* Disallow write attempts if the filesystem is
* mounted read-only.
}
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) then
Exit(EROFS);
end;
end;
end;
Exit(null_bypass(Pointer(ap)));
end;
{
* We handle getattr only to change the fsid.
}
function null_getattr(ap:p_vop_getattr_args):Integer;
var
error:Integer;
begin
error:=null_bypass(Pointer(ap));
if (error<>0) then
Exit(error);
ap^.a_vap^.va_fsid:=p_mount(ap^.a_vp^.v_mount)^.mnt_stat.f_fsid.val[0];
Exit(0);
end;
{
* Handle to disallow write access if mounted read-only.
}
function null_access(ap:p_vop_access_args):Integer;
var
vp:p_vnode;
accmode:accmode_t;
begin
vp:=ap^.a_vp;
accmode:=ap^.a_accmode;
{
* Disallow write attempts on read-only layers;
* unless the file is a socket, fifo, or a block or
* character device resident on the filesystem.
}
if ((accmode and VWRITE)<>0) then
begin
case (vp^.v_type) of
VDIR,
VLNK,
VREG:
begin
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) then
Exit(EROFS);
end;
else;
end;
end;
Exit(null_bypass(Pointer(ap)));
end;
function null_accessx(ap:p_vop_accessx_args):Integer;
var
vp:p_vnode;
accmode:accmode_t;
begin
vp:=ap^.a_vp;
accmode:=ap^.a_accmode;
{
* Disallow write attempts on read-only layers;
* unless the file is a socket, fifo, or a block or
* character device resident on the filesystem.
}
if ((accmode and VWRITE)<>0) then
begin
case (vp^.v_type) of
VDIR,
VLNK,
VREG:
begin
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) then
Exit(EROFS);
end;
else;
end;
end;
Exit(null_bypass(Pointer(ap)));
end;
{
* Increasing refcount of lower vnode is needed at least for the case
* when lower FS is NFS to do sillyrename if the file is in use.
* Unfortunately v_usecount is incremented in many places in
* the kernel and, as such, there may be races that result in
* the NFS client doing an extraneous silly rename, but that seems
* preferable to not doing a silly rename when it is needed.
}
function null_remove(ap:p_vop_remove_args):Integer;
var
retval,vreleit:Integer;
lvp,vp:p_vnode;
tnn:p_null_node;
begin
vp:=ap^.a_vp;
if (vrefcnt(vp) > 1) then
begin
lvp:=NULLVPTOLOWERVP(vp);
VREF(lvp);
vreleit:=1;
end else
vreleit:=0;
tnn:=VTONULL(vp);
tnn^.null_flags:=tnn^.null_flags or NULLV_DROP;
retval:=null_bypass(@ap^.a_gen);
if (vreleit<>0) then
vrele(lvp);
Exit(retval);
end;
{
* We handle this to eliminate null FS to lower FS
* file moving. Don't know why we don't allow this,
* possibly we should.
}
function null_rename(ap:p_vop_rename_args):Integer;
label
_cross;
var
tdvp,fvp,fdvp,tvp:p_vnode;
tnn:p_null_node;
begin
tdvp:=ap^.a_tdvp;
fvp:=ap^.a_fvp;
fdvp:=ap^.a_fdvp;
tvp:=ap^.a_tvp;
if (tvp<>nil) then
begin
if (fvp^.v_mount<>tvp^.v_mount) then goto _cross;
end;
{ Check for cross-device rename. }
if (fvp^.v_mount<>tdvp^.v_mount) then
begin
_cross:
if (tdvp=tvp) then
vrele(tdvp)
else
vput(tdvp);
if (tvp<>nil) then
vput(tvp);
vrele(fdvp);
vrele(fvp);
Exit(EXDEV);
end;
if (tvp<>nil) then
begin
tnn:=VTONULL(tvp);
tnn^.null_flags:=tnn^.null_flags or NULLV_DROP;
end;
Exit(null_bypass(Pointer(ap)));
end;
function null_rmdir(ap:p_vop_rmdir_args):Integer;
var
tnn:p_null_node;
begin
tnn:=VTONULL(ap^.a_vp);
tnn^.null_flags:=tnn^.null_flags or NULLV_DROP;
Exit(null_bypass(Pointer(ap)));
end;
{
* 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.
}
function null_lock(ap:p_vop_lock1_args):Integer;
var
vp:p_vnode;
flags:Integer;
nn:p_null_node;
lvp:p_vnode;
error:Integer;
begin
vp:=ap^.a_vp;
flags:=ap^.a_flags;
if ((flags and LK_INTERLOCK)=0) then
begin
VI_LOCK(vp);
flags:=flags or LK_INTERLOCK;
ap^.a_flags:=flags;
end;
nn:=VTONULL(vp);
{
* If we're still active we must ask the lower layer to
* lock as ffs has special lock considerations in it's
* vop lock.
}
if (nn<>nil) then
begin
lvp:=NULLVPTOLOWERVP(vp);
if (lvp<>nil) then
begin
VI_LOCK(lvp);
VI_UNLOCK(vp);
{
* We have to hold the vnode here to solve a potential
* reclaim race. If we're forcibly vgone'd while we
* still have refs, a thread could be sleeping inside
* the lowervp's vop_lock routine. When we vgone we will
* drop our last ref to the lowervp, which would allow it
* to be reclaimed. The lowervp could then be recycled,
* in which case it is not legal to be sleeping in it's VOP.
* We prevent it from being recycled by holding the vnode
* here.
}
vholdl(lvp);
error:=VOP_LOCK(lvp,flags,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
{
* We might have slept to get the lock and someone might have
* clean our vnode already, switching vnode lock from one in
* lowervp to v_lock in our own vnode structure. Handle this
* case by reacquiring correct lock in requested mode.
}
if (VTONULL(vp)=nil) and (error=0) then
begin
ap^.a_flags:=ap^.a_flags and (not (LK_TYPE_MASK or LK_INTERLOCK));
case (flags and LK_TYPE_MASK) of
LK_SHARED:
begin
ap^.a_flags:=ap^.a_flags or LK_SHARED;
end;
LK_UPGRADE,
LK_EXCLUSIVE:
begin
ap^.a_flags:=ap^.a_flags or LK_EXCLUSIVE;
end;
else
Assert(False,'Unsupported lock request');
end;
VOP_UNLOCK(lvp, 0);
error:=vop_stdlock(ap);
end;
vdrop(lvp);
end else
error:=vop_stdlock(ap);
end else
error:=vop_stdlock(ap);
Exit(error);
end;
{
* 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.
}
function null_unlock(ap:p_vop_unlock_args):Integer;
label
_else;
var
vp:p_vnode;
flags:Integer;
mtxlkflag:Integer;
nn:p_null_node;
lvp:p_vnode;
error:Integer;
begin
vp:=ap^.a_vp;
flags:=ap^.a_flags;
mtxlkflag:=0;
if ((flags and LK_INTERLOCK)<>0) then
mtxlkflag:=1
else
if (not mtx_owned(VI_MTX(vp)^)) then
begin
VI_LOCK(vp);
mtxlkflag:=2;
end;
nn:=VTONULL(vp);
if (nn<>nil) then
begin
lvp:=NULLVPTOLOWERVP(vp);
if (lvp=nil) then goto _else;
VI_LOCK(lvp);
flags:=flags or LK_INTERLOCK;
vholdl(lvp);
VI_UNLOCK(vp);
error:=VOP_UNLOCK(lvp, flags);
vdrop(lvp);
if (mtxlkflag=0) then
VI_LOCK(vp);
end else
begin
_else:
if (mtxlkflag=2) then
VI_UNLOCK(vp);
error:=vop_stdunlock(ap);
end;
Exit(error);
end;
{
* Do not allow the VOP_INACTIVE to be passed to the lower layer,
* since the reference count on the lower vnode is not related to
* ours.
}
function null_inactive(ap:p_vop_inactive_args):Integer;
var
vp,lvp:p_vnode;
xp:p_null_node;
mp:p_mount;
xmp:p_null_mount;
begin
vp:=ap^.a_vp;
xp:=VTONULL(vp);
lvp:=NULLVPTOLOWERVP(vp);
mp:=vp^.v_mount;
xmp:=MOUNTTONULLMOUNT(mp);
if ((xmp^.nullm_flags and NULLM_CACHE)=0) or
((xp^.null_flags and NULLV_DROP)<>0) or
((lvp^.v_vflag and VV_NOSYNC)<>0) then
begin
{
* If this is the last reference and caching of the
* nullfs vnodes is not enabled, or the lower vnode is
* deleted, then free up the vnode so as not to tie up
* the lower vnodes.
}
//vp^.v_object:=nil;
vrecycle(vp);
end;
Exit(0);
end;
{
* Now, the nullfs vnode and, due to the sharing lock, the lower
* vnode, are exclusively locked, and we shall destroy the null vnode.
}
function null_reclaim(ap:p_vop_reclaim_args):Integer;
var
vp:p_vnode;
xp:p_null_node;
lowervp:p_vnode;
begin
vp:=ap^.a_vp;
xp:=VTONULL(vp);
lowervp:=xp^.null_lowervp;
Assert((lowervp<>nil) and (vp^.v_vnlock<>@vp^.v_lock),'Reclaiming incomplete null vnode');
null_hashrem(xp);
{
* Use the interlock to protect the clearing of v_data to
* prevent faults in null_lock().
}
mtx_lock(vp^.v_lock);
//lockmgr(@vp^.v_lock, LK_EXCLUSIVE, nil);
VI_LOCK(vp);
vp^.v_data:=nil;
//vp^.v_object:=nil;
vp^.v_vnlock:=@vp^.v_lock;
VI_UNLOCK(vp);
{
* If we were opened for write, we leased one write reference
* to the lower vnode. If this is a reclamation due to the
* forced unmount, undo the reference now.
}
if (vp^.v_writecount > 0) then
VOP_ADD_WRITECOUNT(lowervp, -1);
if ((xp^.null_flags and NULLV_NOUNLOCK)<>0) then
vunref(lowervp)
else
vput(lowervp);
FreeMem(xp);
Exit(0);
end;
function null_print(ap:p_vop_print_args):Integer;
var
vp:p_vnode;
begin
vp:=ap^.a_vp;
Writeln(Format('vp=%p, lowervp=%p', [vp,VTONULL(vp)^.null_lowervp]));
Exit(0);
end;
{ ARGSUSED }
function null_getwritemount(ap:p_vop_getwritemount_args):Integer;
label
_else;
var
xp:p_null_node;
lowervp:p_vnode;
vp:p_vnode;
begin
vp:=ap^.a_vp;
VI_LOCK(vp);
xp:=VTONULL(vp);
if (xp<>nil) then
begin
lowervp:=xp^.null_lowervp;
if (lowervp=nil) then goto _else;
VI_LOCK(lowervp);
VI_UNLOCK(vp);
vholdl(lowervp);
VI_UNLOCK(lowervp);
VOP_GETWRITEMOUNT(lowervp, ap^.a_mpp);
vdrop(lowervp);
end else
begin
_else:
VI_UNLOCK(vp);
ap^.a_mpp^:=nil;
end;
Exit(0);
end;
function null_vptofh(ap:p_vop_vptofh_args):Integer;
var
lvp:p_vnode;
begin
lvp:=NULLVPTOLOWERVP(ap^.a_vp);
Exit(VOP_VPTOFH(lvp, ap^.a_fhp));
end;
function null_vptocnp(ap:p_vop_vptocnp_args):Integer;
var
vp:p_vnode;
dvp:pp_vnode;
lvp,ldvp:p_vnode;
error,locked:Integer;
begin
vp:=ap^.a_vp;
dvp:=ap^.a_vpp;
if (vp^.v_type=VDIR) then
Exit(vop_stdvptocnp(ap));
locked:=VOP_ISLOCKED(vp);
lvp:=NULLVPTOLOWERVP(vp);
vhold(lvp);
VOP_UNLOCK(vp, 0); { vp is held by vn_vptocnp_locked that called us }
ldvp:=lvp;
vref(lvp);
error:=0;
Assert(False,'TODO vn_vptocnp');
//error:=vn_vptocnp(@ldvp, ap^.a_buf, ap^.a_buflen);
vdrop(lvp);
if (error<>0) then
begin
vn_lock(vp, locked or LK_RETRY);
Exit(ENOENT);
end;
{
* Exclusive lock is required by insmntque1 call in
* null_nodeget()
}
error:=vn_lock(ldvp, LK_EXCLUSIVE);
if (error<>0) then
begin
vrele(ldvp);
vn_lock(vp, locked or LK_RETRY);
Exit(ENOENT);
end;
vref(ldvp);
error:=null_nodeget(vp^.v_mount, ldvp, dvp);
if (error=0) then
begin
VOP_UNLOCK(dvp^, 0); { keep reference on *dvp }
end;
vn_lock(vp, locked or LK_RETRY);
Exit(error);
end;
function null_link(ap:p_vop_link_args):Integer;
begin
if (ap^.a_tdvp^.v_mount<>ap^.a_vp^.v_mount) then
Exit(EXDEV);
Exit(null_bypass(Pointer(ap)));
end;
end.

63
sys/fs/nullfs/nullfs.pas Normal file
View File

@ -0,0 +1,63 @@
unit nullfs;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
vmount,
vnode;
const
NULLM_CACHE=$0001;
NULLV_NOUNLOCK=$0001;
NULLV_DROP =$0002;
type
p_null_mount=^t_null_mount;
t_null_mount=packed record
nullm_vfs :p_mount;
nullm_rootvp:p_vnode; { Reference to root null_node }
nullm_flags :QWORD;
end;
p_null_node=^t_null_node;
t_null_node=packed record
null_hash :LIST_ENTRY; { Hash list }
null_lowervp:p_vnode; { VREFed once }
null_vnode :p_vnode; { Back pointer }
null_flags :DWORD;
end;
function MOUNTTONULLMOUNT(mp:p_mount):p_null_mount;
function VTONULL(vp:p_vnode):p_null_node;
function NULLTOV(xp:p_null_node):p_vnode;
function NULLVPTOLOWERVP(vp:p_vnode):p_vnode;
implementation
function MOUNTTONULLMOUNT(mp:p_mount):p_null_mount;
begin
Result:=mp^.mnt_data;
end;
function VTONULL(vp:p_vnode):p_null_node;
begin
Result:=vp^.v_data;
end;
function NULLTOV(xp:p_null_node):p_vnode;
begin
Result:=xp^.null_vnode;
end;
function NULLVPTOLOWERVP(vp:p_vnode):p_vnode;
begin
Result:=VTONULL(vp)^.null_lowervp;
end;
end.

View File

@ -9,8 +9,8 @@ uses
ntapi;
const
IOSIZE_MAX =High(Int64);
DEVFS_IOSIZE_MAX=High(Int64);
IOSIZE_MAX =High(Integer);
DEVFS_IOSIZE_MAX=High(Integer);
function copystr(from,_to:Pointer;maxlen:ptruint;lencopied:pptruint):Integer;
function copyin(udaddr,kaddr:Pointer;len:ptruint):Integer; inline;

View File

@ -31,6 +31,7 @@ uses
devfs_devs,
devfs_vfsops,
fdesc_vfsops,
null_vfsops,
kern_descrip,
vfs_mountroot;
@ -44,6 +45,7 @@ procedure module_init;
begin
vfs_register(@devfs_vfsconf);
vfs_register(@fdescfs_vfsconf);
vfs_register(@nullfs_vfsconf);
vfs_mountroot.vfs_mountroot();
fildesc_drvinit;
end;

View File

@ -257,10 +257,6 @@
<Filename Value="..\..\rtl\murmurhash.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\vfs\vfs_vnode.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\vfs\vfs_mount.pas"/>
<IsPartOfProject Value="True"/>
@ -453,10 +449,6 @@
<Filename Value="..\sce_errno.inc"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\fdescfs\fdesc.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\fdescfs\fdesc_vfsops.pas"/>
<IsPartOfProject Value="True"/>
@ -469,6 +461,30 @@
<Filename Value="..\kern\subr_hash.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\nullfs\nullfs.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\fdescfs\fdescfs.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\vfs\vnode.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\nullfs\null_subr.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\nullfs\null_vnops.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\fs\nullfs\null_vfsops.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
@ -479,7 +495,7 @@
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir);.."/>
<OtherUnitFiles Value="..;..\..\rtl;..\..\kernel\libthr;..\kern;..\vm;..\vfs;..\fs\deadfs;..\fs\devfs;..\fs\fdescfs"/>
<OtherUnitFiles Value="..;..\..\rtl;..\..\kernel\libthr;..\kern;..\vm;..\vfs;..\fs\deadfs;..\fs\devfs;..\fs\fdescfs;..\fs\nullfs"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>

View File

@ -39,7 +39,6 @@ uses
thr_stack,
sys_mmap,
kern_synch,
vfs_vnode,
murmurhash,
hamt,
vfs_subr,
@ -63,10 +62,15 @@ uses
vstat,
vfcntl,
vdirent,
fdesc,
fdesc_vfsops,
fdesc_vnops,
kern_descrip;
fdescfs,
kern_descrip,
vnode,
nullfs,
null_subr,
null_vnops,
null_vfsops;
var
mtx:umutex;

View File

@ -69,16 +69,16 @@ procedure timevalfix(t1:ptimeval);
procedure timevaladd(t1,t2:ptimeval);
procedure timevalsub(t1,t2:ptimeval);
function timespeccmp_lt(tvp,uvp:ptimespec):Integer; inline;
function timespeccmp_lt(tvp,uvp:ptimespec):Integer;
procedure TIMEVAL_TO_TIMESPEC(tv:ptimeval;ts:ptimespec); inline;
procedure TIMESPEC_TO_TIMEVAL(tv:ptimeval;ts:ptimespec); inline;
procedure TIMEVAL_TO_TIMESPEC(tv:ptimeval;ts:ptimespec);
procedure TIMESPEC_TO_TIMEVAL(tv:ptimeval;ts:ptimespec);
function TIMESPEC_TO_UNIT(ts:ptimespec):Int64; inline; //Unit
function TIMEVAL_TO_UNIT (tv:ptimeval ):Int64; inline; //Unit
function USEC_TO_UNIT (usec:QWORD ):Int64; inline; //Unit
function TIMESPEC_TO_UNIT(ts:ptimespec):Int64; //Unit
function TIMEVAL_TO_UNIT (tv:ptimeval ):Int64; //Unit
function USEC_TO_UNIT (usec:QWORD ):Int64; //Unit
function tvtohz(time:Int64):Int64; inline;
function tvtohz(time:Int64):Int64;
procedure usec2timespec(ts:ptimespec;timeo:DWORD);
procedure TIMESPEC_ADD(dst,src,val:ptimespec);
@ -158,7 +158,7 @@ begin
timevalfix(t1);
end;
function timespeccmp_lt(tvp,uvp:ptimespec):Integer; inline;
function timespeccmp_lt(tvp,uvp:ptimespec):Integer;
begin
if (tvp^.tv_sec=uvp^.tv_sec) then
begin
@ -169,34 +169,34 @@ begin
end;
end;
procedure TIMEVAL_TO_TIMESPEC(tv:ptimeval;ts:ptimespec); inline;
procedure TIMEVAL_TO_TIMESPEC(tv:ptimeval;ts:ptimespec);
begin
ts^.tv_sec :=tv^.tv_sec;
ts^.tv_nsec:=tv^.tv_usec * 1000;
end;
procedure TIMESPEC_TO_TIMEVAL(tv:ptimeval;ts:ptimespec); inline;
procedure TIMESPEC_TO_TIMEVAL(tv:ptimeval;ts:ptimespec);
begin
tv^.tv_sec :=ts^.tv_sec;
tv^.tv_usec:=ts^.tv_nsec div 1000;
end;
function TIMESPEC_TO_UNIT(ts:ptimespec):Int64; inline; //Unit
function TIMESPEC_TO_UNIT(ts:ptimespec):Int64; //Unit
begin
Result:=(QWORD(ts^.tv_sec)*10000000)+(QWORD(ts^.tv_nsec) div 100);
end;
function TIMEVAL_TO_UNIT(tv:ptimeval):Int64; inline; //Unit
function TIMEVAL_TO_UNIT(tv:ptimeval):Int64; //Unit
begin
Result:=(QWORD(tv^.tv_sec)*10000000)+(QWORD(tv^.tv_usec)*10);
end;
function USEC_TO_UNIT(usec:QWORD):Int64; inline; //Unit
function USEC_TO_UNIT(usec:QWORD):Int64; //Unit
begin
Result:=(usec*10);
end;
function tvtohz(time:Int64):Int64; inline;
function tvtohz(time:Int64):Int64;
begin
Result:=time;
end;

View File

@ -10,7 +10,7 @@ uses
vmount,
vfile,
vuio,
vfs_vnode,
vnode,
time,
vm,
vm_object,
@ -1159,6 +1159,7 @@ function make_dev_physpath_alias(flags:Integer;
pdev,old_alias:p_cdev;
physpath:PChar):Integer;
label
_ret,
_out;
var
devfspath:PChar;
@ -1203,8 +1204,11 @@ begin
R:=Format('%s/%s',[physpath,pdev^.si_name]);
Move(PChar(R)^,devfspath^,Length(R)+1);
if (old_alias<>nil) and (strcomp(old_alias^.si_name, devfspath)=0) then
if (old_alias=nil) then goto _ret;
if (strcomp(old_alias^.si_name, devfspath)=0) then
begin
_ret:
{ Retain the existing alias. }
cdev^:=old_alias;
old_alias:=nil;
@ -1271,8 +1275,9 @@ begin
csw:=dev^.si_devsw;
dev^.si_devsw:=nil; { already nil for SI_ALIAS }
while (csw<>nil) and (csw^.d_purge<>nil) and (dev^.si_threadcount<>0) do
while (csw<>nil) and (dev^.si_threadcount<>0) do
begin
if (csw^.d_purge=nil) then Break;
csw^.d_purge(dev);
msleep(csw, @devmtx, PRIBIO, 'devprg', hz div 10);
if (dev^.si_threadcount<>0) then

View File

@ -15,7 +15,7 @@ uses
vfcntl,
vfilio,
vmount,
vfs_vnode,
vnode,
vsocketvar;
const

View File

@ -135,6 +135,7 @@ var
c:p_capability;
error:Integer;
begin
if (fp_cap=nil) then Exit(EINVAL);
if (fp_cap^.f_type<>DTYPE_CAPABILITY) then
begin
fpp^:=fp_cap;

View File

@ -8,7 +8,7 @@ interface
uses
vstat,
vuio,
vfs_vnode,
vnode,
kern_thr,
kern_id;

View File

@ -7,7 +7,7 @@ interface
uses
vfile,
vfs_vnode,
vnode,
kern_rwlock,
kern_id;

View File

@ -7,7 +7,7 @@ interface
uses
sysutils,
vfs_vnode,
vnode,
vnode_if,
vdirent,
vuio,
@ -17,7 +17,6 @@ uses
vnamei,
vfcntl,
vpoll,
vsocketvar,
kern_thr,
kern_mtx;
@ -573,6 +572,8 @@ var
begin
vp:=ap^.a_vp;
//Writeln('vop_std lock:',HexStr(ap^.a_vp^.v_vnlock));
Result:=lockmgr(vp^.v_vnlock,ap^.a_flags,VI_MTX(vp));
//Exit(_lockmgr_args(vp^.v_vnlock, ap^.a_flags, VI_MTX(vp),
@ -587,6 +588,8 @@ var
begin
vp:=ap^.a_vp;
//Writeln('vop_stdunlock:',HexStr(ap^.a_vp^.v_vnlock));
Result:=lockmgr(vp^.v_vnlock,ap^.a_flags or LK_RELEASE,VI_MTX(vp));
//Exit(lockmgr(vp^.v_vnlock, ap^.a_flags or LK_RELEASE, VI_MTX(vp)));
@ -596,6 +599,8 @@ end;
function vop_stdislocked(ap:p_vop_islocked_args):Integer;
begin
//Writeln('vop_stdislocked:',HexStr(ap^.a_vp^.v_vnlock),':',mtx_owned(ap^.a_vp^.v_vnlock^));
if mtx_owned(ap^.a_vp^.v_vnlock^) then
Exit(LK_EXCLUSIVE)
else

View File

@ -13,7 +13,7 @@ uses
vfile,
vfiledesc,
vfcntl,
vfs_vnode,
vnode,
vnode_if,
vnamei,
vmount,
@ -316,13 +316,20 @@ end;
function compute_cn_lkflags(mp:p_mount;lkflags,cnflags:Integer):Integer;
begin
if (mp=nil) or (((lkflags and LK_SHARED)<>0) and
if (mp=nil) then
begin
lkflags:=lkflags and (not LK_SHARED);
lkflags:=lkflags or LK_EXCLUSIVE;
Exit(lkflags);
end;
if (((lkflags and LK_SHARED)<>0) and
(((mp^.mnt_kern_flag and MNTK_LOOKUP_SHARED)=0) or
(((cnflags and ISDOTDOT)<>0) and
((mp^.mnt_kern_flag and MNTK_LOOKUP_EXCL_DOTDOT)<>0)))) then
begin
lkflags:=lkflags and (not LK_SHARED);
lkflags:=lkflags or LK_EXCLUSIVE;
lkflags:=lkflags or LK_EXCLUSIVE;
end;
Exit(lkflags);
end;
@ -348,11 +355,12 @@ begin
}
if ((flags and ISOPEN)<>0) then
begin
if (mp<>nil) and
((mp^.mnt_kern_flag and MNTK_EXTENDED_SHARED)<>0) then
if (mp<>nil) then
if ((mp^.mnt_kern_flag and MNTK_EXTENDED_SHARED)<>0) then
begin
Exit(0)
else
Exit(1);
end;
Exit(1);
end;
{
@ -674,8 +682,8 @@ unionlookup:
if (error=ENOENT) and
((dp^.v_vflag and VV_ROOT)<>0) and
(dp^.v_mount<>nil) and
((p_mount(dp^.v_mount)^.mnt_flag and MNT_UNION)<>0) then
(dp^.v_mount<>nil) then
if ((p_mount(dp^.v_mount)^.mnt_flag and MNT_UNION)<>0) then
begin
tdp:=dp;
dp:=p_mount(dp^.v_mount)^.mnt_vnodecovered;
@ -684,9 +692,7 @@ unionlookup:
VREF(dp);
vput(tdp);
VFS_UNLOCK_GIANT(tvfslocked);
vn_lock(dp,
compute_cn_lkflags(dp^.v_mount, cnp^.cn_lkflags or
LK_RETRY, cnp^.cn_flags));
vn_lock(dp,compute_cn_lkflags(dp^.v_mount, cnp^.cn_lkflags or LK_RETRY, cnp^.cn_flags));
goto unionlookup;
end;
@ -883,8 +889,8 @@ success:
* Because of lookup_shared we may have the vnode shared locked, but
* the caller may want it to be exclusively locked.
}
if (needs_exclusive_leaf(dp^.v_mount, cnp^.cn_flags) and
VOP_ISLOCKED(dp)<>LK_EXCLUSIVE) then
if (needs_exclusive_leaf(dp^.v_mount, cnp^.cn_flags)<>0) and
(VOP_ISLOCKED(dp)<>LK_EXCLUSIVE) then
begin
vn_lock(dp, LK_UPGRADE or LK_RETRY);
if ((dp^.v_iflag and VI_DOOMED)<>0) then

View File

@ -14,7 +14,7 @@ uses
kern_mtx,
kern_synch,
kern_thr,
vfs_vnode,
vnode,
vfs_init,
vfs_lookup,
vnode_if;
@ -103,6 +103,7 @@ function kernel_mount(ma:p_mntarg;flags:QWORD):Integer;
implementation
uses
murmurhash,
errno,
systm,
vfs_vnops,
@ -723,6 +724,18 @@ begin
mtx_destroy(mp^.mnt_mtx);
end;
var
mnt_hashseed:QWORD=QWORD($FEEDBABEFEEDBABE);
function get_mnt_hashseed:DWORD;
var
i:QWORD;
begin
i:=MurmurHash64A(@mnt_hashseed,SizeOf(mnt_hashseed),mnt_hashseed);
mnt_hashseed:=i;
Result:=DWORD(i);
end;
function vfs_mount_alloc(vp :p_vnode;
vfsp :p_vfsconf;
fspath:PChar):p_mount;
@ -755,7 +768,8 @@ begin
//mac_mount_init(mp);
//mac_mount_create(cred, mp);
mp^.mnt_hashseed:=$FEEDBABE; //arc4rand
//arc4rand(&mp->mnt_hashseed, sizeof mp->mnt_hashseed, 0);
mp^.mnt_hashseed:=get_mnt_hashseed;
TAILQ_INIT(@mp^.mnt_uppers);
Result:=mp;

View File

@ -19,7 +19,7 @@ uses
errno,
vuio,
vnamei,
vfs_vnode,
vnode,
vnode_if,
vfiledesc,
vfs_subr,
@ -68,7 +68,10 @@ var
val,val_arg:PChar;
opts:PChar;
begin
if (options=nil) or (options[0]=#0) then
if (options=nil) then
Exit(ma);
if (options[0]=#0) then
Exit(ma);
p:=strdup(options);
@ -165,11 +168,11 @@ begin
mpp^:=mp;
set_rootvnode();
error:=kern_symlink('/', 'dev', UIO_SYSSPACE);
if (error<>0) then
begin
Writeln('kern_symlink /dev / returns ',error);
end;
//error:=kern_symlink('/', 'dev', UIO_SYSSPACE);
//if (error<>0) then
//begin
// Writeln('kern_symlink /dev / returns ',error);
//end;
Exit(error);
end;
@ -296,9 +299,9 @@ begin
begin
vfs_unbusy(mpdevfs);
{ Unlink the no longer needed /dev/dev ^. / symlink }
error:=kern_unlink('/dev/dev', UIO_SYSSPACE);
if (error<>0) then
Writeln('mountroot: unable to unlink /dev/dev ', error);
//error:=kern_unlink('/dev/dev', UIO_SYSSPACE);
//if (error<>0) then
// Writeln('mountroot: unable to unlink /dev/dev ', error);
end;
Exit(0);
@ -332,26 +335,23 @@ begin
end;
procedure vfs_mountroot();
label
_end;
var
mp:p_mount;
//opt:p_vfsoptlist;
error:Integer;
begin
mtx_lock(VFS_Giant);
error:=vfs_mountroot_devfs(@mp);
if (error<>0) then goto _end;
//opt:=nil;
//vfs_domount('fdescfs','/dev/fd',MNT_RDONLY,@opt);
error:=vfs_mountroot_simple('nullfs','/','',nil,MNT_RDONLY or MNT_ROOTFS);
if (error<>0) then goto _end;
//error:=vfs_mountroot_simple('fdescfs','/dev/fd','',nil,0);
//error:=vfs_mountroot_simple('fdescfs','/fd','',nil,0);
//if (error=0) then
//begin
// error:=vfs_mountroot_shuffle(mp);
//end;
error:=vfs_mountroot_shuffle(mp);
_end:
mtx_unlock(VFS_Giant);
end;

View File

@ -10,7 +10,7 @@ uses
vmount,
vfile,
vstat,
vfs_vnode,
vnode,
vnode_if,
vdirent,
vfcntl,
@ -45,14 +45,14 @@ procedure vgone(vp:p_vnode);
function vget(vp:p_vnode;flags:Integer):Integer;
procedure vref(vp:p_vnode);
function vrefcnt(vp:p_vnode):Integer;
procedure vrele(vp:p_vnode);
procedure vput(vp:p_vnode);
procedure vunref(vp:p_vnode);
procedure vinactive(vp:p_vnode);
function vflush(mp:p_mount;rootrefs,flags:Integer):Integer;
procedure vfs_notify_upper(vp:p_vnode;event:Integer);
procedure assert_vi_locked (vp:p_vnode;str:PChar);
procedure assert_vi_unlocked (vp:p_vnode;str:PChar);
procedure assert_vop_locked (vp:p_vnode;str:PChar);
@ -122,18 +122,6 @@ procedure __mnt_vnode_markerfree_active(mvp:pp_vnode;mp:p_mount);
procedure vntblinit; //SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vntblinit, NULL);
procedure vnlru_proc(); //SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, @vnlru_kp);
implementation
uses
errno,
vfs_vnops,
subr_uio,
vm_object,
vsys_generic,
dead_vnops,
rtprio,
kern_conf;
{
* List of vnodes that are ready for recycling.
}
@ -180,6 +168,18 @@ var
freevnodes :Integer=0;
vnlru_nowhere :Integer=0;
implementation
uses
errno,
vfs_vnops,
subr_uio,
vm_object,
vsys_generic,
dead_vnops,
rtprio,
kern_conf;
{
* Macros to control when a vnode is freed and recycled. All require
* the vnode interlock.
@ -406,8 +406,9 @@ begin
while (count<>0) do
begin
vp:=TAILQ_FIRST(@mp^.mnt_nvnodelist);
while (vp<>nil) and (vp^.v_type=VMARKER) do
while (vp<>nil) do
begin
if (vp^.v_type<>VMARKER) then Break;
vp:=TAILQ_NEXT(vp,@vp^.v_nmntvnodes);
end;
if (vp=nil) then
@ -705,7 +706,7 @@ var
td:p_kthread;
vp:p_vnode;
//struct bufobj *bo;
error:Integer;
error,susp:Integer;
begin
vp:=nil;
td:=curkthread;
@ -723,7 +724,13 @@ begin
}
if (freevnodes > wantfreevnodes) then
vnlru_free(1);
error:=getnewvnode_wait(ord((mp<>nil) and ((mp^.mnt_kern_flag and MNTK_SUSPEND)<>0)));
susp:=ord(False);
if (mp<>nil) then
begin
susp:=ord(((mp^.mnt_kern_flag and MNTK_SUSPEND)<>0));
end;
error:=getnewvnode_wait(susp);
System.InterlockedIncrement64(numvnodes);
mtx_unlock(vnode_free_list_mtx);
@ -785,7 +792,7 @@ begin
* E.g., nilfs uses vfs_hash_index() on the lower vnode for
* its own hashing.
}
vp^.v_hash:=ptrint(vp) shr vnsz2log;
vp^.v_hash:=ptruint(vp) shr vnsz2log;
vpp^:=vp;
Exit(0);
@ -2233,7 +2240,8 @@ begin
}
obj:=nil;
//obj:=vp^.v_object;
if (obj<>nil) and ((obj^.flags and OBJ_MIGHTBEDIRTY)<>0) then
if (obj<>nil) then
if ((obj^.flags and OBJ_MIGHTBEDIRTY)<>0) then
begin
VM_OBJECT_LOCK(obj);
//vm_object_page_clean(obj, 0, 0, OBJPC_NOSYNC);
@ -2432,87 +2440,6 @@ begin
VI_UNLOCK(vp);
end;
procedure notify_lowervp_vfs_dummy(mp:p_mount;lowervp:p_vnode);
begin
end;
const
vgonel_vfsops:vfsops=(
vfs_mount :nil;
vfs_cmount :nil;
vfs_unmount :nil;
vfs_root :nil;
vfs_quotactl :nil;
vfs_statfs :nil;
vfs_sync :nil;
vfs_vget :nil;
vfs_fhtovp :nil;
vfs_checkexp :nil;
vfs_init :nil;
vfs_uninit :nil;
vfs_extattrctl :nil;
vfs_sysctl :nil;
vfs_susp_clean :nil;
vfs_reclaim_lowervp:@notify_lowervp_vfs_dummy;
vfs_unlink_lowervp :@notify_lowervp_vfs_dummy
);
{
* Notify upper mounts about reclaimed or unlinked vnode.
}
procedure vfs_notify_upper(vp:p_vnode;event:Integer);
label
unlock;
var
mp,ump,mmp:p_mount;
begin
mp:=vp^.v_mount;
if (mp=nil) then
Exit;
MNT_ILOCK(mp);
if TAILQ_EMPTY(@mp^.mnt_uppers) then
goto unlock;
MNT_IUNLOCK(mp);
mmp:=AllocMem(SizeOf(t_mount));
mmp^.mnt_op:=@vgonel_vfsops;
mmp^.mnt_kern_flag:=mmp^.mnt_kern_flag or MNTK_MARKER;
MNT_ILOCK(mp);
mp^.mnt_kern_flag:=mmp^.mnt_kern_flag or MNTK_VGONE_UPPER;
ump:=TAILQ_FIRST(@mp^.mnt_uppers);
while (ump<>nil) do
begin
if ((ump^.mnt_kern_flag and MNTK_MARKER)<>0) then
begin
ump:=TAILQ_NEXT(ump,@ump^.mnt_upper_link);
continue;
end;
TAILQ_INSERT_AFTER(@mp^.mnt_uppers, ump, mmp,@mmp^.mnt_upper_link);
MNT_IUNLOCK(mp);
case event of
VFS_NOTIFY_UPPER_RECLAIM:
VFS_RECLAIM_LOWERVP(ump, vp);
VFS_NOTIFY_UPPER_UNLINK:
VFS_UNLINK_LOWERVP(ump, vp);
else
Assert(false, 'invalid event');
end;
MNT_ILOCK(mp);
ump:=TAILQ_NEXT(mmp,@mmp^.mnt_upper_link);
TAILQ_REMOVE(@mp^.mnt_uppers, mmp,@mmp^.mnt_upper_link);
end;
FreeMem(mmp);
mp^.mnt_kern_flag:=mp^.mnt_kern_flag and (not MNTK_VGONE_UPPER);
if ((mp^.mnt_kern_flag and MNTK_VGONE_WAITER)<>0) then
begin
mp^.mnt_kern_flag:=mp^.mnt_kern_flag and (not MNTK_VGONE_WAITER);
wakeup(@mp^.mnt_uppers);
end;
unlock:
MNT_IUNLOCK(mp);
end;
{
* vgone, with the vp interlock held.
}
@ -2540,7 +2467,6 @@ begin
active:=vp^.v_usecount;
oweinact:=(vp^.v_iflag and VI_OWEINACT);
VI_UNLOCK(vp);
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_RECLAIM);
{
* Clean out any buffers associated with the vnode.
@ -3074,6 +3000,7 @@ end;
procedure vfs_badlock(msg,str:PChar;vp:p_vnode);
begin
Writeln(msg,' ',str);
Assert(false,RawByteString(msg)+' '+RawByteString(str));
end;
@ -3573,8 +3500,12 @@ begin
mp:=vp^.v_mount;
VFS_ASSERT_GIANT(mp);
ASSERT_VOP_LOCKED(vp,'vfs_mark_atime');
if (mp<>nil) and ((mp^.mnt_flag and (MNT_NOATIME or MNT_RDONLY))=0) then
if (mp<>nil) then
if ((mp^.mnt_flag and (MNT_NOATIME or MNT_RDONLY))=0) then
begin
VOP_MARKATIME(vp);
end;
end;
{
@ -3642,9 +3573,11 @@ begin
MNT_ILOCK(mp);
Assert(mvp^^.v_mount=mp, 'marker vnode mount list mismatch');
vp:=TAILQ_NEXT(mvp^,@mvp^^.v_nmntvnodes);
while (vp<>nil) and
((vp^.v_type=VMARKER) or ((vp^.v_iflag and VI_DOOMED)<>0)) do
while (vp<>nil) do
begin
if not ((vp^.v_type=VMARKER) or ((vp^.v_iflag and VI_DOOMED)<>0)) then Break;
vp:=TAILQ_NEXT(vp,@vp^.v_nmntvnodes);
end;
{ Check if we are done }
if (vp=nil) then

View File

@ -18,7 +18,7 @@ uses
vfilio,
vdisk,
vfs_mount,
vfs_vnode,
vnode,
vfs_vnops,
vfs_subr,
vfs_lookup;
@ -100,8 +100,7 @@ uses
kern_synch,
kern_descrip,
vnode_if,
sys_capability,
vm_object;
sys_capability;
{
* Sync each mounted filesystem.
@ -1395,7 +1394,6 @@ begin
//if (error)
// goto _out;
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK);
error:=VOP_REMOVE(nd.ni_dvp, vp, @nd.ni_cnd);
_out:
@ -2694,7 +2692,6 @@ restart:
Exit(error);
goto restart;
end;
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK);
error:=VOP_RMDIR(nd.ni_dvp, nd.ni_vp, @nd.ni_cnd);
vn_finished_write(mp);
_out:

View File

@ -13,7 +13,7 @@ uses
vuio,
vmparam,
vfilio,
vfs_vnode;
vnode;
function vn_lock(vp:p_vnode;flags:Integer):Integer;
@ -414,13 +414,15 @@ var
mp:p_mount;
error, lock_flags:Integer;
begin
lock_flags:=LK_EXCLUSIVE;
if (vp^.v_type<>VFIFO) and
((flags and FWRITE)=0) and
(vp^.v_mount<>nil) and
((p_mount(vp^.v_mount)^.mnt_kern_flag and MNTK_EXTENDED_SHARED)<>0) then
lock_flags:=LK_SHARED
else
lock_flags:=LK_EXCLUSIVE;
(vp^.v_mount<>nil) then
if ((p_mount(vp^.v_mount)^.mnt_kern_flag and MNTK_EXTENDED_SHARED)<>0) then
begin
lock_flags:=LK_SHARED;
end;
VFS_ASSERT_GIANT(vp^.v_mount);
@ -714,8 +716,8 @@ begin
__end:=uio^.uio_offset - 1;
mtxp:=mtx_pool_find(mtxpool_sleep, fp);
mtx_lock(mtxp^);
if (fp^.f_advice<>nil) and
(p_fadvise_info(fp^.f_advice)^.fa_advice=POSIX_FADV_NOREUSE) then
if (fp^.f_advice<>nil) then
if (p_fadvise_info(fp^.f_advice)^.fa_advice=POSIX_FADV_NOREUSE) then
begin
if (start<>0) and (p_fadvise_info(fp^.f_advice)^.fa_prevend + 1=start) then
begin
@ -761,15 +763,26 @@ begin
// bwillwrite();
ioflag:=IO_UNIT;
if (vp^.v_type=VREG) and ((fp^.f_flag and O_APPEND)<>0) then
begin
ioflag:=ioflag or IO_APPEND;
end;
if ((fp^.f_flag and FNONBLOCK)<>0) then
begin
ioflag:=ioflag or IO_NDELAY;
end;
if ((fp^.f_flag and O_DIRECT)<>0) then
begin
ioflag:=ioflag or IO_DIRECT;
if ((fp^.f_flag and O_FSYNC)<>0) or
((vp^.v_mount<>nil) and
((p_mount(vp^.v_mount)^.mnt_flag and MNT_SYNCHRONOUS)<>0)) then
end;
if ((fp^.f_flag and O_FSYNC)<>0) then
begin
ioflag:=ioflag or IO_SYNC;
end;
if (vp^.v_mount<>nil) then
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_SYNCHRONOUS)<>0) then
begin
ioflag:=ioflag or IO_SYNC;
end;
mp:=nil;
if (vp^.v_type<>VCHR) then
begin
@ -817,8 +830,8 @@ begin
__end:=uio^.uio_offset - 1;
mtxp:=mtx_pool_find(mtxpool_sleep, fp);
mtx_lock(mtxp^);
if (fp^.f_advice<>nil) and
(p_fadvise_info(fp^.f_advice)^.fa_advice=POSIX_FADV_NOREUSE) then
if (fp^.f_advice<>nil) then
if (p_fadvise_info(fp^.f_advice)^.fa_advice=POSIX_FADV_NOREUSE) then
begin
if (start<>0) and (p_fadvise_info(fp^.f_advice)^.fa_prevend + 1=start) then
begin
@ -872,10 +885,15 @@ begin
foffset_lock_uio(fp, uio, flags);
mp:=vp^.v_mount;
if (mp<>nil) then
if ((mp^.mnt_kern_flag and MNTK_NO_IOPF)=0) then
begin
error:=doio(fp, uio, flags or FOF_OFFSET);
goto out_last;
end;
if (uio^.uio_segflg<>UIO_USERSPACE) or
(vp^.v_type<>VREG) or
((mp<>nil) and
((mp^.mnt_kern_flag and MNTK_NO_IOPF)=0)) or
{(not vn_io_fault_enable)} false then
begin
error:=doio(fp, uio, flags or FOF_OFFSET);

View File

@ -11,7 +11,7 @@ uses
kern_mtx,
kern_synch,
kern_sig,
vfs_vnode;
vnode;
const
DFLTPHYS=(64*1024);
@ -240,7 +240,7 @@ type
vfs_cmount_t =function (ma,data:Pointer;flags:QWORD):Integer;
vfs_unmount_t =function (mp:p_mount;mntflags:Integer):Integer;
vfs_root_t =function (mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
vfs_quotactl_t =function (mp:p_mount;cmds:Integer;uid:Integer;arg:Pointer):Integer;
vfs_quotactl_t =function (mp:p_mount;cmds,uid:Integer;arg:Pointer):Integer;
vfs_statfs_t =function (mp:p_mount;sbp:p_statfs):Integer;
vfs_sync_t =function (mp:p_mount;waitfor:Integer):Integer;
vfs_vget_t =function (mp:p_mount;ino:DWORD;flags:Integer;vpp:pp_vnode):Integer;
@ -256,23 +256,21 @@ type
p_vfsops=^vfsops;
vfsops=packed record
vfs_mount :vfs_mount_t ;
vfs_cmount :vfs_cmount_t ;
vfs_unmount :vfs_unmount_t ;
vfs_root :vfs_root_t ;
vfs_quotactl :vfs_quotactl_t ;
vfs_statfs :vfs_statfs_t ;
vfs_sync :vfs_sync_t ;
vfs_vget :vfs_vget_t ;
vfs_fhtovp :vfs_fhtovp_t ;
vfs_checkexp :vfs_checkexp_t ;
vfs_init :vfs_init_t ;
vfs_uninit :vfs_uninit_t ;
vfs_extattrctl :vfs_extattrctl_t ;
vfs_sysctl :vfs_sysctl_t ;
vfs_susp_clean :vfs_susp_clean_t ;
vfs_reclaim_lowervp:vfs_notify_lowervp_t;
vfs_unlink_lowervp :vfs_notify_lowervp_t;
vfs_mount :vfs_mount_t ;
vfs_cmount :vfs_cmount_t ;
vfs_unmount :vfs_unmount_t ;
vfs_root :vfs_root_t ;
vfs_quotactl :vfs_quotactl_t ;
vfs_statfs :vfs_statfs_t ;
vfs_sync :vfs_sync_t ;
vfs_vget :vfs_vget_t ;
vfs_fhtovp :vfs_fhtovp_t ;
vfs_checkexp :vfs_checkexp_t ;
vfs_init :vfs_init_t ;
vfs_uninit :vfs_uninit_t ;
vfs_extattrctl:vfs_extattrctl_t;
vfs_sysctl :vfs_sysctl_t ;
vfs_susp_clean:vfs_susp_clean_t;
end;
{
@ -286,7 +284,7 @@ type
vfsconf=packed record
vfc_version :DWORD ; // ABI version number
vfc_name :array[0..MFSNAMELEN-1] of Char; // filesystem type name
vfc_name :array[0..MFSNAMELEN-1+4] of Char; // filesystem type name
vfc_vfsops :p_vfsops ; // filesystem operations vector
vfc_typenum :Integer ; // historic filesystem type number
vfc_refcount:Integer ; // number mounted of this type
@ -397,12 +395,12 @@ function MNT_MTX(mp:p_mount):p_mtx; inline;
procedure MNT_REF(mp:p_mount); inline;
procedure MNT_REL(mp:p_mount); inline;
function VFS_NEEDSGIANT(mp:p_mount):Boolean; inline;
function VFS_NEEDSGIANT(mp:p_mount):Boolean;
function VFS_LOCK_GIANT(mp:p_mount):Integer;
procedure VFS_UNLOCK_GIANT(locked:Integer);
procedure VFS_ASSERT_GIANT(mp:p_mount);
function VFS_PROLOGUE(mp:p_mount):Boolean; inline;
function VFS_PROLOGUE(mp:p_mount):Boolean;
procedure VFS_EPILOGUE(_enable_stops:Boolean); inline;
function VFS_MOUNT(mp:p_mount):Integer;
@ -411,8 +409,9 @@ function VFS_ROOT(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
function VFS_STATFS(mp:p_mount;sbp:p_statfs):Integer;
function VFS_SYNC(mp:p_mount;WAIT:Integer):Integer;
function VFS_VGET(mp:p_mount;ino:QWORD;flags:Integer;vpp:pp_vnode):Integer;
procedure VFS_RECLAIM_LOWERVP(mp:p_mount;vp:p_vnode);
procedure VFS_UNLINK_LOWERVP(mp:p_mount;vp:p_vnode);
function VFS_QUOTACTL(mp:p_mount;c,u:Integer;a:Pointer):Integer;
function VFS_FHTOVP(mp:p_mount;fidp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
function VFS_EXTATTRCTL(mp:p_mount;c:Integer;fn:p_vnode;ns:Integer;n:PChar):Integer;
procedure VFS_KNOTE_LOCKED(vp:p_vnode;hint:Integer);
procedure VFS_KNOTE_UNLOCKED(vp:p_vnode;hint:Integer);
@ -464,9 +463,15 @@ begin
end;
end;
function VFS_NEEDSGIANT(mp:p_mount):Boolean; inline;
function VFS_NEEDSGIANT(mp:p_mount):Boolean;
begin
Result:=(mp<>nil) and ((mp^.mnt_kern_flag and MNTK_MPSAFE)=0) ;
if (mp<>nil) then
begin
Result:=((mp^.mnt_kern_flag and MNTK_MPSAFE)=0);
end else
begin
Result:=False;
end;
end;
function VFS_LOCK_GIANT(mp:p_mount):Integer;
@ -491,9 +496,15 @@ begin
mtx_assert(VFS_Giant);
end;
function VFS_PROLOGUE(mp:p_mount):Boolean; inline;
function VFS_PROLOGUE(mp:p_mount):Boolean;
begin
Result:=(mp<>nil) and ((mp^.mnt_vfc^.vfc_flags and VFCF_SBDRY)<>0) and (sigdeferstop<>0);
if (mp<>nil) then
begin
Result:=((mp^.mnt_vfc^.vfc_flags and VFCF_SBDRY)<>0) and (sigdeferstop<>0);
end else
begin
Result:=False;
end;
end;
procedure VFS_EPILOGUE(_enable_stops:Boolean); inline;
@ -559,28 +570,31 @@ begin
VFS_EPILOGUE(_enable_stops);
end;
procedure VFS_RECLAIM_LOWERVP(mp:p_mount;vp:p_vnode);
function VFS_QUOTACTL(mp:p_mount;c,u:Integer;a:Pointer):Integer;
var
_enable_stops:Boolean;
begin
if (mp^.mnt_op^.vfs_reclaim_lowervp<>nil) then
begin
_enable_stops:=VFS_PROLOGUE(MP);
mp^.mnt_op^.vfs_reclaim_lowervp(mp,vp);
VFS_EPILOGUE(_enable_stops);
end;
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_quotactl(mp,c,u,a);
VFS_EPILOGUE(_enable_stops);
end;
procedure VFS_UNLINK_LOWERVP(mp:p_mount;vp:p_vnode);
function VFS_FHTOVP(mp:p_mount;fidp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
var
_enable_stops:Boolean;
begin
if (mp^.mnt_op^.vfs_unlink_lowervp<>nil) then
begin
_enable_stops:=VFS_PROLOGUE(MP);
mp^.mnt_op^.vfs_unlink_lowervp(mp,vp);
VFS_EPILOGUE(_enable_stops);
end;
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_fhtovp(mp,fidp,flags,vpp);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_EXTATTRCTL(mp:p_mount;c:Integer;fn:p_vnode;ns:Integer;n:PChar):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_extattrctl(mp,c,fn,ns,n);
VFS_EPILOGUE(_enable_stops);
end;
procedure VFS_KNOTE_LOCKED(vp:p_vnode;hint:Integer);

View File

@ -9,7 +9,7 @@ uses
vcapability,
vfcntl,
vuio,
vfs_vnode,
vnode,
kern_thr;
const

View File

@ -1,4 +1,4 @@
unit vfs_vnode;
unit vnode;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
@ -85,7 +85,7 @@ const
VSTAT_PERMS =VREAD_ATTRIBUTES or VREAD_ACL;
//Permissions that allow to change the state of the file in any way.
VMODIFY_PERMS =VWRITE or VAPPEND or VADMIN_PERMS or VDELETE_CHILD or VDELETE;
VMODIFY_PERMS =VWRITE or VAPPEND or VADMIN_PERMS or VDELETE_CHILD or VDELETE;
// vn_open_flags
VN_OPEN_NOAUDIT=$00000001;
@ -116,10 +116,51 @@ const
DFLTPHYS =(64 * 1024);
MAXPHYS =(128 * 1024);
//Flags for vdesc_flags:
VDESC_MAX_VPS=16;
// Low order 16 flag bits are reserved for willrele flags for vp arguments.
VDESC_VP0_WILLRELE=$0001;
VDESC_VP1_WILLRELE=$0002;
VDESC_VP2_WILLRELE=$0004;
VDESC_VP3_WILLRELE=$0008;
VDESC_NOMAP_VPP =$0100;
VDESC_VPP_WILLRELE=$0200;
{
* VDESC_NO_OFFSET is used to identify the end of the offset list
* and in places where no such field exists.
}
VDESC_NO_OFFSET=-1;
type
p_accmode_t=^accmode_t;
accmode_t=Integer;
{ This structure describes the vnode operation taking place. }
p_vnodeop_desc=^t_vnodeop_desc;
t_vnodeop_desc=record
vdesc_name :PChar; { a readable name for debugging }
vdesc_call :Pointer; { Function to call }
{
* These ops are used by bypass routines to map and locate arguments.
* Creds and procs are not needed in bypass routines, but sometimes
* they are useful to (for example) transport layers.
* Nameidata is useful because it has a cred in it.
}
vdesc_vp_offsets :PByte; { list ended by VDESC_NO_OFFSET }
vdesc_flags :Integer; { VDESC_* flags }
vdesc_vpp_offset :Integer; { return vpp location }
end;
p_vop_generic_args=^t_vop_generic_args;
t_vop_generic_args=record
a_desc:p_vnodeop_desc;
//other random data follows, presumably
end;
vop_bypass_t=function(ap:Pointer):Integer;
pp_vnode=^p_vnode;
p_vnode=^t_vnode;
@ -262,12 +303,15 @@ type
va_vaflags :DWORD;
end;
function VOPARG_OFFSETTO(s_offset:Integer;struct_p:Pointer):Pointer;
function VCALL(c:Pointer):Integer;
procedure VI_LOCK(vp:p_vnode);
function VI_TRYLOCK(vp:p_vnode):Boolean;
procedure VI_UNLOCK(vp:p_vnode);
function VI_MTX(vp:p_vnode):p_mtx; inline;
function IGNORE_LOCK(vp:p_vnode):Boolean; inline;
function IGNORE_LOCK(vp:p_vnode):Boolean;
procedure vn_rangelock_unlock(vp:p_vnode;cookie:Pointer);
procedure vn_rangelock_unlock_range(vp:p_vnode;cookie:Pointer;start,__end:Int64);
@ -279,6 +323,68 @@ var
implementation
uses
vmount;
function VOPARG_OFFSETTO(s_offset:Integer;struct_p:Pointer):Pointer;
begin
Result:=struct_p+s_offset;
end;
function get_vp_cb(vp:p_vnode;offset:Pointer):Pointer; inline;
var
v:p_vop_vector;
p:Pointer;
begin
Result:=nil;
if (vp=nil) then Exit;
v:=vp^.v_op;
while (v<>nil) do
begin
p:=PPointer(Pointer(v)+ptrint(offset))^;
if (p<>nil) then
begin
Exit(p);
end;
p:=v^.vop_bypass;
if (p<>nil) then
begin
Exit(p);
end;
v:=v^.vop_default;
end;
end;
function vcall_panic:Integer; inline;
begin
Assert(false,'filesystem goof: vcall_panic');
Exit(2);
end;
type
p_vop_vcall_args=^t_vop_vcall_args;
t_vop_vcall_args=record
a_desc:p_vnodeop_desc;
a_vp :p_vnode;
end;
function VCALL(c:Pointer):Integer;
var
ap:p_vop_vcall_args;
s:Boolean;
begin
if (c=nil) then Exit(vcall_panic);
ap:=c;
if (ap^.a_desc=nil) then Exit(vcall_panic);
if (ap^.a_vp=nil) then Exit(vcall_panic);
if (ap^.a_desc^.vdesc_call=nil) then Exit(vcall_panic);
c:=get_vp_cb(ap^.a_vp,ap^.a_desc^.vdesc_call);
Assert(c<>nil,'VCALL');
s:=VFS_PROLOGUE(ap^.a_vp^.v_mount);
Result:=vop_bypass_t(c)(ap);
VFS_EPILOGUE(s);
end;
procedure VI_LOCK(vp:p_vnode);
begin
mtx_lock(vp^.v_interlock);
@ -299,9 +405,10 @@ begin
Result:=@vp^.v_interlock;
end;
function IGNORE_LOCK(vp:p_vnode):Boolean; inline;
function IGNORE_LOCK(vp:p_vnode):Boolean;
begin
Result:=(vp=nil) or (vp^.v_type=VCHR) or (vp^.v_type=VBAD);
if (vp=nil) then Exit(True);
Result:=(vp^.v_type=VCHR) or (vp^.v_type=VBAD);
end;
procedure vn_rangelock_unlock(vp:p_vnode;cookie:Pointer);

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ uses
vuio,
vfile,
vcapability,
vfs_vnode,
vnode,
vfcntl,
vfilio,
vfiledesc,
@ -1134,7 +1134,7 @@ begin
continue;
end;
fp:=fget_unlocked(fd^.fd);
if (fp=nil) or (cap_funwrap(fp, CAP_POLL_EVENT, @fp)<>0) then
if (cap_funwrap(fp, CAP_POLL_EVENT, @fp)<>0) then
begin
if (fp<>nil) then
fdrop(fp);
@ -1208,7 +1208,7 @@ begin
end else
begin
fp:=fget_unlocked(fds^.fd);
if ((fp=nil) or (cap_funwrap(fp, CAP_POLL_EVENT, @fp)<>0)) then
if (cap_funwrap(fp, CAP_POLL_EVENT, @fp)<>0) then
begin
fds^.revents:=POLLNVAL;
Inc(n);

View File

@ -482,10 +482,16 @@ end;
procedure vm_map_entry_set_max_free(entry:vm_map_entry_t);
begin
entry^.max_free:=entry^.adj_free;
if (entry^.left<>nil) and (entry^.left^.max_free>entry^.max_free) then
if (entry^.left<>nil) then
if (entry^.left^.max_free>entry^.max_free) then
begin
entry^.max_free:=entry^.left^.max_free;
if (entry^.right<>nil) and (entry^.right^.max_free>entry^.max_free) then
end;
if (entry^.right<>nil) then
if (entry^.right^.max_free>entry^.max_free) then
begin
entry^.max_free:=entry^.right^.max_free;
end;
end;
{
@ -999,6 +1005,8 @@ function vm_map_findspace(map :vm_map_t;
start :vm_offset_t;
length:vm_size_t;
addr :p_vm_offset_t):Integer;
label
_nxt;
var
entry:vm_map_entry_t;
st:vm_offset_t;
@ -1052,7 +1060,11 @@ begin
{ With max_free, can immediately tell if no solution. }
entry:=map^.root^.right;
if (entry=nil) or (length>entry^.max_free) then
if (entry=nil) then
Exit(1);
if (length>entry^.max_free) then
Exit(1);
{
@ -1062,16 +1074,20 @@ begin
}
while (entry<>nil) do
begin
if (entry^.left<>nil) and (entry^.left^.max_free>=length) then
if (entry^.left<>nil) then
begin
if not (entry^.left^.max_free>=length) then goto _nxt;
entry:=entry^.left;
end else
if (entry^.adj_free>=length) then
begin
addr^:=entry^.__end;
Exit(0);
end else
entry:=entry^.right;
_nxt:
if (entry^.adj_free>=length) then
begin
addr^:=entry^.__end;
Exit(0);
end else
entry:=entry^.right;
end;
end;
{ Can't get here, so panic if we do. }
@ -1124,11 +1140,16 @@ label
var
alignment,initial_addr,start:vm_offset_t;
begin
if (find_space=VMFS_OPTIMAL_SPACE) and
((_object=nil) or
((_object^.flags and OBJ_COLORED)=0)) then
if (find_space=VMFS_OPTIMAL_SPACE) then
begin
find_space:=VMFS_ANY_SPACE;
if (_object=nil) then
begin
find_space:=VMFS_ANY_SPACE;
end else
if ((_object^.flags and OBJ_COLORED)=0) then
begin
find_space:=VMFS_ANY_SPACE;
end;
end;
if ((find_space shr 8)<>0) then
begin
@ -2123,6 +2144,7 @@ end;
}
function vm_map_growstack(addr:vm_offset_t):Integer;
label
_or,
_out;
var
next_entry, prev_entry:vm_map_entry_t;
@ -2340,12 +2362,15 @@ begin
grow_amount:=addr - stack_entry^.__end;
{ Grow the underlying object if applicable. }
if ((stack_entry^._object=nil) or
vm_object_coalesce(stack_entry^._object,
stack_entry^.offset,
vm_size_t(stack_entry^.__end - stack_entry^.start),
vm_size_t(grow_amount), false)) then
if (stack_entry^._object=nil) then goto _or;
if vm_object_coalesce(stack_entry^._object,
stack_entry^.offset,
vm_size_t(stack_entry^.__end - stack_entry^.start),
vm_size_t(grow_amount), false) then
begin
_or:
map^.size:=map^.size+(addr - stack_entry^.__end);
{ Update the current entry. }
stack_entry^.__end:=addr;

View File

@ -45,7 +45,7 @@ uses
vstat,
vfile,
vfcntl,
vfs_vnode,
vnode,
vfs_subr,
vnode_if;
@ -457,10 +457,13 @@ begin
vp:=fp^.f_vnode;
if (vp^.v_mount<>nil) and ((p_mount(vp^.v_mount)^.mnt_flag and MNT_NOEXEC)<>0) then
maxprot:=VM_PROT_NONE
else
maxprot:=VM_PROT_EXECUTE;
maxprot:=VM_PROT_EXECUTE;
if (vp^.v_mount<>nil) then
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_NOEXEC)<>0) then
begin
maxprot:=VM_PROT_NONE;
end;
if ((fp^.f_flag and FREAD)<>0) then
begin

View File

@ -114,8 +114,11 @@ var
superpage_offset:vm_offset_t;
begin
if (size < NBPDR) then Exit;
//if (_object<>nil) and ((_object^.flags and OBJ_COLORED)<>0) then
//if (_object<>nil) then
//if ((_object^.flags and OBJ_COLORED)<>0) then
//begin
// offset:=offset+ptoa(_object^.pg_color);
//end;
superpage_offset:=offset and PDRMASK;
if (size - ((NBPDR - superpage_offset) and PDRMASK) < NBPDR) or
((addr^ and PDRMASK)=superpage_offset) then

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,117 +0,0 @@
/*
***********************************************************************************************************************
*
* Copyright (c) 2015-2021 Advanced Micro Devices, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************************************************************************/
#ifndef PM4_IT_OPCODES_H
#define PM4_IT_OPCODES_H
enum IT_OpCodeType {
IT_NOP = 0x10,
IT_SET_BASE = 0x11,
IT_CLEAR_STATE = 0x12,
IT_INDEX_BUFFER_SIZE = 0x13,
IT_DISPATCH_DIRECT = 0x15,
IT_DISPATCH_INDIRECT = 0x16,
IT_ATOMIC_GDS = 0x1D,
IT_ATOMIC = 0x1E,
IT_OCCLUSION_QUERY = 0x1F,
IT_SET_PREDICATION = 0x20,
IT_REG_RMW = 0x21,
IT_COND_EXEC = 0x22,
IT_PRED_EXEC = 0x23,
IT_DRAW_INDIRECT = 0x24,
IT_DRAW_INDEX_INDIRECT = 0x25,
IT_INDEX_BASE = 0x26,
IT_DRAW_INDEX_2 = 0x27,
IT_CONTEXT_CONTROL = 0x28,
IT_INDEX_TYPE = 0x2A,
IT_DRAW_INDIRECT_MULTI = 0x2C,
IT_DRAW_INDEX_AUTO = 0x2D,
IT_NUM_INSTANCES = 0x2F,
IT_DRAW_INDEX_MULTI_AUTO = 0x30,
IT_INDIRECT_BUFFER_CNST = 0x33,
IT_STRMOUT_BUFFER_UPDATE = 0x34,
IT_DRAW_INDEX_OFFSET_2 = 0x35,
IT_WRITE_DATA = 0x37,
IT_DRAW_INDEX_INDIRECT_MULTI = 0x38,
IT_MEM_SEMAPHORE = 0x39,
IT_COPY_DW__SI__CI = 0x3B,
IT_WAIT_REG_MEM = 0x3C,
IT_INDIRECT_BUFFER = 0x3F,
IT_COND_INDIRECT_BUFFER = 0x3F,
IT_COPY_DATA = 0x40,
IT_CP_DMA = 0x41,
IT_PFP_SYNC_ME = 0x42,
IT_SURFACE_SYNC = 0x43,
IT_COND_WRITE = 0x45,
IT_EVENT_WRITE = 0x46,
IT_EVENT_WRITE_EOP = 0x47,
IT_EVENT_WRITE_EOS = 0x48,
IT_PREAMBLE_CNTL = 0x4A,
IT_CONTEXT_REG_RMW = 0x51,
IT_LOAD_SH_REG = 0x5F,
IT_LOAD_CONFIG_REG = 0x60,
IT_LOAD_CONTEXT_REG = 0x61,
IT_SET_CONFIG_REG = 0x68,
IT_SET_CONTEXT_REG = 0x69,
IT_SET_CONTEXT_REG_INDIRECT = 0x73,
IT_SET_SH_REG = 0x76,
IT_SET_SH_REG_OFFSET = 0x77,
IT_SCRATCH_RAM_WRITE = 0x7D,
IT_SCRATCH_RAM_READ = 0x7E,
IT_LOAD_CONST_RAM = 0x80,
IT_WRITE_CONST_RAM = 0x81,
IT_DUMP_CONST_RAM = 0x83,
IT_INCREMENT_CE_COUNTER = 0x84,
IT_INCREMENT_DE_COUNTER = 0x85,
IT_WAIT_ON_CE_COUNTER = 0x86,
IT_WAIT_ON_DE_COUNTER__SI = 0x87,
IT_WAIT_ON_DE_COUNTER_DIFF = 0x88,
IT_SWITCH_BUFFER = 0x8B,
IT_DRAW_PREAMBLE__CI__VI = 0x36,
IT_RELEASE_MEM__CI__VI = 0x49,
IT_DMA_DATA__CI__VI = 0x50,
IT_ACQUIRE_MEM__CI__VI = 0x58,
IT_REWIND__CI__VI = 0x59,
IT_LOAD_UCONFIG_REG__CI__VI = 0x5E,
IT_SET_QUEUE_REG__CI__VI = 0x78,
IT_SET_UCONFIG_REG__CI__VI = 0x79,
IT_INDEX_ATTRIBUTES_INDIRECT__CI__VI = 0x91,
IT_SET_SH_REG_INDEX__CI__VI = 0x9B,
IT_SET_RESOURCES__CI__VI = 0xA0,
IT_MAP_PROCESS__CI__VI = 0xA1,
IT_MAP_QUEUES__CI__VI = 0xA2,
IT_UNMAP_QUEUES__CI__VI = 0xA3,
IT_QUERY_STATUS__CI__VI = 0xA4,
IT_RUN_LIST__CI__VI = 0xA5,
IT_LOAD_SH_REG_INDEX__VI = 0x63,
IT_LOAD_CONTEXT_REG_INDEX__VI = 0x9F,
IT_DUMP_CONST_RAM_OFFSET__VI = 0x9E,
};
#define PM4_TYPE_0 0
#define PM4_TYPE_2 2
#define PM4_TYPE_3 3
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -181,6 +181,9 @@ var
S,Name:RawByteString;
pre,post:RawByteString;
releflags:RawByteString;
vpp_offset:RawByteString;
rele:ptruint;
F:THandle;
@ -189,6 +192,7 @@ var
state:Integer;
links,maxlen:SizeUInt;
vpnum:Integer;
begin
EnumList:=TStringList.Create;
@ -258,12 +262,13 @@ begin
end;
1:begin //value
rele:=0;
repeat
case Name of
'IN':;
'OUT':;
'INOUT':;
'WILLRELE':;
'WILLRELE':rele:=1;
'struct':;
'const':;
else
@ -304,7 +309,7 @@ begin
if (Length(S)>Enum.namelen) then Enum.namelen:=Length(S);
Enum.AddPair(S,Name);
Enum.AddPair(S,Name,TObject(rele));
Writeln(S,':',Name);
end;
end;
@ -315,14 +320,18 @@ begin
F:=FileCreate(ChangeFileExt(fname,'.pas'));
S:='unit '+ChangeFileExt(ExtractFileName(fname),'')+';'#13#10#13#10+
'interface'#13#10#13#10+
'{$mode objfpc}{$H+}'#13#10+
'{$CALLING SysV_ABI_CDecl}'#13#10#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:='{This file is automatically generated by "vop_generator"}'#13#10;
S:=S+#13#10;
S:=S+'unit '+ChangeFileExt(ExtractFileName(fname),'')+';'#13#10;
S:=S+#13#10;
S:=S+'interface'#13#10;
S:=S+#13#10;
S:=S+'{$mode objfpc}{$H+}'#13#10;
S:=S+'{$CALLING SysV_ABI_CDecl}'#13#10;
S:=S+#13#10;
S:='uses'#13#10;
S:=S+' vfs_vnode,'#13#10;
S:=S+'uses'#13#10;
S:=S+' vnode,'#13#10;
S:=S+' vnamei,'#13#10;
S:=S+' vfile,'#13#10;
S:=S+' vuio,'#13#10;
@ -330,9 +339,8 @@ begin
S:=S+' vfcntl,'#13#10;
S:=S+' vsocketvar;'#13#10;
S:=S+#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:='type'#13#10;
S:=S+'type'#13#10;
S:=S+' PPPtrUint =^PPtrUint;'#13#10;
S:=S+' pp_bufobj =Pointer;'#13#10;
S:=S+' daddr_t =PtrUint;'#13#10;
@ -355,21 +363,22 @@ begin
Enum:=TEnum(EnumList.Objects[i]);
S:=' p_'+Enum.name+'_args=^'+Enum.name+'_args;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:=' '+Enum.name+'_args=record'#13#10;
S:=S+' '+Enum.name+'_args=record'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
if (Length(Enum.name)>maxlen) then maxlen:=Length(Enum.name);
if Length('gen')>Enum.namelen then Enum.namelen:=Length('gen');
S:=' a_gen'+Space(Enum.namelen-Length('gen'))+':p_vnodeop_desc;'#13#10;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=' a_'+Name+Space(Enum.namelen-Length(Name))+':'+Enum.ValueFromIndex[x]+';'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:=S+' a_'+Name+Space(Enum.namelen-Length(Name))+':'+Enum.ValueFromIndex[x]+';'#13#10;
end;
S:=' end;'#13#10#13#10;
S:=S+' end;'#13#10#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
@ -386,16 +395,16 @@ begin
FileWrite(F,Pchar(S)^,Length(S));
//list
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
//For i:=0 to EnumList.Count-1 do
//begin
// Enum:=TEnum(EnumList.Objects[i]);
//
// S:='//'+Enum.name+Space(maxlen-Length(Enum.name))+':Pointer;'#13#10;
// FileWrite(F,Pchar(S)^,Length(S));
//end;
S:='//'+Enum.name+Space(maxlen-Length(Enum.name))+':Pointer;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//S:=#13#10;
//FileWrite(F,Pchar(S)^,Length(S));
//functions header
For i:=0 to EnumList.Count-1 do
@ -405,7 +414,7 @@ begin
Name:=FixFuncName(Enum.name);
Name:=Upcase(Name);
S:='function '+Name+'(';
S:='function '+Name+Space(maxlen-Length(Name))+'(';
FileWrite(F,Pchar(S)^,Length(S));
For x:=0 to Enum.Count-1 do
@ -423,9 +432,166 @@ begin
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10'implementation'#13#10#13#10;
//const
S:=#13#10'const'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//vp_offsets
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
S:=' '+Enum.name+'_vp_offsets'+Space(maxlen-Length(Enum.name))+':array[0..';
//calc count
vpnum:=0;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
Inc(vpnum);
end;
end;
Assert(vpnum<>0);
S:=S+IntToStr(vpnum)+'] of Byte=(';
//offsets
vpnum:=0;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
if (vpnum<>0) then
begin
S:=S+',';
end;
Name:=Enum.Names[x];
Name:='a_'+Name;
S:=S+'Byte(ptrint(@p_'+Enum.name+'_args(nil)^.'+Name+'))';
Inc(vpnum);
end;
end;
S:=S+',Byte(-1));'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
S:=S+' vop_default_desc:t_vnodeop_desc=('#13#10;
S:=S+' vdesc_name :''default'';'#13#10;
S:=S+' vdesc_call :nil;'#13#10;
S:=S+' vdesc_vp_offsets :nil;'#13#10;
S:=S+' vdesc_flags :0;'#13#10;
S:=S+' vdesc_vpp_offset :-1;'#13#10;
S:=S+' );'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//vnodeop_desc
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
//releflags
vpnum:=0;
releflags:='';
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
if (Enum.Objects[x]<>nil) then //rele
begin
if (releflags<>'') then
begin
releflags:=releflags+' or ';
end;
releflags:=releflags+'VDESC_VP'+IntToStr(vpnum)+'_WILLRELE';
end;
Inc(vpnum);
end;
end;
//vppwillrele,vpp_offset
vpp_offset:='';
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='pp_vnode') then
begin
if (vpp_offset='') then
begin
Name:=Enum.Names[x];
Name:='a_'+Name;
vpp_offset:='Integer(ptrint(@p_'+Enum.name+'_args(nil)^.'+Name+'))';
end;
if (Enum.Objects[x]<>nil) then //rele
begin
if (releflags<>'') then
begin
releflags:=releflags+' or ';
end;
releflags:=releflags+'VDESC_VPP_WILLRELE';
Break;
end;
end;
end;
if (releflags='') then releflags:='0';
if (vpp_offset='') then vpp_offset:='-1';
S:=#13#10;
S:=S+' '+Enum.name+'_desc:t_vnodeop_desc=('#13#10;
S:=S+' vdesc_name :'''+Enum.name+''';'#13#10;
S:=S+' vdesc_call :@p_vop_vector(nil)^.'+Enum.name+';'#13#10;
S:=S+' vdesc_vp_offsets :@'+Enum.name+'_vp_offsets;'#13#10;
S:=S+' vdesc_flags :'+releflags+';'#13#10;
S:=S+' vdesc_vpp_offset :'+vpp_offset+';'#13#10;
S:=S+' );'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
S:=S+'implementation'#13#10;
S:=S+#13#10;
S:=S+'uses'#13#10;
S:=S+' vfs_subr;'#13#10#13#10;
S:=S+' errno,'#13#10;
S:=S+' vfs_subr;'#13#10;
S:=S+#13#10;
S:=S+'function get_vp_cb(vp:p_vnode;offset:Pointer):Pointer; inline;'#13#10;
S:=S+'var'#13#10;
S:=S+' v:p_vop_vector;'#13#10;
S:=S+' p:Pointer;'#13#10;
S:=S+'begin'#13#10;
S:=S+' Result:=nil;'#13#10;
S:=S+' if (vp=nil) then Exit;'#13#10;
S:=S+' v:=vp^.v_op;'#13#10;
S:=S+' while (v<>nil) do'#13#10;
S:=S+' begin'#13#10;
S:=S+' p:=PPointer(Pointer(v)+ptrint(offset))^;'#13#10;
S:=S+' if (p<>nil) then'#13#10;
S:=S+' begin'#13#10;
S:=S+' Exit(p);'#13#10;
S:=S+' end;'#13#10;
S:=S+' p:=v^.vop_bypass;'#13#10;
S:=S+' if (p<>nil) then'#13#10;
S:=S+' begin'#13#10;
S:=S+' Exit(p);'#13#10;
S:=S+' end;'#13#10;
S:=S+' v:=v^.vop_default;'#13#10;
S:=S+' end;'#13#10;
S:=S+'end;'#13#10;
S:=S+#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//functions body
@ -457,17 +623,15 @@ begin
//var
S:='var'#13#10;
S:=S+' v:p_vop_vector;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//var
if (Enum.Count>1) then
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=' a:'+Enum.name+'_args;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:=S+' osize,ooffset:Int64;'#13#10;
end;
S:=' s:Boolean;'#13#10;
S:=S+' c:Pointer;'#13#10;
S:=S+' a:'+Enum.name+'_args;'#13#10;
S:=S+' s:Boolean;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//body
@ -477,62 +641,51 @@ begin
Name:=FixFuncName(Enum.name);
Name:=Upcase(Name);
S:=' v:='+FixFieldName(Enum.Names[0])+'^.v_op;'#13#10;
S:=S+' while (v<>nil) do'#13#10;
S:=S+' begin'#13#10;
S:=S+' if (v^.'+Enum.name+'<>nil) or (v^.vop_bypass<>nil) then Break;'#13#10;
S:=S+' v:=v^.vop_default;'#13#10;
S:=S+' end;'#13#10;
S:=S+' Assert(v<>nil,'+''''+Name+''''+');'#13#10;
S:=' c:=get_vp_cb('+FixFieldName(Enum.Names[0])+','+Enum.name+'_desc.vdesc_call);'#13#10;
S:=S+' Assert(c<>nil,'+''''+Name+''''+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
if (Enum.Count>1) then
begin
//set val
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
//set val
S:=' a.a_gen'+Space(Enum.namelen-Length('gen'))+':=@'+Enum.name+'_desc;'#13#10;
S:=' a.a_'+Name+Space(Enum.namelen-Length(Name))+':='+FixFieldName(Name)+';'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=S+' a.a_'+Name+Space(Enum.namelen-Length(Name))+':='+FixFieldName(Name)+';'#13#10;
end;
if (Enum.Count>1) then
begin
Name:='a';
end else
begin
Name:=FixFieldName(Enum.Names[0]);
end;
FileWrite(F,Pchar(S)^,Length(S));
//pre
if (Enum.pre<>'') then
begin
S:=' '+Enum.pre+'(@'+Name+');'#13#10;
S:=' '+Enum.pre+'(@'+'a';
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=S+',osize,ooffset';
end;
S:=S+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=' s:=VFS_PROLOGUE('+FixFieldName(Enum.Names[0])+'^.v_mount);'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//call
S:=' if (v^.'+Enum.name+'<>nil) then'#13#10;
S:=S+' begin'#13#10;
S:=S+' Result:='+Enum.name+'_t(v^.'+Enum.name+')(@'+Name+');'#13#10;
S:=S+' end else'#13#10;
S:=S+' begin'#13#10;
S:=S+' Result:='+Enum.name+'_t(v^.vop_bypass)(@'+Name+');'#13#10;
S:=S+' end;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
S:=S+' Result:='+Enum.name+'_t(c)(@a);'#13#10;
S:=' VFS_EPILOGUE(s);'#13#10;
S:=S+' VFS_EPILOGUE(s);'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//post
if (Enum.post<>'') then
begin
S:=' '+Enum.post+'(@'+Name+',Result);'#13#10;
S:=' '+Enum.post+'(@a,Result';
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=S+',osize,ooffset';
end;
S:=S+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;