This commit is contained in:
Pavel 2024-01-03 00:57:22 +03:00
parent d1fdd8221f
commit e3fc81c59c
13 changed files with 541 additions and 54 deletions

View File

@ -205,7 +205,8 @@ uses
kern_proc,
kern_descrip,
kern_mtxpool,
subr_uio;
subr_uio,
vnode_pager;
function VFSTODEVFS(mp:p_mount):p_devfs_mount; inline;
begin
@ -1641,7 +1642,7 @@ begin
end;
mtx_unlock(devfs_de_interlock);
//vnode_destroy_vobject(vp);
vnode_destroy_vobject(vp);
VI_LOCK(vp);
dev_lock();

View File

@ -101,7 +101,8 @@ uses
kern_thr,
kern_proc,
vfs_subr,
subr_uio;
subr_uio,
vnode_pager;
const
UFS_DEL_VNLOCKED =$01;
@ -1026,7 +1027,7 @@ begin
ufs_relv(vp);
//vnode_destroy_vobject(vp);
vnode_destroy_vobject(vp);
Exit(0);
end;

View File

@ -20,18 +20,18 @@ type
//budget resid
const
SCE_KERNEL_BUDGET_MEMORY_INVALID=0;
SCE_KERNEL_BUDGET_MEMORY_DMEM =1;
SCE_KERNEL_BUDGET_MEMORY_VMEM =2;
SCE_KERNEL_BUDGET_MEMORY_MLOCK =3;
SCE_KERNEL_BUDGET_CPU_SET =4;
SCE_KERNEL_BUDGET_FD_FILE =5;
SCE_KERNEL_BUDGET_FD_SOCKET =6;
SCE_KERNEL_BUDGET_FD_EQUEUE =7;
SCE_KERNEL_BUDGET_FD_PIPE =8;
SCE_KERNEL_BUDGET_FD_DEVICE =9;
SCE_KERNEL_BUDGET_THREADS =10;
SCE_KERNEL_BUDGET_FD_IPCSOCKET =11;
SCE_KERNEL_BUDGET_INVALID =0;
SCE_KERNEL_BUDGET_MEMORY_DMEM =1;
SCE_KERNEL_BUDGET_MEMORY_VMEM =2;
SCE_KERNEL_BUDGET_MEMORY_MLOCK=3;
SCE_KERNEL_BUDGET_CPU_SET =4;
SCE_KERNEL_BUDGET_FD_FILE =5;
SCE_KERNEL_BUDGET_FD_SOCKET =6;
SCE_KERNEL_BUDGET_FD_EQUEUE =7;
SCE_KERNEL_BUDGET_FD_PIPE =8;
SCE_KERNEL_BUDGET_FD_DEVICE =9;
SCE_KERNEL_BUDGET_THREADS =10;
SCE_KERNEL_BUDGET_FD_IPCSOCKET=11;
//budget proc_type
PTYPE_BIG_APP = 0;

View File

@ -463,7 +463,7 @@ begin
if (imgp=nil) then Exit;
imgp^.authinfo:=Default(t_authinfo);
imgp^.authinfo.app_caps [0]:=QWORD($2000000000000000); //IsGameProcess1
imgp^.authinfo.app_caps [0]:=QWORD($2000000000000000); //IsGame
imgp^.authinfo.app_attrs[0]:=$400000 or $800000; //allow dmem map
if (imgp^.image_header=nil) or

View File

