[PATCH 09/11] mount.cc: Implement poor-man's cache

Ben Wijen ben@wijen.net
Fri Jan 15 13:45:32 GMT 2021


Try to avoid NtQueryVolumeInformationFile.
---
 winsup/cygwin/mount.cc | 78 ++++++++++++++++++++++++++++--------------
 winsup/cygwin/mount.h  |  2 +-
 winsup/cygwin/path.cc  |  2 +-
 winsup/cygwin/path.h   |  1 +
 4 files changed, 56 insertions(+), 27 deletions(-)

diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc
index e0349815d..1d2b3a61a 100644
--- a/winsup/cygwin/mount.cc
+++ b/winsup/cygwin/mount.cc
@@ -82,6 +82,32 @@ win32_device_name (const char *src_path, char *win32_path, device& dev)
   return true;
 }
 
+static uint32_t
+hash_prefix (const PUNICODE_STRING upath)
+{
+  UNICODE_STRING prefix;
+  WCHAR *p;
+
+  if (upath->Buffer[5] == L':' && upath->Buffer[6] == L'\\')
+    p = upath->Buffer + 6;
+  else
+    {
+      /* We're expecting an UNC path.  Move p to the backslash after
+       "\??\UNC\server\share" or the trailing NUL. */
+      p = upath->Buffer + 7; /* Skip "\??\UNC" */
+      int bs_cnt = 0;
+
+      while (*++p)
+        if (*p == L'\\')
+          if (++bs_cnt > 1)
+            break;
+    }
+  RtlInitCountedUnicodeString (&prefix, upath->Buffer,
+                               (p - upath->Buffer) * sizeof(WCHAR));
+
+  return hash_path_name ((ino_t) 0, &prefix);
+}
+
 /* Beginning with Samba 3.0.28a, Samba allows to get version information using
    the ExtendedInfo member returned by a FileFsObjectIdInformation request.
    We just store the samba_version information for now.  Older versions than
@@ -106,14 +132,16 @@ class fs_info_cache
   struct {
     fs_info fsi;
     uint32_t hash;
+    uint32_t prefix_hash;
   } entry[MAX_FS_INFO_CNT];
 
   uint32_t genhash (PFILE_FS_VOLUME_INFORMATION);
 
 public:
   fs_info_cache () : count (0) { fsi_lock.init ("fsi_lock"); }
+  fs_info *search (uint32_t);
   fs_info *search (PFILE_FS_VOLUME_INFORMATION, uint32_t &);
-  void add (uint32_t, fs_info *);
+  void add (uint32_t, fs_info *, uint32_t);
 };
 
 static fs_info_cache fsi_cache;
@@ -142,22 +170,31 @@ fs_info_cache::search (PFILE_FS_VOLUME_INFORMATION pffvi, uint32_t &hash)
       return &entry[i].fsi;
   return NULL;
 }
+fs_info*
+fs_info_cache::search (uint32_t prefix_hash)
+{
+  for (uint32_t i = 0; i < count; ++i)
+    if (entry[i].prefix_hash == prefix_hash)
+      return &entry[i].fsi;
+  return NULL;
+}
 
 void
-fs_info_cache::add (uint32_t hashval, fs_info *new_fsi)
+fs_info_cache::add (uint32_t hashval, fs_info *new_fsi, uint32_t prefix_hash)
 {
   fsi_lock.acquire ();
   if (count < MAX_FS_INFO_CNT)
     {
       entry[count].fsi = *new_fsi;
       entry[count].hash = hashval;
+      entry[count].prefix_hash = prefix_hash;
       ++count;
     }
   fsi_lock.release ();
 }
 
 bool
-fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
+fs_info::update (PUNICODE_STRING upath, HANDLE in_vol, bool use_prefix_hash)
 {
   NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
   HANDLE vol;
@@ -178,6 +215,17 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
   UNICODE_STRING fsname;
 
   clear ();
+
+  if (use_prefix_hash)
+    {
+      fs_info *fsi = fsi_cache.search (hash_prefix (upath));
+      if (fsi)
+        {
+          *this = *fsi;
+          return true;
+        }
+    }
+
   /* Always caseinsensitive.  We really just need access to the drive. */
   InitializeObjectAttributes (&attr, upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
   if (in_vol)
@@ -233,27 +281,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
 	 a unique per-drive/share hash. */
       if (ffvi_buf.ffvi.VolumeSerialNumber == 0)
 	{
-	  UNICODE_STRING path_prefix;
-	  WCHAR *p;
-
-	  if (upath->Buffer[5] == L':' && upath->Buffer[6] == L'\\')
-	    p = upath->Buffer + 6;
-	  else
-	    {
-	      /* We're expecting an UNC path.  Move p to the backslash after
-	         "\??\UNC\server\share" or the trailing NUL. */
-	      p = upath->Buffer + 7;  /* Skip "\??\UNC" */
-	      int bs_cnt = 0;
-
-	      while (*++p)
-		if (*p == L'\\')
-		    if (++bs_cnt > 1)
-		      break;
-	    }
-	  RtlInitCountedUnicodeString (&path_prefix, upath->Buffer,
-				       (p - upath->Buffer) * sizeof (WCHAR));
-	  ffvi_buf.ffvi.VolumeSerialNumber = hash_path_name ((ino_t) 0,
-							     &path_prefix);
+	  ffvi_buf.ffvi.VolumeSerialNumber = hash_prefix(upath);
 	}
       fs_info *fsi = fsi_cache.search (&ffvi_buf.ffvi, hash);
       if (fsi)
@@ -460,7 +488,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
 
   if (!in_vol)
     NtClose (vol);
-  fsi_cache.add (hash, this);
+  fsi_cache.add (hash, this, hash_prefix (upath));
   return true;
 }
 
diff --git a/winsup/cygwin/mount.h b/winsup/cygwin/mount.h
index 122a679a8..86b72fb4c 100644
--- a/winsup/cygwin/mount.h
+++ b/winsup/cygwin/mount.h
@@ -124,7 +124,7 @@ class fs_info
 
   const char *fsname () const { return fsn[0] ? fsn : "unknown"; }
 
-  bool __reg3 update (PUNICODE_STRING, HANDLE);
+  bool __reg3 update (PUNICODE_STRING, HANDLE, bool=false);
   bool inited () const { return !!status.flags; }
 };
 
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index f00707e86..9e803f986 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1179,7 +1179,7 @@ path_conv::check (const char *src, unsigned opt,
 	{
 	  /* If FS hasn't been checked already in symlink_info::check,
 	     do so now. */
-	  if (fs.inited ()|| fs.update (get_nt_native_path (), NULL))
+	  if (fs.inited ()|| fs.update (get_nt_native_path (), NULL, opt & PC_FS_USE_PREFIX_HASH))
 	    {
 	      /* Incoming DOS paths are treated like DOS paths in native
 		 Windows applications.  No ACLs, just default settings. */
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index 56855e1c9..b9264811e 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -60,6 +60,7 @@ enum pathconv_arg
   PC_NO_ACCESS_CHECK	 = _BIT (13),	/* helper flag for error check */
   PC_SYM_NOFOLLOW_DIR	 = _BIT (14),	/* don't follow a trailing slash */
   PC_SKIP_SYM_CHECK	 = _BIT (15),	/* skip symlink_info::check */
+  PC_FS_USE_PREFIX_HASH	 = _BIT (16),	/* in fs_info search by prefix hash */
   PC_DONT_USE		 = _BIT (31)	/* conversion to signed happens. */
 };
 
-- 
2.29.2



More information about the Cygwin-patches mailing list