From f65c5a0a2b1728ce2b317b31b601574f1ef7f5b2 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 10 Sep 2010 10:04:28 +0000 Subject: [PATCH] * mount.cc (class fs_info_cache): New class to cache filesystem information. (fs_info::update): Check FileFsVolumeInformation against filesystem cache and use it, if filesystem is already available. Add filesystem to cache, if not. Only request FileFsObjectIdInformation if FILE_SUPPORTS_OBJECT_IDS is set in filesystem flags. * ntdll.h (struct _FILE_FS_VOLUME_INFORMATION): Add pragma pack so the structure size is matching the OS expectations. Add __dummy member used in filesystem cache. --- winsup/cygwin/ChangeLog | 12 ++++++ winsup/cygwin/mount.cc | 82 ++++++++++++++++++++++++++++++++++++++--- winsup/cygwin/ntdll.h | 3 ++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb15dd325..521b4cd4c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2010-09-10 Corinna Vinschen + + * mount.cc (class fs_info_cache): New class to cache filesystem + information. + (fs_info::update): Check FileFsVolumeInformation against filesystem + cache and use it, if filesystem is already available. Add filesystem + to cache, if not. Only request FileFsObjectIdInformation if + FILE_SUPPORTS_OBJECT_IDS is set in filesystem flags. + * ntdll.h (struct _FILE_FS_VOLUME_INFORMATION): Add pragma pack so the + structure size is matching the OS expectations. Add __dummy member + used in filesystem cache. + 2010-09-10 Corinna Vinschen * security.cc (get_file_sd): Add bool parameter justcreated. Use diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 0117b43b1..8ea1b6295 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -105,6 +105,64 @@ struct smb_extended_info { }; #pragma pack(pop) +#define MAX_FS_INFO_CNT 32 +class fs_info_cache +{ + static muto fsi_lock; + uint32_t count; + struct { + fs_info fsi; + uint32_t 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 (PFILE_FS_VOLUME_INFORMATION, uint32_t &); + void add (uint32_t, fs_info *); +}; + +static fs_info_cache fsi_cache; +muto NO_COPY fs_info_cache::fsi_lock; + +uint32_t +fs_info_cache::genhash (PFILE_FS_VOLUME_INFORMATION pffvi) +{ + uint32_t hash = 0; + const uint16_t *p = (const uint16_t *) pffvi; + const uint16_t *end = (const uint16_t *) + ((const uint8_t *) p + sizeof *pffvi + + pffvi->VolumeLabelLength - sizeof (WCHAR)); + pffvi->__dummy = 0; /* This member can have random values! */ + while (p < end) + hash = *p++ + (hash << 6) + (hash << 16) - hash; + return hash; +} + +fs_info * +fs_info_cache::search (PFILE_FS_VOLUME_INFORMATION pffvi, uint32_t &hash) +{ + hash = genhash (pffvi); + for (uint32_t i = 0; i < count; ++i) + if (entry[i].hash == hash) + return &entry[i].fsi; + return NULL; +} + +void +fs_info_cache::add (uint32_t hashval, fs_info *new_fsi) +{ + fsi_lock.acquire (); + if (count < MAX_FS_INFO_CNT) + { + entry[count].fsi = *new_fsi; + entry[count].hash = hashval; + ++count; + } + fsi_lock.release (); +} + bool fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) { @@ -172,11 +230,23 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) return false; } } - + sernum = 0; status = NtQueryVolumeInformationFile (vol, &io, &ffvi_buf.ffvi, sizeof ffvi_buf, FileFsVolumeInformation); - sernum = NT_SUCCESS (status) ? ffvi_buf.ffvi.VolumeSerialNumber : 0; + uint32_t hash = 0; + if (NT_SUCCESS (status)) + { + fs_info *fsi = fsi_cache.search (&ffvi_buf.ffvi, hash); + if (fsi) + { + *this = *fsi; + if (!in_vol) + NtClose (vol); + return true; + } + sernum = ffvi_buf.ffvi.VolumeSerialNumber; + } status = NtQueryVolumeInformationFile (vol, &io, &ffdi, sizeof ffdi, FileFsDeviceInformation); if (!NT_SUCCESS (status)) @@ -253,9 +323,10 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) #define FS_IS_WINDOWS_FAT TEST_GVI(flags (), WIN_FAT_FLAGS) /* This always fails on NT4. */ - status = NtQueryVolumeInformationFile (vol, &io, &ffoi, sizeof ffoi, - FileFsObjectIdInformation); - if (NT_SUCCESS (status)) + if ((flags () & FILE_SUPPORTS_OBJECT_IDS) + && NT_SUCCESS (NtQueryVolumeInformationFile (vol, &io, &ffoi, + sizeof ffoi, + FileFsObjectIdInformation))) { smb_extended_info *extended_info = (smb_extended_info *) &ffoi.ExtendedInfo; @@ -355,6 +426,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) if (!in_vol) NtClose (vol); + fsi_cache.add (hash, this); return true; } diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 5c6eb53c2..f707cd28d 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -751,14 +751,17 @@ typedef struct _FILE_FS_ATTRIBUTE_INFORMATION WCHAR FileSystemName[1]; } FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; +#pragma pack(push,4) typedef struct _FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; ULONG VolumeSerialNumber; ULONG VolumeLabelLength; BOOLEAN SupportsObjects; + BOOLEAN __dummy; WCHAR VolumeLabel[1]; } FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; +#pragma pack(pop) typedef struct _FILE_FS_SIZE_INFORMATION {