FPPS4/sys/vfs/vmount.pas

627 lines
20 KiB
Plaintext

unit vmount;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
kern_param,
time,
sys_event,
kern_mtx,
//kern_synch,
signal,
vnode;
const
STATFS_VERSION=$20030518; // current version number
//User specifiable flags, stored in mnt_flag.
MNT_RDONLY =$0000000000000001; // read only filesystem
MNT_SYNCHRONOUS=$0000000000000002; // fs written synchronously
MNT_NOEXEC =$0000000000000004; // can't exec from filesystem
MNT_NOSUID =$0000000000000008; // don't honor setuid fs bits
MNT_NFS4ACLS =$0000000000000010; // enable NFS version 4 ACLs
MNT_UNION =$0000000000000020; // union with underlying fs
MNT_ASYNC =$0000000000000040; // fs written asynchronously
MNT_SUIDDIR =$0000000000100000; // special SUID dir handling
MNT_SOFTDEP =$0000000000200000; // using soft updates
MNT_NOSYMFOLLOW=$0000000000400000; // do not follow symlinks
MNT_GJOURNAL =$0000000002000000; // GEOM journal support enabled
MNT_MULTILABEL =$0000000004000000; // MAC support for objects
MNT_ACLS =$0000000008000000; // ACL support enabled
MNT_NOATIME =$0000000010000000; // dont update file access time
MNT_NOCLUSTERR =$0000000040000000; // disable cluster read
MNT_NOCLUSTERW =$0000000080000000; // disable cluster write
MNT_SUJ =$0000000100000000; // using journaled soft updates
//NFS export related mount flags.
MNT_EXRDONLY =$0000000000000080; // exported read only
MNT_EXPORTED =$0000000000000100; // filesystem is exported
MNT_DEFEXPORTED=$0000000000000200; // exported to the world
MNT_EXPORTANON =$0000000000000400; // anon uid mapping for all
MNT_EXKERB =$0000000000000800; // exported with Kerberos
MNT_EXPUBLIC =$0000000020000000; // public export (WebNFS)
{
* Flags set by internal operations,
* but visible to the user.
* XXX some of these are not quite right.. (I've never seen the root flag set)
}
MNT_LOCAL =$0000000000001000; // filesystem is stored locally
MNT_QUOTA =$0000000000002000; // quotas are enabled on fs
MNT_ROOTFS=$0000000000004000; // identifies the root fs
MNT_USER =$0000000000008000; // mounted by a user
MNT_IGNORE=$0000000000800000; // do not show entry in df
{
* External filesystem command modifier flags.
* Unmount can use the MNT_FORCE flag.
* XXX: These are not STATES and really should be somewhere else.
* XXX: MNT_BYFSID collides with MNT_ACLS, but because MNT_ACLS is only used for
* mount(2) and MNT_BYFSID is only used for unmount(2) it's harmless.
}
MNT_UPDATE =$0000000000010000; // not real mount, just update
MNT_DELEXPORT=$0000000000020000; // delete export host lists
MNT_RELOAD =$0000000000040000; // reload filesystem data
MNT_FORCE =$0000000000080000; // force unmount or readonly
MNT_SNAPSHOT =$0000000001000000; // snapshot the filesystem
MNT_BYFSID =$0000000008000000; // specify filesystem by ID.
MNT_VISFLAGMASK=(MNT_RDONLY or MNT_SYNCHRONOUS or MNT_NOEXEC or
MNT_NOSUID or MNT_UNION or MNT_SUJ or
MNT_ASYNC or MNT_EXRDONLY or MNT_EXPORTED or
MNT_DEFEXPORTED or MNT_EXPORTANON or MNT_EXKERB or
MNT_LOCAL or MNT_USER or MNT_QUOTA or
MNT_ROOTFS or MNT_NOATIME or MNT_NOCLUSTERR or
MNT_NOCLUSTERW or MNT_SUIDDIR or MNT_SOFTDEP or
MNT_IGNORE or MNT_EXPUBLIC or MNT_NOSYMFOLLOW or
MNT_GJOURNAL or MNT_MULTILABEL or MNT_ACLS or
MNT_NFS4ACLS);
MNT_UPDATEMASK=(MNT_NOSUID or MNT_NOEXEC or
MNT_SYNCHRONOUS or MNT_UNION or MNT_ASYNC or
MNT_NOATIME or
MNT_NOSYMFOLLOW or MNT_IGNORE or
MNT_NOCLUSTERR or MNT_NOCLUSTERW or MNT_SUIDDIR or
MNT_ACLS or MNT_USER or MNT_NFS4ACLS);
{
* Internal filesystem control flags stored in mnt_kern_flag.
*
* MNTK_UNMOUNT locks the mount entry so that name lookup cannot proceed
* past the mount point. This keeps the subtree stable during mounts
* and unmounts.
*
* MNTK_UNMOUNTF permits filesystems to detect a forced unmount while
* dounmount() is still waiting to lock the mountpoint. This allows
* the filesystem to cancel operations that might otherwise deadlock
* with the unmount attempt (used by NFS).
*
* MNTK_NOINSMNTQ is strict subset of MNTK_UNMOUNT. They are separated
* to allow for failed unmount attempt to restore the syncer vnode for
* the mount.
}
MNTK_UNMOUNTF =$00000001; // forced unmount in progress
MNTK_ASYNC =$00000002; // filtered async flag
MNTK_SOFTDEP =$00000004; // async disabled by softdep
MNTK_NOINSMNTQ =$00000008; // insmntque is not allowed
MNTK_DRAINING =$00000010; // lock draining is happening
MNTK_REFEXPIRE =$00000020; // refcount expiring is happening
MNTK_EXTENDED_SHARED =$00000040; // Allow shared locking for more ops
MNTK_SHARED_WRITES =$00000080; // Allow shared locking for writes
MNTK_NO_IOPF =$00000100; { Disallow page faults during reads
and writes. Filesystem shall properly
handle i/o state on EFAULT.}
MNTK_VGONE_UPPER =$00000200;
MNTK_VGONE_WAITER =$00000400;
MNTK_LOOKUP_EXCL_DOTDOT=$00000800;
MNTK_MARKER =$00001000;
MNTK_UNMAPPED_BUFS =$00002000;
MNTK_NOASYNC =$00800000; // disable async
MNTK_UNMOUNT =$01000000; // unmount in progress
MNTK_MWAIT =$02000000; // waiting for unmount to finish
MNTK_SUSPEND =$08000000; // request write suspension
MNTK_SUSPEND2 =$04000000; // block secondary writes
MNTK_SUSPENDED =$10000000; // write operations are suspended
MNTK_MPSAFE =$20000000; // Filesystem is MPSAFE.
MNTK_LOOKUP_SHARED =$40000000; // FS supports shared lock lookups
MNTK_NOKNOTE =$80000000; // Don't send KNOTEs from VOP hooks
{
* Sysctl CTL_VFS definitions.
*
* Second level identifier specifies which filesystem. Second level
* identifier VFS_VFSCONF returns information about all filesystems.
* Second level identifier VFS_GENERIC is non-terminal.
}
VFS_VFSCONF=0; // get configured filesystems
VFS_GENERIC=0; // generic filesystem information
{
* Third level identifiers for VFS_GENERIC are given below; third
* level identifiers for specific filesystems are given in their
* mount specific header files.
}
VFS_MAXTYPENUM=1; // int: highest defined filesystem type
VFS_CONF =2; // struct: vfsconf for filesystem given as next argument
{
* Flags for various system call interfaces.
*
* waitfor flags to vfs_sync() and getfsstat()
}
MNT_WAIT =1; // synchronously wait for I/O to complete
MNT_NOWAIT =2; // start all I/O, but do not wait for it
MNT_LAZY =3; // push data not written by filesystem syncer
MNT_SUSPEND=4; // Suspend file system after sync
{
* vfs_busy specific flags and mask.
}
MBF_NOWAIT =$01;
MBF_MNTLSTLOCK=$02;
MBF_MASK =(MBF_NOWAIT or MBF_MNTLSTLOCK);
VFCF_STATIC =$00010000; // statically compiled into kernel
VFCF_NETWORK =$00020000; // may get data over the network
VFCF_READONLY =$00040000; // writes are not implemented
VFCF_SYNTHETIC =$00080000; // data does not represent real files
VFCF_LOOPBACK =$00100000; // aliases some other mounted FS
VFCF_UNICODE =$00200000; // stores file names as Unicode
VFCF_JAIL =$00400000; // can be mounted from within a jail
VFCF_DELEGADMIN=$00800000; // supports delegated administration
VFCF_SBDRY =$01000000; // defer stop requests
{ vfsquery flags }
VQ_NOTRESP =$0001; { server down }
VQ_NEEDAUTH =$0002; { server bad auth }
VQ_LOWDISK =$0004; { we're low on space }
VQ_MOUNT =$0008; { new filesystem arrived }
VQ_UNMOUNT =$0010; { filesystem has left }
VQ_DEAD =$0020; { filesystem is dead, needs force unmount }
VQ_ASSIST =$0040; { filesystem needs assistance from external program }
VQ_NOTRESPLOCK=$0080; { server lockd down }
type
p_fsid=^fsid_t;
fsid_t=packed record // filesystem id type
val:array[0..1] of Integer;
end;
{
* File identifier.
* These are unique per filesystem on a single machine.
}
p_fid=^fid;
fid=packed record
fid_len :Word; // length of data in bytes
fid_data0:Word; // force longword alignment
fid_data :array[0..MAXFIDSZ-1] of Byte; // data (variable length)
end;
vnodelst=TAILQ_HEAD; //vnode
pp_vfsoptlist=^p_vfsoptlist;
p_vfsoptlist=^vfsoptlist;
vfsoptlist=TAILQ_HEAD; //vfsopt
// Mount options list
p_vfsopt=^vfsopt;
vfsopt=packed record
link :TAILQ_ENTRY; //vfsopt
name :PChar;
value:Pointer;
len :Integer;
pos :Integer;
seen :Integer;
end;
{
* Operations supported on mounted filesystem.
}
PPInteger=^PInteger;
pp_mount=^p_mount;
p_mount=^t_mount;
pp_statfs=^p_statfs;
p_statfs=^t_statfs;
p_vfsconf=^vfsconf;
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,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;
vfs_fhtovp_t =function (mp:p_mount;fhp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
vfs_checkexp_t =function (mp:p_mount;nam:Pointer;extflagsp,numsecflavors:Pinteger;secflavors:PPInteger):Integer;
vfs_init_t =function (cf:p_vfsconf):Integer;
vfs_uninit_t =function (cf:p_vfsconf):Integer;
vfs_extattrctl_t =function (mp:p_mount;cmd:Integer;filename_vp:p_vnode;attrnamespace:Integer;attrname:PChar):Integer;
vfs_mount_t =function (mp:p_mount):Integer;
vfs_sysctl_t =function (mp:p_mount;op:Integer;req:Pointer):Integer;
vfs_susp_clean_t =procedure(mp:p_mount);
vfs_notify_lowervp_t=procedure(mp:p_mount;lowervp:p_vnode);
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;
end;
t_fsnamelen=array[0..MFSNAMELEN-1] of AnsiChar;
t_mname =array[0..MNAMELEN-1] of AnsiChar;
{
* Filesystem configuration information. One of these exists for each
* type of filesystem supported by the kernel. These are searched at
* mount time to identify the requested filesystem.
*
* XXX: Never change the first two arguments!
}
p_vfsoptdecl=Pointer;
vfsconf=record
vfc_version :DWORD ; // ABI version number
vfc_name :t_fsnamelen ; // 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
vfc_flags :Integer ; // permanent flags
vfc_opts :p_vfsoptdecl; // mount options
vfc_list :TAILQ_ENTRY ; // list of vfscons
end;
t_statfs=packed record
f_version :DWORD; // structure version number
f_type :DWORD; // type of filesystem
f_flags :QWORD; // copy of mount exported flags
f_bsize :QWORD; // filesystem fragment size
f_iosize :QWORD; // optimal transfer block size
f_blocks :QWORD; // total data blocks in filesystem
f_bfree :QWORD; // free blocks in filesystem
f_bavail :Int64; // free blocks avail to non-superuser
f_files :QWORD; // total file nodes in filesystem
f_ffree :Int64; // free nodes avail to non-superuser
f_syncwrites :QWORD; // count of sync writes since mount
f_asyncwrites:QWORD; // count of async writes since mount
f_syncreads :QWORD; // count of sync reads since mount
f_asyncreads :QWORD; // count of async reads since mount
f_spare:array[0..9] of QWORD; // unused spare
f_namemax :DWORD; // maximum filename length
f_owner :DWORD; // user that mounted the filesystem
f_fsid :fsid_t; // filesystem id
f_charspare :array[0..79] of AnsiChar; // spare string space
f_fstypename :t_fsnamelen; // filesystem type name
f_mntfromname:t_mname; // mounted filesystem
f_mntonname :t_mname; // directory on which mounted
end;
{$IF sizeof(t_statfs)<>472}{$STOP sizeof(t_statfs)<>472}{$ENDIF}
{
* Structure per mounted filesystem. Each mounted filesystem has an
* array of operations and an instance record. The filesystems are
* put on a doubly linked list.
*
* Lock reference:
* m - mountlist_mtx
* i - interlock
* v - vnode freelist mutex
*
* Unmarked fields are considered stable as long as a ref is held.
*
}
t_mount=packed record
mnt_mtx :mtx ;// mount structure interlock
mnt_gen :Integer ;// mount generation
mnt_list :TAILQ_ENTRY ;// (m) mount list
mnt_op :p_vfsops ;// operations on fs
mnt_vfc :p_vfsconf ;// configuration info
mnt_vnodecovered :p_vnode ;// vnode we mounted on
mnt_syncer :p_vnode ;// syncer vnode
mnt_ref :Integer ;// (i) Reference count
mnt_nvnodelist :vnodelst ;// (i) list of vnodes
mnt_nvnodelistsize :Integer ;// (i) # of vnodes
mnt_activevnodelist :vnodelst ;// (v) list of active vnodes
mnt_activevnodelistsize:Integer ;// (v) # of active vnodes
mnt_writeopcount :Integer ;// (i) write syscalls pending
mnt_kern_flag :Integer ;// (i) kernel only flags
mnt_flag :QWORD ;// (i) flags shared with user
mnt_pad_noasync :DWORD ;
mnt_opt :p_vfsoptlist;// current mount options
mnt_optnew :p_vfsoptlist;// new options passed to fs
mnt_maxsymlinklen :Integer ;// max size of short symlink
mnt_stat :t_statfs ;// cache of filesystem stats
mnt_data :Pointer ;// private data
mnt_time :time_t ;// last time written
mnt_iosize_max :Integer ;// max size for clusters, etc
//mnt_export :p_netexport ;// export list
//mnt_label :p_label ;// MAC label for the fs
mnt_hashseed :DWORD ;// Random seed for vfs_hash
mnt_lockref :Integer ;// (i) Lock reference count
mnt_secondary_writes :Integer ;// (i) # of secondary writes
mnt_secondary_accwrites:Integer ;// (i) secondary wr. starts
mnt_susp_owner :Pointer ;// (i) thread owning suspension
mnt_explock :mtx ;// vfs_export walkers lock
mnt_upper_link :TAILQ_ENTRY ;// (m) we in the all uppers
mnt_uppers :TAILQ_HEAD ;// (m) upper mounts over us
end;
//Generic file handle
fhandle_t=packed record
fh_fsid:fsid_t; // Filesystem id of mount point
fh_fid :fid // Filesys specific id
end;
const
VFS_NOTIFY_UPPER_RECLAIM=1;
VFS_NOTIFY_UPPER_UNLINK =2;
VFS_VERSION=$19660120;
var
mountlist_mtx:mtx;
mountlist:TAILQ_HEAD=(tqh_first:nil;tqh_last:@mountlist.tqh_first);
VFS_Giant:mtx;
function MNT_SHARED_WRITES(mp:p_mount):Boolean; inline;
procedure MNT_ILOCK(mp:p_mount); inline;
function MNT_ITRYLOCK(mp:p_mount):Boolean; inline;
procedure MNT_IUNLOCK(mp:p_mount); inline;
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;
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;
procedure VFS_EPILOGUE(_enable_stops:Boolean); inline;
function VFS_MOUNT(mp:p_mount):Integer;
function VFS_UNMOUNT(mp:p_mount;FORCE:Integer):Integer;
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;
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);
procedure vmountinit; //SYSINIT
implementation
//
procedure wakeup(ident:Pointer); external;
//
function MNT_SHARED_WRITES(mp:p_mount):Boolean; inline;
begin
if (mp<>nil) then
begin
Result:=((mp^.mnt_kern_flag and MNTK_SHARED_WRITES)<>0);
end else
begin
Result:=False;
end;
end;
procedure MNT_ILOCK(mp:p_mount); inline;
begin
mtx_lock(mp^.mnt_mtx);
end;
function MNT_ITRYLOCK(mp:p_mount):Boolean; inline;
begin
Result:=mtx_trylock(mp^.mnt_mtx);
end;
procedure MNT_IUNLOCK(mp:p_mount); inline;
begin
mtx_unlock(mp^.mnt_mtx);
end;
function MNT_MTX(mp:p_mount):p_mtx; inline;
begin
Result:=@mp^.mnt_mtx;
end;
procedure MNT_REF(mp:p_mount); inline;
begin
Assert(mp^.mnt_ref>=0);
System.InterlockedIncrement(mp^.mnt_ref);
end;
procedure MNT_REL(mp:p_mount); inline;
begin
Assert(mp^.mnt_ref>0);
if (System.InterlockedDecrement(mp^.mnt_ref)=0) then
begin
wakeup(mp)
end;
end;
function VFS_NEEDSGIANT(mp:p_mount):Boolean;
begin
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; public;
begin
if VFS_NEEDSGIANT(mp) then
begin
mtx_lock(VFS_Giant);
Result:=1;
end else
Result:=0;
end;
procedure VFS_UNLOCK_GIANT(locked:Integer);
begin
if (locked<>0) then
mtx_unlock(VFS_Giant);
end;
procedure VFS_ASSERT_GIANT(mp:p_mount);
begin
if VFS_NEEDSGIANT(mp) then
mtx_assert(VFS_Giant);
end;
function VFS_PROLOGUE(mp:p_mount):Boolean; public;
begin
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); public;
begin
if _enable_stops then sigallowstop;
end;
function VFS_MOUNT(mp:p_mount):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_mount(mp);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_UNMOUNT(mp:p_mount;FORCE:Integer):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_unmount(mp,FORCE);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_ROOT(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_root(mp,flags,vpp);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_STATFS(mp:p_mount;sbp:p_statfs):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_statfs(mp,@mp^.mnt_stat);
if (sbp<>@mp^.mnt_stat) then
begin
sbp^:=mp^.mnt_stat;
end;
VFS_EPILOGUE(_enable_stops);
end;
function VFS_SYNC(mp:p_mount;WAIT:Integer):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_sync(mp,WAIT);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_VGET(mp:p_mount;ino:QWORD;flags:Integer;vpp:pp_vnode):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_vget(mp,ino,flags,vpp);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_QUOTACTL(mp:p_mount;c,u:Integer;a:Pointer):Integer;
var
_enable_stops:Boolean;
begin
_enable_stops:=VFS_PROLOGUE(MP);
Result:=mp^.mnt_op^.vfs_quotactl(mp,c,u,a);
VFS_EPILOGUE(_enable_stops);
end;
function VFS_FHTOVP(mp:p_mount;fidp:p_fid;flags:Integer;vpp:pp_vnode):Integer;
var
_enable_stops:Boolean;
begin
_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);
begin
if ((vp^.v_vflag and VV_NOKNOTE)=0) then
VN_KNOTE(vp, hint, KNF_LISTLOCKED);
end;
procedure VFS_KNOTE_UNLOCKED(vp:p_vnode;hint:Integer);
begin
if ((vp^.v_vflag and VV_NOKNOTE)=0) then
VN_KNOTE(vp, hint, 0);
end;
procedure vmountinit;
begin
mtx_init(mountlist_mtx,'mountlist');
mtx_init(VFS_Giant ,'VFS_Giant');
end;
end.