diff --git a/sys/kern/kern_sx.pas b/sys/kern/kern_sx.pas index a9f6a49e..d7099617 100644 --- a/sys/kern/kern_sx.pas +++ b/sys/kern/kern_sx.pas @@ -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. diff --git a/sys/sys_fnmatch.pas b/sys/sys_fnmatch.pas index e1ab0fdd..026eb861 100644 --- a/sys/sys_fnmatch.pas +++ b/sys/sys_fnmatch.pas @@ -33,16 +33,10 @@ implementation uses sysutils; -//#include -//#include -//#include -//#include - { * 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; diff --git a/sys/sys_sysinit.pas b/sys/sys_sysinit.pas index 88d1278f..967fa953 100644 --- a/sys/sys_sysinit.pas +++ b/sys/sys_sysinit.pas @@ -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. diff --git a/sys/test/project1.lpi b/sys/test/project1.lpi index b631379e..69ecc796 100644 --- a/sys/test/project1.lpi +++ b/sys/test/project1.lpi @@ -425,6 +425,10 @@ + + + + diff --git a/sys/test/project1.lpr b/sys/test/project1.lpr index c0371268..63ae30f7 100644 --- a/sys/test/project1.lpr +++ b/sys/test/project1.lpr @@ -51,7 +51,8 @@ uses vnode_if, sys_sysinit, sys_fnmatch, - devfs; + devfs, + devfs_vfsops; var mtx:umutex; diff --git a/sys/vfs/devfs/devfs_rule.pas b/sys/vfs/devfs/devfs_rule.pas index 76d0364f..99d8923b 100644 --- a/sys/vfs/devfs/devfs_rule.pas +++ b/sys/vfs/devfs/devfs_rule.pas @@ -10,20 +10,6 @@ uses devfs, kern_sx; -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include -//#include - { * Kernel version of devfs_rule. } diff --git a/sys/vfs/devfs/devfs_vfsops.pas b/sys/vfs/devfs/devfs_vfsops.pas new file mode 100644 index 00000000..a3995ef9 --- /dev/null +++ b/sys/vfs/devfs/devfs_vfsops.pas @@ -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. + diff --git a/sys/vfs/vfs_mount.pas b/sys/vfs/vfs_mount.pas index 261e069e..e8334e08 100644 --- a/sys/vfs/vfs_mount.pas +++ b/sys/vfs/vfs_mount.pas @@ -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; diff --git a/sys/vfs/vfs_subr.pas b/sys/vfs/vfs_subr.pas index e176118e..4e67905e 100644 --- a/sys/vfs/vfs_subr.pas +++ b/sys/vfs/vfs_subr.pas @@ -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.