@ -123,7 +123,8 @@ uses
vstat,
vfs_subr,
subr_uio,
kern_thr;
kern_thr,
vnode_pager;
const
UFS_SET_READONLY=(not &0222);
@ -1094,7 +1095,7 @@ begin
md_delete_cache(de);
end;
//vnode_destroy_vobject(vp);
vnode_destroy_vobject(vp);
Exit(0);
end;
@ -1944,7 +1945,7 @@ begin
VLNK:Exit(0);
VDIR:Exit(0);
else
Exit(EPERM);
Exit(EOPNOTSUPP);
end;
de:=vp^.v_data;
@ -1997,6 +1998,8 @@ begin
vp^.v_un:=Pointer(FD);
vnode_create_vobject(vp, de^.ufs_size);
if ((de^.ufs_flags and UFS_CREATE)<>0) then
begin
if ((flags and O_EXCL)<>0) then
@ -2028,6 +2031,8 @@ begin
NtClose(FD);
end;
vnode_destroy_vobject(vp);
Result:=0;
end;
@ -2259,6 +2264,8 @@ begin
if (Result<>0) then goto _err;
de^.ufs_size:=SIZE;
vnode_pager_setsize(vp, SIZE);
end;
_err:
@ -2396,6 +2403,19 @@ begin
Dec(uio^.uio_iovcnt);
end;
if (Result=0) and (uio^.uio_rw=UIO_WRITE) then
begin
if not locked then
begin
sx_xlock(@de^.ufs_md_lock);
end;
md_update_dirent(F,de,nil);
vnode_pager_setsize(vp, de^.ufs_size);
sx_xunlock(@de^.ufs_md_lock);
end else
if locked then
begin
sx_xunlock(@de^.ufs_md_lock);

View File

@ -799,6 +799,10 @@
<Filename Value="..\sys_crt.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\vm\vnode_pager.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -2164,8 +2164,8 @@ var
mp:p_mount;
begin
Inc(vp^.v_holdcnt);
if (not VSHOULDBUSY(vp)) then
Exit;
if (not VSHOULDBUSY(vp)) then Exit;
ASSERT_VI_LOCKED(vp,'vholdl');
Assert((vp^.v_iflag and VI_FREE)<>0,'vnode not free');
Assert(vp^.v_op<>nil,'vholdl: vnode already reclaimed.');
@ -2659,7 +2659,7 @@ begin
begin
obj:=vp^.v_object;
if (obj<>nil) and
{((obj^.flags and OBJ_MIGHTBEDIRTY)<>0)} False and
((obj^.flags and OBJ_MIGHTBEDIRTY)<>0) and
((flags=MNT_WAIT) or (VOP_ISLOCKED(vp)=0)) then
begin
if (vget(vp, LK_EXCLUSIVE or LK_RETRY or LK_INTERLOCK)=0) then
@ -2960,17 +2960,21 @@ begin
error:=0;
dev_lock();
if (vp^.v_type<>VCHR) then
begin
error:=ENOTBLK
else
end else
if (vp^.v_rdev=nil) then
begin
error:=ENXIO
else
end else
if (p_cdev(vp^.v_rdev)^.si_devsw=nil) then
begin
error:=ENXIO
end{ else
if ((p_cdev(vp^.v_rdev)^.si_devsw^.d_flags and D_DISK)=0) then
error:=ENOTBLK};
end else
if ((p_cdevsw(p_cdev(vp^.v_rdev)^.si_devsw)^.d_flags and D_DISK)=0) then
begin
error:=ENOTBLK;
end;
dev_unlock();
error:=ENOTBLK;
if (errp<>nil) then

View File

@ -311,6 +311,8 @@ procedure vn_rangelock_unlock_range(vp:p_vnode;cookie:Pointer;start,__end:Int64)
function vn_rangelock_rlock(vp:p_vnode;start,__end:Int64):Pointer;
function vn_rangelock_wlock(vp:p_vnode;start,__end:Int64):Pointer;
function vn_canvmio(vp:p_vnode):Boolean;
var
rootvnode:p_vnode=nil;
@ -463,5 +465,22 @@ begin
//Result:=rangelock_wlock(@vp^.v_rl, start, __end, VI_MTX(vp))
end;
const
vmiodirenable=False;
function vn_canvmio(vp:p_vnode):Boolean;
begin
if (vp<>nil) then
begin
if (vp^.v_type=VREG) or
(vmiodirenable and (vp^.v_type=VDIR)) then
begin
Exit(True);
end;
end;
Result:=False;
end;
end.

