5
5
6
6
#include " public/PrjFSCommon.h"
7
7
#include " public/PrjFSPerfCounter.h"
8
+ #include " public/PrjFSXattrs.h"
8
9
#include " VirtualizationRoots.hpp"
9
10
#include " VnodeUtilities.hpp"
10
11
#include " KauthHandler.hpp"
16
17
#include " kernel-header-wrappers/stdatomic.h"
17
18
#include " KextLog.hpp"
18
19
#include " ProviderMessaging.hpp"
19
- #include " public/PrjFSXattrs.h "
20
+ #include " VnodeCache.hpp "
20
21
21
22
#ifdef KEXT_UNIT_TESTING
22
23
#include " KauthHandlerTestable.hpp"
@@ -88,12 +89,13 @@ static bool TryGetVirtualizationRoot(
88
89
int * kauthResult,
89
90
int * kauthError);
90
91
91
- static bool ShouldHandleFileOpEvent (
92
+ KEXT_STATIC bool ShouldHandleFileOpEvent (
92
93
// In params:
93
94
PerfTracer* perfTracer,
94
95
vfs_context_t _Nonnull context,
95
96
const vnode_t vnode,
96
97
kauth_action_t action,
98
+ bool isDirectory,
97
99
98
100
// Out params:
99
101
VirtualizationRootHandle* root,
@@ -124,6 +126,11 @@ kern_return_t KauthHandler_Init()
124
126
goto CleanupAndFail;
125
127
}
126
128
129
+ if (VnodeCache_Init ())
130
+ {
131
+ goto CleanupAndFail;
132
+ }
133
+
127
134
s_vnodeListener = kauth_listen_scope (KAUTH_SCOPE_VNODE, HandleVnodeOperation, nullptr );
128
135
if (nullptr == s_vnodeListener)
129
136
{
@@ -172,6 +179,11 @@ kern_return_t KauthHandler_Cleanup()
172
179
173
180
WaitForListenerCompletion ();
174
181
182
+ if (VnodeCache_Cleanup ())
183
+ {
184
+ result = KERN_FAILURE;
185
+ }
186
+
175
187
if (VirtualizationRoots_Cleanup ())
176
188
{
177
189
result = KERN_FAILURE;
@@ -468,6 +480,8 @@ KEXT_STATIC int HandleFileOpOperation(
468
480
469
481
putCurrentVnode = true ;
470
482
483
+ bool isDirectory = (0 != vnode_isdir (currentVnode));
484
+
471
485
VirtualizationRootHandle root = RootHandle_None;
472
486
FsidInode vnodeFsidInode = {};
473
487
int pid;
@@ -476,6 +490,7 @@ KEXT_STATIC int HandleFileOpOperation(
476
490
context,
477
491
currentVnode,
478
492
action,
493
+ isDirectory,
479
494
&root,
480
495
&vnodeFsidInode,
481
496
&pid))
@@ -491,7 +506,7 @@ KEXT_STATIC int HandleFileOpOperation(
491
506
PerfSample renameSample (&perfTracer, PrjFSPerfCounter_FileOp_Renamed);
492
507
493
508
MessageType messageType =
494
- vnode_isdir (currentVnode)
509
+ isDirectory
495
510
? MessageType_KtoU_NotifyDirectoryRenamed
496
511
: MessageType_KtoU_NotifyFileRenamed;
497
512
@@ -566,6 +581,7 @@ KEXT_STATIC int HandleFileOpOperation(
566
581
context,
567
582
currentVnode,
568
583
action,
584
+ false /* isDirectory */ ,
569
585
&root,
570
586
&vnodeFsidInode,
571
587
&pid))
@@ -619,6 +635,7 @@ KEXT_STATIC int HandleFileOpOperation(
619
635
context,
620
636
currentVnode,
621
637
action,
638
+ false /* isDirectory */ ,
622
639
&root,
623
640
&vnodeFsidInode,
624
641
&pid))
@@ -780,10 +797,11 @@ static bool TryGetVirtualizationRoot(
780
797
int * kauthError)
781
798
{
782
799
PerfSample findRootSample (perfTracer, PrjFSPerfCounter_VnodeOp_GetVirtualizationRoot);
783
-
784
- *vnodeFsidInode = Vnode_GetFsidAndInode (vnode, context, true /* the inode is used for getting the path in the provider, so use linkid */ );
785
- *root = VirtualizationRoot_FindForVnode (
800
+
801
+ *root = VnodeCache_FindRootForVnode (
786
802
perfTracer,
803
+ PrjFSPerfCounter_VnodeOp_Vnode_Cache_Hit,
804
+ PrjFSPerfCounter_VnodeOp_Vnode_Cache_Miss,
787
805
PrjFSPerfCounter_VnodeOp_FindRoot,
788
806
PrjFSPerfCounter_VnodeOp_FindRoot_Iteration,
789
807
vnode,
@@ -836,6 +854,8 @@ static bool TryGetVirtualizationRoot(
836
854
return false ;
837
855
}
838
856
857
+ *vnodeFsidInode = Vnode_GetFsidAndInode (vnode, context, true /* the inode is used for getting the path in the provider, so use linkid */ );
858
+
839
859
return true ;
840
860
}
841
861
@@ -884,12 +904,13 @@ static bool CurrentProcessWasSpawnedByRegularUser()
884
904
}
885
905
886
906
887
- static bool ShouldHandleFileOpEvent (
907
+ KEXT_STATIC bool ShouldHandleFileOpEvent (
888
908
// In params:
889
909
PerfTracer* perfTracer,
890
- vfs_context_t context,
910
+ vfs_context_t _Nonnull context,
891
911
const vnode_t vnode,
892
912
kauth_action_t action,
913
+ bool isDirectory,
893
914
894
915
// Out params:
895
916
VirtualizationRootHandle* root,
@@ -914,12 +935,72 @@ static bool ShouldHandleFileOpEvent(
914
935
{
915
936
PerfSample findRootSample (perfTracer, PrjFSPerfCounter_FileOp_ShouldHandle_FindVirtualizationRoot);
916
937
917
- *root = VirtualizationRoot_FindForVnode (
918
- perfTracer,
919
- PrjFSPerfCounter_FileOp_FindRoot,
920
- PrjFSPerfCounter_FileOp_FindRoot_Iteration,
921
- vnode,
922
- context);
938
+ if (isDirectory)
939
+ {
940
+ if (KAUTH_FILEOP_RENAME == action)
941
+ {
942
+ // Directory renames into (or out) of virtualization roots require invalidating all of the entries
943
+ // within the directory being renamed (because all of those entires now have a new virtualzation root).
944
+ // Rather than trying to find all vnodes in the cache that are children of the directory being renamed
945
+ // we simply invalidate the entire cache.
946
+ //
947
+ // Potential future optimizations include:
948
+ // - Only invalidate the cache if the rename moves a directory in or out of a directory
949
+ // - Keeping a per-root generation ID in the cache to allow invalidating a subset of the cache
950
+ VnodeCache_InvalidateCache (perfTracer);
951
+ }
952
+
953
+ *root = VnodeCache_FindRootForVnode (
954
+ perfTracer,
955
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Hit,
956
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Miss,
957
+ PrjFSPerfCounter_FileOp_FindRoot,
958
+ PrjFSPerfCounter_FileOp_FindRoot_Iteration,
959
+ vnode,
960
+ context);
961
+ }
962
+ else
963
+ {
964
+ // TODO(Mac): Once all hardlink paths are delivered to the appropriate root(s)
965
+ // check if the KAUTH_FILEOP_LINK case can be removed. For now the check is required to make
966
+ // sure we're looking up the most up-to-date parent information for the vnode on the next
967
+ // access to the vnode cache
968
+ switch (action)
969
+ {
970
+ case KAUTH_FILEOP_LINK:
971
+ *root = VnodeCache_InvalidateVnodeRootAndGetLatestRoot (
972
+ perfTracer,
973
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Hit,
974
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Miss,
975
+ PrjFSPerfCounter_FileOp_FindRoot,
976
+ PrjFSPerfCounter_FileOp_FindRoot_Iteration,
977
+ vnode,
978
+ context);
979
+ break ;
980
+
981
+ case KAUTH_FILEOP_RENAME:
982
+ *root = VnodeCache_RefreshRootForVnode (
983
+ perfTracer,
984
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Hit,
985
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Miss,
986
+ PrjFSPerfCounter_FileOp_FindRoot,
987
+ PrjFSPerfCounter_FileOp_FindRoot_Iteration,
988
+ vnode,
989
+ context);
990
+ break ;
991
+
992
+ default :
993
+ *root = VnodeCache_FindRootForVnode (
994
+ perfTracer,
995
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Hit,
996
+ PrjFSPerfCounter_FileOp_Vnode_Cache_Miss,
997
+ PrjFSPerfCounter_FileOp_FindRoot,
998
+ PrjFSPerfCounter_FileOp_FindRoot_Iteration,
999
+ vnode,
1000
+ context);
1001
+ break ;
1002
+ }
1003
+ }
923
1004
924
1005
if (!VirtualizationRoot_IsValidRootHandle (*root))
925
1006
{
0 commit comments