mirror of https://github.com/red-prig/fpPS4.git
This commit is contained in:
parent
ed32b44e8d
commit
5818cc3403
|
@ -24,6 +24,7 @@ procedure sx_xlock(p:p_sx);
|
|||
procedure sx_sunlock(p:p_sx);
|
||||
procedure sx_xunlock(p:p_sx);
|
||||
procedure sx_unlock(p:p_sx);
|
||||
procedure sx_destroy(p:p_sx);
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -77,5 +78,10 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure sx_destroy(p:p_sx);
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
@ -33,16 +33,10 @@ implementation
|
|||
uses
|
||||
sysutils;
|
||||
|
||||
//#include <sys/cdefs.h>
|
||||
//#include <sys/param.h>
|
||||
//#include <sys/ctype.h>
|
||||
//#include <sys/libkern.h>
|
||||
|
||||
{
|
||||
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
|
||||
* Compares a filename or pathname to a pattern.
|
||||
}
|
||||
|
||||
function fnmatch(pattern,str:pchar;flags:Integer):Integer;
|
||||
label
|
||||
norm;
|
||||
|
|
|
@ -26,8 +26,10 @@ uses
|
|||
vsys_generic,
|
||||
vfs_subr,
|
||||
vfs_lookup,
|
||||
vfs_init,
|
||||
devfs,
|
||||
devfs_devs;
|
||||
devfs_devs,
|
||||
devfs_vfsops;
|
||||
|
||||
//Daemon for a separate thread
|
||||
procedure sys_update;
|
||||
|
@ -35,6 +37,11 @@ begin
|
|||
vnlru_proc;
|
||||
end;
|
||||
|
||||
procedure module_init;
|
||||
begin
|
||||
vfs_register(@devfs_vfsconf);
|
||||
end;
|
||||
|
||||
//Manual order of lazy initialization
|
||||
procedure sys_init;
|
||||
begin
|
||||
|
@ -55,6 +62,7 @@ begin
|
|||
nameiinit;
|
||||
devfs_mtx_init;
|
||||
devfs_devs_init;
|
||||
module_init;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
@ -425,6 +425,10 @@
|
|||
<Filename Value="..\sys_fnmatch.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\devfs\devfs_vfsops.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
|
@ -51,7 +51,8 @@ uses
|
|||
vnode_if,
|
||||
sys_sysinit,
|
||||
sys_fnmatch,
|
||||
devfs;
|
||||
devfs,
|
||||
devfs_vfsops;
|
||||
|
||||
var
|
||||
mtx:umutex;
|
||||
|
|
|
@ -10,20 +10,6 @@ uses
|
|||
devfs,
|
||||
kern_sx;
|
||||
|
||||
//#include <sys/param.h>
|
||||
//#include <sys/systm.h>
|
||||
//#include <sys/conf.h>
|
||||
//#include <sys/kernel.h>
|
||||
//#include <sys/malloc.h>
|
||||
//#include <sys/priv.h>
|
||||
//#include <sys/dirent.h>
|
||||
//#include <sys/ioccom.h>
|
||||
//#include <sys/lock.h>
|
||||
//#include <sys/sx.h>
|
||||
//
|
||||
//#include <fs/devfs/devfs.h>
|
||||
//#include <fs/devfs/devfs_int.h>
|
||||
|
||||
{
|
||||
* Kernel version of devfs_rule.
|
||||
}
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
unit devfs_vfsops;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
vfs_vnode,
|
||||
vmount,
|
||||
devfs,
|
||||
kern_id;
|
||||
|
||||
var
|
||||
devfs_unr:p_id_desc_table;
|
||||
|
||||
function devfs_mount(mp:p_mount):Integer;
|
||||
function devfs_unmount(mp:p_mount;mntflags:Integer):Integer;
|
||||
function devfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
|
||||
function devfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
||||
|
||||
const
|
||||
devfs_opts:array[0..3] of PChar=(
|
||||
'from','export','ruleset',nil
|
||||
);
|
||||
|
||||
_devfs_vfsops:vfsops=(
|
||||
vfs_mount :@devfs_mount;
|
||||
vfs_cmount :nil;
|
||||
vfs_unmount :@devfs_unmount;
|
||||
vfs_root :@devfs_root;
|
||||
vfs_quotactl :nil;
|
||||
vfs_statfs :@devfs_statfs;
|
||||
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:nil;
|
||||
vfs_unlink_lowervp :nil;
|
||||
);
|
||||
|
||||
var
|
||||
//VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC or VFCF_JAIL);
|
||||
devfs_vfsconf:vfsconf=(
|
||||
vfc_version :VFS_VERSION;
|
||||
vfc_name :'devfs';
|
||||
vfc_vfsops :@_devfs_vfsops;
|
||||
vfc_typenum :-1;
|
||||
vfc_refcount:0;
|
||||
vfc_flags :VFCF_SYNTHETIC or VFCF_JAIL;
|
||||
);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
errno,
|
||||
kern_mtx,
|
||||
kern_sx,
|
||||
devfs_devs,
|
||||
devfs_rule,
|
||||
vfs_mount,
|
||||
vfs_subr,
|
||||
vnode_if;
|
||||
|
||||
function new_unrhdr(min,max:Integer):p_id_desc_table;
|
||||
begin
|
||||
Result:=AllocMem(SizeOf(t_id_desc_table));
|
||||
id_table_init(Result,min);
|
||||
Result^.max_key:=max;
|
||||
end;
|
||||
|
||||
function alloc_unr(p:p_id_desc_table):Integer;
|
||||
begin
|
||||
if id_new(p,nil,@Result) then
|
||||
begin
|
||||
//
|
||||
end else
|
||||
begin
|
||||
Result:=-1;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure free_unr(p:p_id_desc_table;i:Integer);
|
||||
begin
|
||||
id_del(p,i,nil);
|
||||
end;
|
||||
|
||||
{
|
||||
* Mount the filesystem
|
||||
}
|
||||
function devfs_mount(mp:p_mount):Integer;
|
||||
var
|
||||
error:Integer;
|
||||
fmp:p_devfs_mount;
|
||||
rvp:p_vnode;
|
||||
//struct thread *td:=curthread;
|
||||
{injail,}rsnum:Integer;
|
||||
begin
|
||||
|
||||
if (devfs_unr=nil) then
|
||||
devfs_unr:=new_unrhdr(0, High(Integer));
|
||||
|
||||
error:=0;
|
||||
|
||||
if ((mp^.mnt_flag and MNT_ROOTFS)<>0) then
|
||||
Exit(EOPNOTSUPP);
|
||||
|
||||
//if (!prison_allow(td^.td_ucred, PR_ALLOW_MOUNT_DEVFS))
|
||||
// Exit(EPERM);
|
||||
|
||||
rsnum:=0;
|
||||
//injail:=jailed(td^.td_ucred);
|
||||
|
||||
if (mp^.mnt_optnew<>nil) then
|
||||
begin
|
||||
if (vfs_filteropt(mp^.mnt_optnew, devfs_opts)<>0) then
|
||||
Exit(EINVAL);
|
||||
|
||||
if (vfs_flagopt(mp^.mnt_optnew, 'export', nil, 0)<>0) then
|
||||
Exit(EOPNOTSUPP);
|
||||
|
||||
if (vfs_getopt(mp^.mnt_optnew, 'ruleset', nil, nil)=0) and
|
||||
((vfs_scanopt(mp^.mnt_optnew, 'ruleset', '%d',[rsnum])<>1) or
|
||||
(rsnum < 0) or
|
||||
(rsnum > 65535)) then
|
||||
begin
|
||||
vfs_mount_error(mp, '%s', ['invalid ruleset specification']);
|
||||
Exit(EINVAL);
|
||||
end;
|
||||
|
||||
//if (injail) and
|
||||
// (rsnum<>0) and
|
||||
// (rsnum<>td^.td_ucred^.cr_prison^.pr_devfs_rsnum) then
|
||||
// Exit(EPERM);
|
||||
end;
|
||||
|
||||
{ jails enforce their ruleset }
|
||||
//if (injail<>0) then
|
||||
// rsnum:=td^.td_ucred^.cr_prison^.pr_devfs_rsnum;
|
||||
|
||||
if ((mp^.mnt_flag and MNT_UPDATE)<>0) then
|
||||
begin
|
||||
if (rsnum<>0) then
|
||||
begin
|
||||
fmp:=mp^.mnt_data;
|
||||
if (fmp<>nil) then
|
||||
begin
|
||||
sx_xlock(@fmp^.dm_lock);
|
||||
devfs_ruleset_set(devfs_rsnum(rsnum), fmp);
|
||||
devfs_ruleset_apply(fmp);
|
||||
sx_xunlock(@fmp^.dm_lock);
|
||||
end;
|
||||
end;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
fmp:=AllocMem(sizeof(t_devfs_mount));
|
||||
fmp^.dm_idx:=alloc_unr(devfs_unr);
|
||||
sx_init(@fmp^.dm_lock, 'devfsmount');
|
||||
fmp^.dm_holdcnt:=1;
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
mp^.mnt_flag:=mp^.mnt_flag or MNT_LOCAL;
|
||||
mp^.mnt_kern_flag:=mp^.mnt_kern_flag or MNTK_MPSAFE or MNTK_LOOKUP_SHARED or MNTK_EXTENDED_SHARED;
|
||||
|
||||
//MAC
|
||||
//mp^.mnt_flag:=mp^.mnt_flag or MNT_MULTILABEL;
|
||||
|
||||
MNT_IUNLOCK(mp);
|
||||
fmp^.dm_mount:=mp;
|
||||
mp^.mnt_data:=fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
fmp^.dm_rootdir:=devfs_vmkdir(fmp, nil, 0, nil, DEVFS_ROOTINO);
|
||||
|
||||
error:=devfs_root(mp, LK_EXCLUSIVE, @rvp);
|
||||
if (error<>0) then
|
||||
begin
|
||||
sx_destroy(@fmp^.dm_lock);
|
||||
free_unr(devfs_unr, fmp^.dm_idx);
|
||||
FreeMem(fmp);
|
||||
Exit(error);
|
||||
end;
|
||||
|
||||
if (rsnum<>0) then
|
||||
begin
|
||||
sx_xlock(@fmp^.dm_lock);
|
||||
devfs_ruleset_set(devfs_rsnum(rsnum), fmp);
|
||||
sx_xunlock(@fmp^.dm_lock);
|
||||
end;
|
||||
|
||||
VOP_UNLOCK(rvp, 0);
|
||||
|
||||
vfs_mountedfrom(mp, 'devfs');
|
||||
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
procedure devfs_unmount_final(fmp:p_devfs_mount);
|
||||
begin
|
||||
sx_destroy(@fmp^.dm_lock);
|
||||
FreeMem(fmp);
|
||||
end;
|
||||
|
||||
function devfs_unmount(mp:p_mount;mntflags:Integer):Integer;
|
||||
var
|
||||
error:Integer;
|
||||
flags:Integer;
|
||||
fmp:p_devfs_mount;
|
||||
hold:Integer;
|
||||
idx:DWORD;
|
||||
begin
|
||||
flags:=0;
|
||||
|
||||
fmp:=VFSTODEVFS(mp);
|
||||
Assert(fmp^.dm_mount<>nil,
|
||||
('devfs_unmount unmounted devfs_mount'));
|
||||
{ There is 1 extra root vnode reference from devfs_mount(). }
|
||||
error:=vflush(mp, 1, flags);
|
||||
if (error<>0) then
|
||||
Exit(error);
|
||||
sx_xlock(@fmp^.dm_lock);
|
||||
devfs_cleanup(fmp);
|
||||
devfs_rules_cleanup(fmp);
|
||||
fmp^.dm_mount:=nil;
|
||||
Inc(fmp^.dm_holdcnt);
|
||||
hold:=fmp^.dm_holdcnt;
|
||||
mp^.mnt_data:=nil;
|
||||
idx:=fmp^.dm_idx;
|
||||
sx_xunlock(@fmp^.dm_lock);
|
||||
free_unr(devfs_unr, idx);
|
||||
if (hold=0) then
|
||||
devfs_unmount_final(fmp);
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
{ Exitlocked reference to root. }
|
||||
|
||||
function devfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
|
||||
var
|
||||
error:Integer;
|
||||
vp:p_vnode;
|
||||
dmp:p_devfs_mount;
|
||||
begin
|
||||
dmp:=VFSTODEVFS(mp);
|
||||
sx_xlock(@dmp^.dm_lock);
|
||||
//error:=devfs_allocv(dmp^.dm_rootdir, mp, LK_EXCLUSIVE, @vp);
|
||||
if (error<>0) then
|
||||
Exit(error);
|
||||
vp^.v_vflag:=vp^.v_vflag or VV_ROOT;
|
||||
vpp^:=vp;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
function devfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
||||
begin
|
||||
sbp^.f_flags :=0;
|
||||
sbp^.f_bsize :=DEV_BSIZE;
|
||||
sbp^.f_iosize:=DEV_BSIZE;
|
||||
sbp^.f_blocks:=2; { 1K to keep df happy }
|
||||
sbp^.f_bfree :=0;
|
||||
sbp^.f_bavail:=0;
|
||||
sbp^.f_files :=0;
|
||||
sbp^.f_ffree :=0;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -22,6 +22,17 @@ uses
|
|||
const
|
||||
VFS_MOUNTARG_SIZE_MAX=(1024 * 64);
|
||||
|
||||
global_opts:array[0..7] of PChar=(
|
||||
'errmsg',
|
||||
'fstype',
|
||||
'fspath',
|
||||
'ro',
|
||||
'rw',
|
||||
'nosuid',
|
||||
'noexec',
|
||||
nil
|
||||
);
|
||||
|
||||
procedure vfs_freeopt(opts:p_vfsoptlist;opt:p_vfsopt);
|
||||
procedure vfs_freeopts(opts:p_vfsoptlist);
|
||||
procedure vfs_deleteopt(opts:p_vfsoptlist;name:PChar);
|
||||
|
@ -32,13 +43,18 @@ procedure vfs_sanitizeopts(opts:p_vfsoptlist);
|
|||
function vfs_buildopts(auio:p_uio;options:pp_vfsoptlist):Integer;
|
||||
procedure vfs_mergeopts(toopts,oldopts:p_vfsoptlist);
|
||||
|
||||
procedure vfs_mount_error(mp:p_mount;fmt:PChar;const Args:Array of const); register;
|
||||
procedure vfs_opterror(opts:p_vfsoptlist;fmt:PChar;const Args:Array of const); register;
|
||||
function vfs_filteropt(opts:p_vfsoptlist;legal:ppchar):Integer;
|
||||
function vfs_getopt(opts:p_vfsoptlist;name:PChar;buf:PPointer;len:PInteger):Integer;
|
||||
function vfs_getopt_pos(opts:p_vfsoptlist;name:PChar):Integer;
|
||||
function vfs_getopts(opts:p_vfsoptlist;name:PChar;error:PInteger):PChar;
|
||||
function vfs_flagopt(opts:p_vfsoptlist;name:PChar;w:PQWORD;val:QWORD):Integer;
|
||||
function vfs_scanopt(opts:p_vfsoptlist;name,fmt:PChar;const Args:Array of const):Integer; register;
|
||||
function vfs_setopt(opts:p_vfsoptlist;name,value:PChar;len:Integer):Integer;
|
||||
function vfs_setopt_part(opts:p_vfsoptlist;name,value:PChar;len:Integer):Integer;
|
||||
function vfs_setopts(opts:p_vfsoptlist;name,value:PChar):Integer;
|
||||
procedure vfs_mountedfrom(mp:p_mount;from:PChar);
|
||||
|
||||
procedure vfs_ref(mp:p_mount); inline;
|
||||
procedure vfs_rel(mp:p_mount); inline;
|
||||
|
@ -337,11 +353,116 @@ begin
|
|||
vfs_sanitizeopts(toopts);
|
||||
end;
|
||||
|
||||
{
|
||||
* Report errors during filesystem mounting.
|
||||
}
|
||||
procedure vfs_mount_error(mp:p_mount;fmt:PChar;const Args:Array of const); register;
|
||||
var
|
||||
moptlist:p_vfsoptlist;
|
||||
error,len:Integer;
|
||||
errmsg:PChar;
|
||||
S:RawByteString;
|
||||
begin
|
||||
moptlist:=mp^.mnt_optnew;
|
||||
|
||||
error:=vfs_getopt(moptlist, 'errmsg', @errmsg, @len);
|
||||
if (error<>0) or
|
||||
(errmsg=nil) or
|
||||
(len<=0) then
|
||||
Exit;
|
||||
|
||||
S:=Format(fmt,Args);
|
||||
if (len>(Length(S)+1)) then len:=Length(S)+1;
|
||||
Move(PChar(S)^,errmsg^,len);
|
||||
end;
|
||||
|
||||
procedure vfs_opterror(opts:p_vfsoptlist;fmt:PChar;const Args:Array of const); register;
|
||||
var
|
||||
error,len:Integer;
|
||||
errmsg:PChar;
|
||||
S:RawByteString;
|
||||
begin
|
||||
error:=vfs_getopt(opts, 'errmsg', @errmsg, @len);
|
||||
if (error<>0) or
|
||||
(errmsg=nil) or
|
||||
(len<=0) then
|
||||
Exit;
|
||||
|
||||
S:=Format(fmt,Args);
|
||||
if (len>(Length(S)+1)) then len:=Length(S)+1;
|
||||
Move(PChar(S)^,errmsg^,len);
|
||||
end;
|
||||
|
||||
{
|
||||
* Check that no unknown options are given
|
||||
}
|
||||
function vfs_filteropt(opts:p_vfsoptlist;legal:ppchar):Integer;
|
||||
var
|
||||
opt:p_vfsopt;
|
||||
errmsg:array[0..254] of Char;
|
||||
t:ppchar;
|
||||
p,q:pchar;
|
||||
begin
|
||||
opt:=TAILQ_FIRST(opts);
|
||||
while (opt<>nil) do
|
||||
begin
|
||||
p:=opt^.name;
|
||||
q:=nil;
|
||||
if (p[0]='n') and (p[1]='o') then
|
||||
q:=p + 2;
|
||||
t:=@global_opts;
|
||||
while (t^<>nil) do
|
||||
begin
|
||||
if (strcomp(t^, p)=0) then
|
||||
break;
|
||||
if (q<>nil) then
|
||||
begin
|
||||
if (strcomp(t^, q)=0) then
|
||||
break;
|
||||
end;
|
||||
Inc(t);
|
||||
end;
|
||||
if (t^<>nil) then
|
||||
continue;
|
||||
t:=legal;
|
||||
while (t^<>nil) do
|
||||
begin
|
||||
if (strcomp(t^, p)=0) then
|
||||
break;
|
||||
if (q<>nil) then
|
||||
begin
|
||||
if (strcomp(t^, q)=0) then
|
||||
break;
|
||||
end;
|
||||
Inc(t);
|
||||
end;
|
||||
if (t^<>nil) then
|
||||
continue;
|
||||
errmsg:='mount option is unknown';
|
||||
Result:=EINVAL;
|
||||
opt:=TAILQ_NEXT(opt,@opt^.link);
|
||||
end;
|
||||
if (Result<>0) then
|
||||
begin
|
||||
opt:=TAILQ_FIRST(opts);
|
||||
while (opt<>nil) do
|
||||
begin
|
||||
if (strcomp(opt^.name, 'errmsg')=0) then
|
||||
begin
|
||||
strlcopy(opt^.value, errmsg, opt^.len);
|
||||
break;
|
||||
end;
|
||||
opt:=TAILQ_NEXT(opt,@opt^.link);
|
||||
end;
|
||||
if (opt=nil) then
|
||||
Writeln(errmsg);
|
||||
end;
|
||||
end;
|
||||
|
||||
{
|
||||
* Get a mount option by its name.
|
||||
*
|
||||
* Exit0 if the option was found, ENOENT otherwise.
|
||||
* return 0 if the option was found, ENOENT otherwise.
|
||||
* If len is non-nil it will be filled with the length
|
||||
* of the option. If buf is non-nil, it will be filled
|
||||
* with the address of the option.
|
||||
|
@ -439,6 +560,34 @@ begin
|
|||
Exit(0);
|
||||
end;
|
||||
|
||||
function vfs_scanopt(opts:p_vfsoptlist;name,fmt:PChar;const Args:Array of const):Integer; register;
|
||||
var
|
||||
opt:p_vfsopt;
|
||||
S:RawByteString;
|
||||
begin
|
||||
Assert(opts<>nil, 'vfs_getopt: caller passed opts as nil');
|
||||
|
||||
opt:=TAILQ_FIRST(opts);
|
||||
while (opt<>nil) do
|
||||
begin
|
||||
if (strcomp(name, opt^.name)<>0) then
|
||||
begin
|
||||
opt:=TAILQ_NEXT(opt,@opt^.link);
|
||||
continue;
|
||||
end;
|
||||
opt^.seen:=1;
|
||||
if (opt^.len=0) or (opt^.value=nil) then
|
||||
Exit(0);
|
||||
if (PChar(opt^.value)[opt^.len - 1]<>#0) then
|
||||
Exit(0);
|
||||
|
||||
S:=Format(fmt,Args);
|
||||
Move(PChar(S)^,opt^.value^,Length(S)+1);
|
||||
Exit(0);
|
||||
end;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
function vfs_setopt(opts:p_vfsoptlist;name,value:PChar;len:Integer):Integer;
|
||||
var
|
||||
opt:p_vfsopt;
|
||||
|
@ -520,6 +669,12 @@ begin
|
|||
Exit(ENOENT);
|
||||
end;
|
||||
|
||||
procedure vfs_mountedfrom(mp:p_mount;from:PChar);
|
||||
begin
|
||||
FillChar(mp^.mnt_stat.f_mntfromname,sizeof(mp^.mnt_stat.f_mntfromname),0);
|
||||
strlcopy(@mp^.mnt_stat.f_mntfromname, from, sizeof(mp^.mnt_stat.f_mntfromname));
|
||||
end;
|
||||
|
||||
///
|
||||
|
||||
procedure vfs_ref(mp:p_mount); inline;
|
||||
|
|
|
@ -42,6 +42,7 @@ procedure vrele(vp:p_vnode);
|
|||
procedure vput(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);
|
||||
|
||||
|
@ -2248,44 +2249,55 @@ end;
|
|||
* If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must
|
||||
* be zero.
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
int
|
||||
vflush(mp:p_mount, int rootrefs, int flags, struct thread *td)
|
||||
function vflush(mp:p_mount;rootrefs,flags:Integer):Integer;
|
||||
label
|
||||
loop;
|
||||
var
|
||||
vp,mvp,rootvp:p_vnode;
|
||||
vattr:t_vattr;
|
||||
busy,error:Integer;
|
||||
begin
|
||||
vp:p_vnode, *mvp, *rootvp:=nil;
|
||||
struct vattr vattr;
|
||||
int busy:=0, error;
|
||||
rootvp:=nil;
|
||||
busy:=0;
|
||||
|
||||
if (rootrefs > 0) begin
|
||||
Assert((flags and (SKIPSYSTEM or WRITECLOSE))=0,
|
||||
'vflush: bad args');
|
||||
if (rootrefs > 0) then
|
||||
begin
|
||||
Assert((flags and (SKIPSYSTEM or WRITECLOSE))=0,'vflush: bad args');
|
||||
{
|
||||
* Get the filesystem root vnode. We can vput() it
|
||||
* immediately, since with rootrefs > 0, it won't go away.
|
||||
}
|
||||
if ((error:=VFS_ROOT(mp, LK_EXCLUSIVE, &rootvp))<>0) then
|
||||
error:=VFS_ROOT(mp, LK_EXCLUSIVE, @rootvp);
|
||||
if (error<>0) then
|
||||
begin
|
||||
Exit(error);
|
||||
end;
|
||||
vput(rootvp);
|
||||
end;
|
||||
loop:
|
||||
MNT_VNODE_FOREACH_ALL(vp, mp, mvp) begin
|
||||
vp:=__mnt_vnode_first_all(@mvp,mp);
|
||||
while (vp<>nil) do
|
||||
begin
|
||||
vholdl(vp);
|
||||
error:=vn_lock(vp, LK_INTERLOCK or LK_EXCLUSIVE);
|
||||
if (error) begin
|
||||
if (error<>0) then
|
||||
begin
|
||||
vdrop(vp);
|
||||
MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
|
||||
//MNT_VNODE_FOREACH_ALL_ABORT
|
||||
MNT_ILOCK(mp);
|
||||
__mnt_vnode_markerfree_all(@mvp,mp);
|
||||
//MNT_VNODE_FOREACH_ALL_ABORT
|
||||
goto loop;
|
||||
end;
|
||||
{
|
||||
* Skip over a vnodes marked VV_SYSTEM.
|
||||
}
|
||||
if ((flags and SKIPSYSTEM) and (vp^.v_vflag and VV_SYSTEM)) begin
|
||||
if (((flags and SKIPSYSTEM)<>0) and ((vp^.v_vflag and VV_SYSTEM)<>0)) then
|
||||
begin
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vdrop(vp);
|
||||
//
|
||||
vp:=__mnt_vnode_next_all(@mvp,mp);
|
||||
continue;
|
||||
end;
|
||||
{
|
||||
|
@ -2293,30 +2305,39 @@ loop:
|
|||
* files (even if open only for reading) and regular file
|
||||
* vnodes open for writing.
|
||||
}
|
||||
if (flags and WRITECLOSE) begin
|
||||
if (vp^.v_object<>nil) begin
|
||||
VM_OBJECT_LOCK(vp^.v_object);
|
||||
vm_object_page_clean(vp^.v_object, 0, 0, 0);
|
||||
VM_OBJECT_UNLOCK(vp^.v_object);
|
||||
end;
|
||||
error:=VOP_FSYNC(vp, MNT_WAIT, td);
|
||||
if (error<>0) begin
|
||||
if ((flags and WRITECLOSE)<>0) then
|
||||
begin
|
||||
//if (vp^.v_object<>nil) then
|
||||
//begin
|
||||
// VM_OBJECT_LOCK(vp^.v_object);
|
||||
// vm_object_page_clean(vp^.v_object, 0, 0, 0);
|
||||
// VM_OBJECT_UNLOCK(vp^.v_object);
|
||||
//end;
|
||||
error:=VOP_FSYNC(vp, MNT_WAIT);
|
||||
if (error<>0) then
|
||||
begin
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vdrop(vp);
|
||||
MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
|
||||
//MNT_VNODE_FOREACH_ALL_ABORT
|
||||
MNT_ILOCK(mp);
|
||||
__mnt_vnode_markerfree_all(@mvp,mp);
|
||||
//MNT_VNODE_FOREACH_ALL_ABORT
|
||||
Exit(error);
|
||||
end;
|
||||
error:=VOP_GETATTR(vp, &vattr, td^.td_ucred);
|
||||
error:=VOP_GETATTR(vp, @vattr);
|
||||
VI_LOCK(vp);
|
||||
|
||||
if ((vp^.v_type=VNON or
|
||||
(error=0 and vattr.va_nlink > 0)) and
|
||||
(vp^.v_writecount=0 or vp^.v_type<>VREG)) begin
|
||||
if ((vp^.v_type=VNON) or
|
||||
((error=0) and (vattr.va_nlink > 0))) and
|
||||
((vp^.v_writecount=0) or (vp^.v_type<>VREG)) then
|
||||
begin
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vdropl(vp);
|
||||
//
|
||||
vp:=__mnt_vnode_next_all(@mvp,mp);
|
||||
continue;
|
||||
end;
|
||||
end; else
|
||||
end else
|
||||
VI_LOCK(vp);
|
||||
{
|
||||
* With v_usecount=0, all we need to do is clear out the
|
||||
|
@ -2324,46 +2345,46 @@ loop:
|
|||
*
|
||||
* If FORCECLOSE is set, forcibly close the vnode.
|
||||
}
|
||||
if (vp^.v_usecount=0 or (flags and FORCECLOSE)) begin
|
||||
Assert(vp^.v_usecount=0 or
|
||||
(vp^.v_type<>VCHR and vp^.v_type<>VBLK), vp,
|
||||
'device VNODE %p is FORCECLOSED", vp));
|
||||
if (vp^.v_usecount=0 or (flags and FORCECLOSE)) then
|
||||
begin
|
||||
Assert((vp^.v_usecount=0) or
|
||||
((vp^.v_type<>VCHR) and (vp^.v_type<>VBLK)),'device VNODE %p is FORCECLOSED');
|
||||
vgonel(vp);
|
||||
end; else begin
|
||||
busy++;
|
||||
|
||||
end else
|
||||
begin
|
||||
Inc(busy);
|
||||
end;
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vdropl(vp);
|
||||
//
|
||||
vp:=__mnt_vnode_next_all(@mvp,mp);
|
||||
end;
|
||||
if (rootrefs > 0 and (flags and FORCECLOSE)=0) begin
|
||||
if (rootrefs > 0) and ((flags and FORCECLOSE)=0) then
|
||||
begin
|
||||
{
|
||||
* If just the root vnode is busy, and if its refcount
|
||||
* is equal to `rootrefs', then go ahead and kill it.
|
||||
}
|
||||
VI_LOCK(rootvp);
|
||||
Assert(busy > 0, 'vflush: not busy');
|
||||
Assert(rootvp^.v_usecount >= rootrefs, rootvp,
|
||||
'vflush: usecount %d < rootrefs %d",
|
||||
rootvp^.v_usecount, rootrefs));
|
||||
if (busy=1 and rootvp^.v_usecount=rootrefs) begin
|
||||
VOP_LOCK(rootvp, LK_EXCLUSIVE|LK_INTERLOCK);
|
||||
Assert(rootvp^.v_usecount >= rootrefs,'vflush: usecount %d < rootrefs %d');
|
||||
if (busy=1) and (rootvp^.v_usecount=rootrefs) then
|
||||
begin
|
||||
VOP_LOCK(rootvp, LK_EXCLUSIVE or LK_INTERLOCK,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
|
||||
vgone(rootvp);
|
||||
VOP_UNLOCK(rootvp, 0);
|
||||
busy:=0;
|
||||
end; else
|
||||
end else
|
||||
VI_UNLOCK(rootvp);
|
||||
end;
|
||||
if (busy) begin
|
||||
CTR2(KTR_VFS, "%s: failing as %d vnodes are busy", {$I %LINE%},
|
||||
busy);
|
||||
if (busy<>0) then
|
||||
begin
|
||||
Exit(EBUSY);
|
||||
end;
|
||||
for (; rootrefs > 0; rootrefs--)
|
||||
For rootrefs:=rootrefs downto 0 do
|
||||
vrele(rootvp);
|
||||
Exit(0);
|
||||
end;
|
||||
}
|
||||
|
||||
{
|
||||
* Recycle an unused vnode to the front of the free list.
|
||||
|
|
Loading…
Reference in New Issue