View File

@ -32,9 +32,7 @@ type
vm_object_t=^t_vm_object;
t_vm_object=packed record
mtx :mtx;
memq :TAILQ_HEAD; // list of resident pages
patchq :TAILQ_HEAD; // list of patches
root :Pointer; // root of the resident page splay tree
size :vm_pindex_t; // Object size
generation :Integer; // generation ID
ref_count :Integer; // How many refs??
@ -118,6 +116,15 @@ function vm_object_page_clean(obj:vm_object_t;
implementation
uses
vnode;
//
procedure vref(vp:p_vnode); external;
//
function VM_OBJECT_MTX(obj:vm_object_t):p_mtx;
begin
Result:=@obj^.mtx;
@ -166,7 +173,6 @@ begin
mtx_init(Result^.mtx,'vm_object');
TAILQ_INIT(@Result^.memq);
TAILQ_INIT(@Result^.patchq);
Result^.otype :=t;
@ -190,7 +196,19 @@ procedure vm_object_reference(obj:vm_object_t);
begin
if (obj=nil) then Exit;
System.InterlockedIncrement(obj^.ref_count);
VM_OBJECT_LOCK(obj);
Inc(obj^.ref_count);
if (obj^.otype=OBJT_VNODE) then
begin
if (obj^.otype=OBJT_VNODE) then
begin
vref(obj^.handle);
end;
end;
VM_OBJECT_UNLOCK(obj);
end;
procedure vm_object_pip_add(obj:vm_object_t;i:word);

View File

@ -181,7 +181,7 @@ begin
end;
foff:=foffp^;
flags:=flagsp^;
obj:=nil;
obj:=vp^.v_object;
case vp^.v_type of
@ -258,12 +258,14 @@ begin
begin
flags:=flags or MAP_NOSYNC;
end;
obj:=vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff);
if (obj=nil) then
begin
error:=ENOMEM;
goto done;
end;
objp^:=obj;
flagsp^:=flags;
@ -276,7 +278,9 @@ done:
writecounted^:=FALSE;
//vnode_pager_update_writecount(obj, objsize, 0);
end;
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Result:=(error);
end;

View File

