FPPS4/sys/fs/nullfs/null_vfsops.pas

445 lines
9.2 KiB
Plaintext

unit null_vfsops;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
kern_param,
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_vnops,
vfs_subr,
vnode_if,
null_vnops,
kern_thr,
kern_mtx,
systm;
function MOUNTTONULLMOUNT(mp:p_mount):p_null_mount; inline;
begin
Result:=mp^.mnt_data;
end;
function VTONULL(vp:p_vnode):p_null_node; inline;
begin
Result:=vp^.v_data;
end;
function NULLTOV(xp:p_null_node):p_vnode; inline;
begin
Result:=xp^.null_vnode;
end;
{
* 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;
lvp:p_vnode;
lmp:p_mount;
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'} 'from', @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
begin
vn_lock(mp^.mnt_vnodecovered, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
end;
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));
if (lowerrootvp=nil) then
begin
xmp^.nullm_vfs:=nil;
vp:=nil;
error:=0;
end else
begin
{
* Save reference to underlying FS
}
xmp^.nullm_vfs:=lowerrootvp^.v_mount;
end;
{
* 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);
lvp:=NULLVPTOLOWERVP(nullm_rootvp);
if (lvp<>nil) then
begin
lmp:=lvp^.v_mount;
if ((lmp^.mnt_flag and MNT_LOCAL)<>0) then
begin
MNT_ILOCK(mp);
mp^.mnt_flag:=mp^.mnt_flag or MNT_LOCAL;
MNT_IUNLOCK(mp);
end;
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
if (lowerrootvp<>nil) then
begin
lmp:=lowerrootvp^.v_mount;
mp^.mnt_kern_flag:=mp^.mnt_kern_flag or (lmp^.mnt_kern_flag and (MNTK_MPSAFE or MNTK_SHARED_WRITES or MNTK_LOOKUP_SHARED or MNTK_EXTENDED_SHARED));
end;
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
if (xmp^.nullm_vfs<>nil) 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 (ump<>nil) then
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;
xmp:p_null_mount;
begin
{
* Return locked reference to root.
}
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
vp:=xmp^.nullm_rootvp;
VREF(vp);
//ASSERT_VOP_UNLOCKED(vp, 'root vnode is locked');
vn_lock(vp, flags or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
vpp^:=vp;
Exit(0);
end;
function nullfs_quotactl(mp:p_mount;cmd,uid:Integer;arg:Pointer):Integer;
var
xmp:p_null_mount;
begin
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
Exit(VFS_QUOTACTL(xmp^.nullm_vfs, cmd, uid, arg));
end;
function nullfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
var
error:Integer;
mstat:t_statfs;
xmp:p_null_mount;
begin
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
if (xmp^.nullm_vfs=nil) then
begin
sbp^.f_flags :=0;
sbp^.f_bsize :=DEV_BSIZE;
sbp^.f_iosize:=DEV_BSIZE;
sbp^.f_blocks:=2;
sbp^.f_bfree :=0;
sbp^.f_bavail:=0;
sbp^.f_files :=0;
sbp^.f_ffree :=0;
Exit(0);
end;
mstat:=Default(t_statfs);
error:=VFS_STATFS(xmp^.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
xmp:p_null_mount;
error:Integer;
begin
Assert((flags and LK_TYPE_MASK)<>0,'nullfs_vget: no lock requested');
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
if (xmp^.nullm_vfs=nil) then
begin
Exit(ENOENT);
end;
error:=VFS_VGET(xmp^.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
xmp:p_null_mount;
error:Integer;
begin
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
if (xmp^.nullm_vfs=nil) then
begin
Exit(ENOENT);
end;
error:=VFS_FHTOVP(xmp^.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;
var
xmp:p_null_mount;
begin
xmp:=MOUNTTONULLMOUNT(mp);
if (xmp=nil) then Exit(EOPNOTSUPP);
if (xmp^.nullm_vfs=nil) then
begin
Exit(ENOENT);
end;
Exit(VFS_EXTATTRCTL(xmp^.nullm_vfs, cmd, filename_vp, namespace, attrname));
end;
end.