[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