@ -38,7 +38,11 @@ implementation
uses
vmparam,
vnode,
vfs_subr;
vnode_if,
vmount,
vfs_subr,
vfs_vnops,
kern_mtx;
//
@ -71,7 +75,7 @@ end;
The object must be locked.
This routine may block.
}
procedure vm_object_terminate(obj:vm_object_t);
procedure vm_object_terminate(obj:vm_object_t); public;
var
vp:p_vnode;
begin
@ -118,26 +122,112 @@ begin
vm_object_destroy(obj);
end;
procedure vm_object_deallocate(obj:vm_object_t); public;
{
Handle deallocating an object of type OBJT_VNODE.
}
procedure vm_object_vndeallocate(obj:vm_object_t);
var
ref:Integer;
vp:p_vnode;
begin
vp:=obj^.handle;
VFS_ASSERT_GIANT(vp^.v_mount);
VM_OBJECT_LOCK_ASSERT(obj);
Assert(obj^.otype=OBJT_VNODE,'vm_object_vndeallocate: not a vnode obj');
Assert(vp<>nil, 'vm_object_vndeallocate: missing vp');
if (obj^.ref_count > 1) then
begin
VM_OBJECT_UNLOCK(obj);
// vrele may need the vnode lock.
vrele(vp);
end else
begin
vhold(vp);
VM_OBJECT_UNLOCK(obj);
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY);
vdrop(vp);
VM_OBJECT_LOCK(obj);
Dec(obj^.ref_count);
if (obj^.otype=OBJT_DEAD) then
begin
VM_OBJECT_UNLOCK(obj);
VOP_UNLOCK(vp, 0);
end else
begin
if (obj^.ref_count=0) then
begin
//VOP_UNSET_TEXT(vp);
end;
VM_OBJECT_UNLOCK(obj);
vput(vp);
end;
end;
end;
{
vm_object_deallocate:
Release a reference to the specified object,
gained either through a vm_object_allocate
or a vm_object_reference call. When all references
are gone, storage associated with this object
may be relinquished.
No object may be locked.
}
procedure vm_object_deallocate(obj:vm_object_t); public;
label
restart;
var
vfslocked:Integer;
vp:p_vnode;
begin
if (obj=nil) then Exit;
ref:=System.InterlockedDecrement(obj^.ref_count);
VM_OBJECT_LOCK(obj);
if (ref=1) then
begin
VM_OBJECT_LOCK(obj);
vm_object_set_flag(obj, OBJ_ONEMAPPING);
VM_OBJECT_UNLOCK(obj);
end else
if (ref=0) then
if ((obj^.flags and OBJ_DEAD)=0) then
begin
VM_OBJECT_LOCK(obj);
vm_object_terminate(obj);
end;
if (obj^.otype=OBJT_VNODE) then
begin
restart:
vp:=obj^.handle;
vfslocked:=0;
if VFS_NEEDSGIANT(vp^.v_mount) then
begin
vfslocked:=1;
if not mtx_trylock(VFS_Giant) then
begin
VM_OBJECT_UNLOCK(obj);
mtx_lock(VFS_Giant);
goto restart;
end;
end;
vm_object_vndeallocate(obj);
VFS_UNLOCK_GIANT(vfslocked);
Exit;
end;
Dec(obj^.ref_count);
if (obj^.ref_count=1) then
begin
vm_object_set_flag(obj, OBJ_ONEMAPPING);
end else
if (obj^.ref_count=0) then
if ((obj^.flags and OBJ_DEAD)=0) then
begin
vm_object_terminate(obj);
end;
VM_OBJECT_UNLOCK(obj);
end;
procedure vm_object_pip_wakeup(obj:vm_object_t);
@ -166,7 +256,7 @@ begin
end;
end;
procedure vm_object_pip_wait(obj:vm_object_t;waitid:pchar);
procedure vm_object_pip_wait(obj:vm_object_t;waitid:pchar); public;
begin
if (obj=nil) then Exit;

View File

@ -21,7 +21,8 @@ implementation
uses
vmparam,
device_pager;
device_pager,
vnode_pager;
function OFF_TO_IDX(x:QWORD):DWORD; inline;
begin
@ -37,7 +38,7 @@ begin
case otype of
OBJT_DEFAULT :Result:=vm_object_allocate(otype,OFF_TO_IDX(size));
//OBJT_SWAP :;
//OBJT_VNODE :;
OBJT_VNODE :Result:=vnode_pager_alloc(handle,size,prot,off);
OBJT_DEVICE :Result:=dev_pager_alloc(handle,size,prot,off);
//OBJT_PHYS :;
//OBJT_DEAD :;
@ -65,7 +66,7 @@ begin
case obj^.otype of
OBJT_DEFAULT :default_dealloc(obj);
OBJT_SWAP :;
OBJT_VNODE :;
OBJT_VNODE :vnode_pager_dealloc(obj);
OBJT_DEVICE :dev_pager_dealloc(obj);
OBJT_PHYS :;
OBJT_DEAD :;

325
sys/vm/vnode_pager.pas Normal file
View File

