Re: [PATCH 09/11] mount.cc: Implement poor-man's cache
On Feb 3 12:38, Ben wrote: > > > On 18-01-2021 12:51, Corinna Vinschen via Cygwin-patches wrote: > > Ok, so hash_prefix reduces the path to a drive letter or the UNC path > > prefix and hashes it. However, what about partitions mounted to a > > subdir of, say, drive C? In that case the hashing goes awry, because > > you're comparing with the hash of drive C while the path is actually > > pointing to another partition. > > > How can I mount a partition as a subdir of drive C? > For some reason I can't: > $ mount /cygdrive/e/Temp/dummy /cygdrive/c/Temp/dummy/dummyone > mount: /cygdrive/c/Temp/dummy/dummyone: Invalid argument I wasn't talking about Cygwin mount points, but rather about Windows mount points. Since Windows 2000 a partition can be mounted into a directory of another partition. Only drive C: (ignoring non-harddisks) has to be mounted with a drive letter, all others can be mounted just as on Unix. But, yeah, Cygwin also supports bind mounts. Here's an example from my /etc/fstab.d user mount file: //remote/cygwin-src /cygwin nfs binary 0 0 /cygwin/pub /home/pub nfs bind 0 0 Corinna
Re: [PATCH 09/11] mount.cc: Implement poor-man's cache
On 18-01-2021 12:51, Corinna Vinschen via Cygwin-patches wrote: > Ok, so hash_prefix reduces the path to a drive letter or the UNC path > prefix and hashes it. However, what about partitions mounted to a > subdir of, say, drive C? In that case the hashing goes awry, because > you're comparing with the hash of drive C while the path is actually > pointing to another partition. > How can I mount a partition as a subdir of drive C? For some reason I can't: $ mount /cygdrive/e/Temp/dummy /cygdrive/c/Temp/dummy/dummyone mount: /cygdrive/c/Temp/dummy/dummyone: Invalid argument
Re: [PATCH 09/11] mount.cc: Implement poor-man's cache
On Jan 15 14:45, Ben Wijen wrote: > 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); > +} > + Ok, so hash_prefix reduces the path to a drive letter or the UNC path prefix and hashes it. However, what about partitions mounted to a subdir of, say, drive C? In that case the hashing goes awry, because you're comparing with the hash of drive C while the path is actually pointing to another partition. > @@ -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); Please note that we did this *only* for border case FSes returning a VSN of 0. This was sufficient for these cases, but not in a a general sense. Corinna
[PATCH 09/11] mount.cc: Implement poor-man's cache
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] ? f