cygwin: readdir: don't lookup mount target inodes

So far Cygwin's readdir returned the inode number of a mount target
in d_ino, rather than the actual inode number of the mount point in
the underlying filesystem.  This not only results in a performance
hit if the mount target is a remote FS, it is also not done on other
POSIX systems.

Remove the code evaluating the mount target inode number.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2017-06-14 13:22:56 +02:00
parent 0a9edd73e3
commit 8eada33223
1 changed files with 30 additions and 41 deletions

View File

@ -28,6 +28,12 @@ details. */
#define _COMPILING_NEWLIB #define _COMPILING_NEWLIB
#include <dirent.h> #include <dirent.h>
enum __DIR_mount_type {
__DIR_mount_none = 0,
__DIR_mount_target,
__DIR_mount_virt_target
};
class __DIR_mounts class __DIR_mounts
{ {
int count; int count;
@ -41,23 +47,6 @@ class __DIR_mounts
#define __DIR_CYGDRIVE (MAX_MOUNTS+1) #define __DIR_CYGDRIVE (MAX_MOUNTS+1)
#define __DIR_DEV (MAX_MOUNTS+2) #define __DIR_DEV (MAX_MOUNTS+2)
ino_t eval_ino (int idx)
{
ino_t ino = 0;
char fname[parent_dir_len + mounts[idx].Length + 2];
struct stat st;
char *c = stpcpy (fname, parent_dir);
if (c[- 1] != '/')
*c++ = '/';
sys_wcstombs (c, mounts[idx].Length + 1,
mounts[idx].Buffer, mounts[idx].Length / sizeof (WCHAR));
path_conv pc (fname, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE);
if (!stat_worker (pc, &st))
ino = st.st_ino;
return ino;
}
public: public:
__DIR_mounts (const char *posix_path) __DIR_mounts (const char *posix_path)
: parent_dir (posix_path) : parent_dir (posix_path)
@ -73,48 +62,47 @@ public:
RtlFreeUnicodeString (&mounts[i]); RtlFreeUnicodeString (&mounts[i]);
RtlFreeUnicodeString (&cygdrive); RtlFreeUnicodeString (&cygdrive);
} }
ino_t check_mount (PUNICODE_STRING fname, ino_t ino, /* For an entry within this dir, check if a mount point exists. */
bool eval = true) bool check_mount (PUNICODE_STRING fname)
{ {
if (parent_dir_len == 1) /* root dir */ if (parent_dir_len == 1) /* root dir */
{ {
if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE)) if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE))
{ {
found[__DIR_PROC] = true; found[__DIR_PROC] = true;
return 2; return true;
} }
if (RtlEqualUnicodeString (fname, &ro_u_dev, FALSE)) if (RtlEqualUnicodeString (fname, &ro_u_dev, FALSE))
{ {
found[__DIR_DEV] = true; found[__DIR_DEV] = true;
return 2; return true;
} }
if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2 if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2
&& RtlEqualUnicodeString (fname, &cygdrive, FALSE)) && RtlEqualUnicodeString (fname, &cygdrive, FALSE))
{ {
found[__DIR_CYGDRIVE] = true; found[__DIR_CYGDRIVE] = true;
return 2; return true;
} }
} }
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
if (RtlEqualUnicodeString (fname, &mounts[i], FALSE)) if (RtlEqualUnicodeString (fname, &mounts[i], FALSE))
{ {
found[i] = true; found[i] = true;
return eval ? eval_ino (i) : 1; return true;
} }
return ino; return false;
} }
ino_t check_missing_mount (PUNICODE_STRING retname = NULL) /* On each call, add another mount point within this directory, which is
not backed by a real subdir. */
__DIR_mount_type check_missing_mount (PUNICODE_STRING retname = NULL)
{ {
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
if (!found[i]) if (!found[i])
{ {
found[i] = true; found[i] = true;
if (retname) if (retname)
{ *retname = mounts[i];
*retname = mounts[i]; return __DIR_mount_target;
return eval_ino (i);
}
return 1;
} }
if (parent_dir_len == 1) /* root dir */ if (parent_dir_len == 1) /* root dir */
{ {
@ -123,14 +111,14 @@ public:
found[__DIR_PROC] = true; found[__DIR_PROC] = true;
if (retname) if (retname)
*retname = ro_u_proc; *retname = ro_u_proc;
return 2; return __DIR_mount_virt_target;
} }
if (!found[__DIR_DEV]) if (!found[__DIR_DEV])
{ {
found[__DIR_DEV] = true; found[__DIR_DEV] = true;
if (retname) if (retname)
*retname = ro_u_dev; *retname = ro_u_dev;
return 2; return __DIR_mount_virt_target;
} }
if (!found[__DIR_CYGDRIVE]) if (!found[__DIR_CYGDRIVE])
{ {
@ -139,11 +127,11 @@ public:
{ {
if (retname) if (retname)
*retname = cygdrive; *retname = cygdrive;
return 2; return __DIR_mount_virt_target;
} }
} }
} }
return 0; return __DIR_mount_none;
} }
void rewind () { memset (found, 0, sizeof found); } void rewind () { memset (found, 0, sizeof found); }
}; };
@ -1989,16 +1977,17 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
{ {
if (w32_err) if (w32_err)
{ {
bool added = false; switch (d_mounts (dir)->check_missing_mount (fname))
if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname)))
added = true;
if (!added)
{ {
case __DIR_mount_none:
fname->Length = 0; fname->Length = 0;
return geterrno_from_win_error (w32_err); return geterrno_from_win_error (w32_err);
case __DIR_mount_virt_target:
de->d_type = DT_DIR;
break;
default:
break;
} }
if (de->d_ino == 2) /* Inode number for virtual dirs. */
de->d_type = DT_DIR;
attr = 0; attr = 0;
dir->__flags &= ~dirent_set_d_ino; dir->__flags &= ~dirent_set_d_ino;
} }
@ -2216,7 +2205,7 @@ go_ahead:
((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes; ((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes;
} }
RtlInitCountedUnicodeString (&fname, FileName, FileNameLength); RtlInitCountedUnicodeString (&fname, FileName, FileNameLength);
de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino); d_mounts (dir)->check_mount (&fname);
if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino)) if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
{ {
/* Don't try to optimize relative to dir->__d_position. On several /* Don't try to optimize relative to dir->__d_position. On several