@ -0,0 +1,325 @@
unit vnode_pager;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
vnode,
vm,
vmparam,
sys_vm_object;
function vnode_pager_alloc(handle:Pointer;
size:vm_ooffset_t;
prot:vm_prot_t;
offset:vm_ooffset_t):vm_object_t;
function vnode_create_vobject(vp:p_vnode;isize:vm_ooffset_t):Integer;
procedure vnode_destroy_vobject(vp:p_vnode);
procedure vnode_pager_dealloc(obj:vm_object_t);
procedure vnode_pager_setsize(vp:p_vnode;nsize:vm_ooffset_t);
implementation
uses
vnode_if,
vfs_subr,
vfs_vnops,
kern_synch,
kern_param,
kern_mtx;
//
procedure vm_object_terminate(obj:vm_object_t); external;
procedure vm_pager_deallocate(obj:vm_object_t); external;
procedure vm_object_pip_wait(obj:vm_object_t;waitid:pchar); external;
//
function IDX_TO_OFF(x:DWORD):QWORD; inline;
begin
Result:=QWORD(x) shl PAGE_SHIFT;
end;
function OFF_TO_IDX(x:QWORD):DWORD; inline;
begin
Result:=QWORD(x) shr PAGE_SHIFT;
end;
{
* Allocate (or lookup) pager for a vnode.
* Handle is a vnode pointer.
*
* MPSAFE
}
function vnode_pager_alloc(handle:Pointer;
size:vm_ooffset_t;
prot:vm_prot_t;
offset:vm_ooffset_t):vm_object_t;
label
retry;
var
obj:vm_object_t;
vp:p_vnode;
begin
{
* Pageout to vnode, no can do yet.
}
if (handle=nil) then Exit(nil);
vp:=handle;
{
* If the obj is being terminated, wait for it to
* go away.
}
retry:
obj:=vp^.v_object;
while (obj<>nil) do
begin
VM_OBJECT_LOCK(obj);
if ((obj^.flags and OBJ_DEAD)=0) then
begin
break;
end;
vm_object_set_flag(obj, OBJ_DISCONNECTWNT);
msleep(obj, VM_OBJECT_MTX(obj), PDROP or PVM, 'vadead', 0);
obj:=vp^.v_object;
end;
Assert(vp^.v_usecount<>0, 'vnode_pager_alloc: no vnode reference');
if (obj=nil) then
begin
{
* Add an obj of the appropriate size
}
obj:=vm_object_allocate(OBJT_VNODE, OFF_TO_IDX(round_page(size)));
obj^.un_pager.vnp.vnp_size:=size;
obj^.un_pager.vnp.writemappings:=0;
obj^.handle:=handle;
VI_LOCK(vp);
if (vp^.v_object<>nil) then
begin
// Obj has been created while we were sleeping
VI_UNLOCK(vp);
VM_OBJECT_LOCK(obj);
Assert(obj^.ref_count=1, 'leaked ref %p %d');
obj^.otype:=OBJT_DEAD;
obj^.ref_count:=0;
VM_OBJECT_UNLOCK(obj);
vm_object_destroy(obj);
goto retry;
end;
vp^.v_object:=obj;
VI_UNLOCK(vp);
end else
begin
Inc(obj^.ref_count);
VM_OBJECT_UNLOCK(obj);
end;
vref(vp);
Exit(obj);
end;
{ Create the VM system backing object for this vnode }
function vnode_create_vobject(vp:p_vnode;isize:vm_ooffset_t):Integer;
var
obj:vm_object_t;
size:QWORD;
va:t_vattr;
begin
size:=isize;
if (not vn_isdisk(vp, nil)) and (vn_canvmio(vp)=FALSE) then
begin
Exit(0);
end;
obj:=vp^.v_object;
while (obj<>nil) do
begin
VM_OBJECT_LOCK(obj);
if ((obj^.flags and OBJ_DEAD)=0) then
begin
VM_OBJECT_UNLOCK(obj);
Exit(0);
end;
VOP_UNLOCK(vp, 0);
vm_object_set_flag(obj, OBJ_DISCONNECTWNT);
msleep(obj, VM_OBJECT_MTX(obj), PDROP or PVM, 'vodead', 0);
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY);
//
obj:=vp^.v_object;
end;
if (size=0) then
begin
if (vn_isdisk(vp, nil)) then
begin
size:=IDX_TO_OFF(High(Integer));
end else
begin
if (VOP_GETATTR(vp, @va)<>0) then
begin
Exit(0);
end;
size:=va.va_size;
end;
end;
obj:=vnode_pager_alloc(vp, size, 0, 0);
{
* Dereference the reference we just created. This assumes
* that the obj is associated with the vp.
}
//VM_OBJECT_LOCK(obj);
// Dec(obj^.ref_count);
//VM_OBJECT_UNLOCK(obj);
//vrele(vp);
Assert(vp^.v_object<>nil, 'vnode_create_vobject: nil obj');
Exit(0);
end;
procedure vnode_destroy_vobject(vp:p_vnode);
var
obj:vm_object_t;
begin
obj:=vp^.v_object;
if (obj=nil) then Exit;
ASSERT_VOP_ELOCKED(vp, 'vnode_destroy_vobject');
VM_OBJECT_LOCK(obj);
if (obj^.ref_count=0) then
begin
{
* vclean() may be called twice. The first time
* removes the primary reference to the object,
* the second time goes one further and is a
* special-case to terminate the object.
*
* don't double-terminate the object
}
if ((obj^.flags and OBJ_DEAD)=0) then
vm_object_terminate(obj)
else
VM_OBJECT_UNLOCK(obj);
end else
begin
{
* Woe to the process that tries to page now :-).
}
vm_pager_deallocate(obj);
VM_OBJECT_UNLOCK(obj);
end;
vp^.v_object:=nil;
end;
{
* The object must be locked.
}
procedure vnode_pager_dealloc(obj:vm_object_t);
var
vp:p_vnode;
refs:Integer;
begin
vp:=obj^.handle;
if (vp=nil) then
begin
Writeln(StdErr,'vnode_pager_dealloc: pager already dealloced');
Exit;
end;
VM_OBJECT_LOCK_ASSERT(obj);
vm_object_pip_wait(obj, 'vnpdea');
refs:=obj^.ref_count;
obj^.handle:=nil;
obj^.otype:=OBJT_DEAD;
if ((obj^.flags and OBJ_DISCONNECTWNT)<>0) then
begin
vm_object_clear_flag(obj, OBJ_DISCONNECTWNT);
wakeup(obj);
end;
ASSERT_VOP_ELOCKED(vp, 'vnode_pager_dealloc');
if (obj^.un_pager.vnp.writemappings > 0) then
begin
obj^.un_pager.vnp.writemappings:=0;
VOP_ADD_WRITECOUNT(vp, -1);
end;
vp^.v_object:=nil;
//VOP_UNSET_TEXT(vp);
VM_OBJECT_UNLOCK(obj);
while (refs>0) do
begin
vunref(vp);
Dec(refs);
end;
VM_OBJECT_LOCK(obj);
end;
{
Lets the VM system know about a change in size for a file.
We adjust our own internal size and flush any cached pages in
the associated object that are affected by the size change.
Note: this routine may be invoked as a result of a pager put
operation (possibly at object termination time), so we must be careful.
}
procedure vnode_pager_setsize(vp:p_vnode;nsize:vm_ooffset_t);
var
obj:vm_object_t;
nobjsize:DWORD;
begin
obj:=vp^.v_object;
if (obj=nil) then Exit;
nobjsize:=OFF_TO_IDX(nsize + PAGE_MASK);
VM_OBJECT_LOCK(obj);
if (obj^.otype=OBJT_DEAD) then
begin
VM_OBJECT_UNLOCK(obj);
Exit;
end;
Assert(obj^.otype=OBJT_VNODE,'not vnode-backed obj %p');
obj^.un_pager.vnp.vnp_size:=nsize;
obj^.size:=nobjsize;
VM_OBJECT_UNLOCK(obj);
end;
end.