git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/3] Improve the mmap() emulation on Windows
@ 2016-04-22 14:31 Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 1/3] win32mmap: set errno appropriately Johannes Schindelin
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-22 14:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Sven Strickroth

Kevin David reported a problem last October where a simple git fetch
would produce this error output:

	fatal: mmap failed: No error
	fatal: write error: Invalid argument

The reason was that several bits of our mmap() emulation left room for
improvement. These patches fix it, and made it already into Git
for Windows v2.6.2 and have been working without problems ever since.


Johannes Schindelin (3):
  win32mmap: set errno appropriately
  mmap(win32): avoid copy-on-write when it is unnecessary
  mmap(win32): avoid expensive fstat() call

 compat/win32mmap.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

-- 
2.8.1.306.gff998f2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] win32mmap: set errno appropriately
  2016-04-22 14:31 [PATCH 0/3] Improve the mmap() emulation on Windows Johannes Schindelin
@ 2016-04-22 14:31 ` Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 3/3] mmap(win32): avoid expensive fstat() call Johannes Schindelin
  2 siblings, 0 replies; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-22 14:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Sven Strickroth

It is not really helpful when a `git fetch` fails with the message:

	fatal: mmap failed: No error

In the particular instance encountered by a colleague of yours truly,
the Win32 error code was ERROR_COMMITMENT_LIMIT which means that the
page file is not big enough.

Let's make the message

	fatal: mmap failed: File too large

instead, which is only marginally better, but which can be associated
with the appropriate work-around: setting `core.packedGitWindowSize` to
a relatively small value.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32mmap.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 80a8c9a..3a39f0f 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -24,15 +24,21 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
 	hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
 		PAGE_WRITECOPY, 0, 0, NULL);
 
-	if (!hmap)
+	if (!hmap) {
+		errno = EINVAL;
 		return MAP_FAILED;
+	}
 
 	temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
 
 	if (!CloseHandle(hmap))
 		warning("unable to close file mapping handle");
 
-	return temp ? temp : MAP_FAILED;
+	if (temp)
+		return temp;
+
+	errno = GetLastError() == ERROR_COMMITMENT_LIMIT ? EFBIG : EINVAL;
+	return MAP_FAILED;
 }
 
 int git_munmap(void *start, size_t length)
-- 
2.8.1.306.gff998f2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary
  2016-04-22 14:31 [PATCH 0/3] Improve the mmap() emulation on Windows Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 1/3] win32mmap: set errno appropriately Johannes Schindelin
@ 2016-04-22 14:31 ` Johannes Schindelin
  2016-04-26 18:53   ` Johannes Sixt
  2016-04-22 14:31 ` [PATCH 3/3] mmap(win32): avoid expensive fstat() call Johannes Schindelin
  2 siblings, 1 reply; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-22 14:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Sven Strickroth

Often we are mmap()ing read-only. In those cases, it is wasteful to map in
copy-on-write mode. Even worse: it can cause errors where we run out of
space in the page file.

So let's be extra careful to map files in read-only mode whenever
possible.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32mmap.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 3a39f0f..b836169 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -22,14 +22,15 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
 		die("Invalid usage of mmap when built with USE_WIN32_MMAP");
 
 	hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
-		PAGE_WRITECOPY, 0, 0, NULL);
+		prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0, NULL);
 
 	if (!hmap) {
 		errno = EINVAL;
 		return MAP_FAILED;
 	}
 
-	temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
+	temp = MapViewOfFileEx(hmap, prot == PROT_READ ?
+			FILE_MAP_READ : FILE_MAP_COPY, h, l, length, start);
 
 	if (!CloseHandle(hmap))
 		warning("unable to close file mapping handle");
-- 
2.8.1.306.gff998f2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] mmap(win32): avoid expensive fstat() call
  2016-04-22 14:31 [PATCH 0/3] Improve the mmap() emulation on Windows Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 1/3] win32mmap: set errno appropriately Johannes Schindelin
  2016-04-22 14:31 ` [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary Johannes Schindelin
@ 2016-04-22 14:31 ` Johannes Schindelin
  2 siblings, 0 replies; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-22 14:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Sven Strickroth

On Windows, we have to emulate the fstat() call to fill out information
that takes extra effort to obtain, such as the file permissions/type.

If all we want is the file size, we can use the much cheaper
GetFileSizeEx() function (available since Windows XP).

Suggested by Philip Kelley.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32mmap.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index b836169..519d51f 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -2,26 +2,24 @@
 
 void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
 {
-	HANDLE hmap;
+	HANDLE osfhandle, hmap;
 	void *temp;
-	off_t len;
-	struct stat st;
+	LARGE_INTEGER len;
 	uint64_t o = offset;
 	uint32_t l = o & 0xFFFFFFFF;
 	uint32_t h = (o >> 32) & 0xFFFFFFFF;
 
-	if (!fstat(fd, &st))
-		len = st.st_size;
-	else
+	osfhandle = (HANDLE)_get_osfhandle(fd);
+	if (!GetFileSizeEx(osfhandle, &len))
 		die("mmap: could not determine filesize");
 
-	if ((length + offset) > len)
-		length = xsize_t(len - offset);
+	if ((length + offset) > len.QuadPart)
+		length = xsize_t(len.QuadPart - offset);
 
 	if (!(flags & MAP_PRIVATE))
 		die("Invalid usage of mmap when built with USE_WIN32_MMAP");
 
-	hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
+	hmap = CreateFileMapping(osfhandle, NULL,
 		prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0, NULL);
 
 	if (!hmap) {
-- 
2.8.1.306.gff998f2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary
  2016-04-22 14:31 ` [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary Johannes Schindelin
@ 2016-04-26 18:53   ` Johannes Sixt
  2016-04-27  6:43     ` Johannes Schindelin
  0 siblings, 1 reply; 8+ messages in thread
From: Johannes Sixt @ 2016-04-26 18:53 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git, Sven Strickroth

Am 22.04.2016 um 16:31 schrieb Johannes Schindelin:
> Often we are mmap()ing read-only. In those cases, it is wasteful to map in
> copy-on-write mode. Even worse: it can cause errors where we run out of
> space in the page file.
>
> So let's be extra careful to map files in read-only mode whenever
> possible.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>   compat/win32mmap.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/compat/win32mmap.c b/compat/win32mmap.c
> index 3a39f0f..b836169 100644
> --- a/compat/win32mmap.c
> +++ b/compat/win32mmap.c
> @@ -22,14 +22,15 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
>   		die("Invalid usage of mmap when built with USE_WIN32_MMAP");
>
>   	hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
> -		PAGE_WRITECOPY, 0, 0, NULL);
> +		prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0, NULL);

As long as we use this implementation with MAP_PRIVATE, PAGE_WRITECOPY 
is the right setting. Should we insert a check for MAP_PRIVATE to catch 
unexpected use-cases (think of the index-helper daemon effort)?

>
>   	if (!hmap) {
>   		errno = EINVAL;
>   		return MAP_FAILED;
>   	}
>
> -	temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
> +	temp = MapViewOfFileEx(hmap, prot == PROT_READ ?
> +			FILE_MAP_READ : FILE_MAP_COPY, h, l, length, start);

Same here: FILE_MAP_COPY is the right choice for MAP_SHARED mmaps.

>
>   	if (!CloseHandle(hmap))
>   		warning("unable to close file mapping handle");
>

Except for these mental notes, I've no comments on this series. Looks good.

-- Hannes

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary
  2016-04-26 18:53   ` Johannes Sixt
@ 2016-04-27  6:43     ` Johannes Schindelin
  2016-04-27 18:51       ` Johannes Sixt
  0 siblings, 1 reply; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-27  6:43 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: Junio C Hamano, git, Sven Strickroth

Hi Hannes,

On Tue, 26 Apr 2016, Johannes Sixt wrote:

> Am 22.04.2016 um 16:31 schrieb Johannes Schindelin:
> > Often we are mmap()ing read-only. In those cases, it is wasteful to map in
> > copy-on-write mode. Even worse: it can cause errors where we run out of
> > space in the page file.
> >
> > So let's be extra careful to map files in read-only mode whenever
> > possible.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >   compat/win32mmap.c | 5 +++--
> >   1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/compat/win32mmap.c b/compat/win32mmap.c
> > index 3a39f0f..b836169 100644
> > --- a/compat/win32mmap.c
> > +++ b/compat/win32mmap.c
> > @@ -22,14 +22,15 @@ void *git_mmap(void *start, size_t length, int prot, int
> > flags, int fd, off_t of
> >     die("Invalid usage of mmap when built with USE_WIN32_MMAP");
> >
> >   	hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
> > -		PAGE_WRITECOPY, 0, 0, NULL);
> > +		prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0,
> > NULL);
> 
> As long as we use this implementation with MAP_PRIVATE, PAGE_WRITECOPY
> is the right setting. Should we insert a check for MAP_PRIVATE to catch
> unexpected use-cases (think of the index-helper daemon effort)?

I agree, we should have such a check. The line above the `die("Invalid
usage ...")` that you can read as first line in above-quoted hunk reads:

	if (!(flags & MAP_PRIVATE))

So I think we're fine :-)

And yes, I am worrying about the index-helper support, too: I need this
myself, so I will have to make mmap() work for that use case, too. But
that is a story for another day ;-)

> >    if (!hmap) {
> >     errno = EINVAL;
> >     return MAP_FAILED;
> >    }
> >
> > -	temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
> > +	temp = MapViewOfFileEx(hmap, prot == PROT_READ ?
> > +			FILE_MAP_READ : FILE_MAP_COPY, h, l, length, start);
> 
> Same here: FILE_MAP_COPY is the right choice for MAP_SHARED mmaps.

I agree ;-)

> >    if (!CloseHandle(hmap))
> >     warning("unable to close file mapping handle");
> >
> 
> Except for these mental notes, I've no comments on this series. Looks good.

Thanks for reviewing!

Do you think we should add a note to the commit message that we'll have to
do something about this when MAP_PRIVATE is not the only way mmap() will
be used?

I am torn: on the one hand, it is the appropriate thing to do, on the
other hand, it is easy to forget such notes in commit messages. On the
third hand, I hope to find time to work on the index-helper this week,
meaning that I will still know about this when touching
compat/win32mmap.c.

So maybe I can just leave things as are here, and focus on the
index-helper?

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary
  2016-04-27  6:43     ` Johannes Schindelin
@ 2016-04-27 18:51       ` Johannes Sixt
  2016-04-28  8:03         ` Johannes Schindelin
  0 siblings, 1 reply; 8+ messages in thread
From: Johannes Sixt @ 2016-04-27 18:51 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git, Sven Strickroth

Am 27.04.2016 um 08:43 schrieb Johannes Schindelin:
> On Tue, 26 Apr 2016, Johannes Sixt wrote:
>> Should we insert a check for MAP_PRIVATE to catch
>> unexpected use-cases (think of the index-helper daemon effort)?
>
> I agree, we should have such a check. The line above the `die("Invalid
> usage ...")` that you can read as first line in above-quoted hunk reads:
>
> 	if (!(flags & MAP_PRIVATE))
>
> So I think we're fine :-)

Oh, well... I thought I had checked the code before I wrote my question, 
but it seems I was blind... ;)

Thanks,
-- Hannes

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary
  2016-04-27 18:51       ` Johannes Sixt
@ 2016-04-28  8:03         ` Johannes Schindelin
  0 siblings, 0 replies; 8+ messages in thread
From: Johannes Schindelin @ 2016-04-28  8:03 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: Junio C Hamano, git, Sven Strickroth

Hi Hannes,

On Wed, 27 Apr 2016, Johannes Sixt wrote:

> Am 27.04.2016 um 08:43 schrieb Johannes Schindelin:
> > On Tue, 26 Apr 2016, Johannes Sixt wrote:
> > > Should we insert a check for MAP_PRIVATE to catch
> > > unexpected use-cases (think of the index-helper daemon effort)?
> >
> > I agree, we should have such a check. The line above the `die("Invalid
> > usage ...")` that you can read as first line in above-quoted hunk reads:
> >
> >  if (!(flags & MAP_PRIVATE))
> >
> > So I think we're fine :-)
> 
> Oh, well... I thought I had checked the code before I wrote my question, but
> it seems I was blind... ;)

Don't worry! I really appreciate your review!

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-04-28  8:03 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-22 14:31 [PATCH 0/3] Improve the mmap() emulation on Windows Johannes Schindelin
2016-04-22 14:31 ` [PATCH 1/3] win32mmap: set errno appropriately Johannes Schindelin
2016-04-22 14:31 ` [PATCH 2/3] mmap(win32): avoid copy-on-write when it is unnecessary Johannes Schindelin
2016-04-26 18:53   ` Johannes Sixt
2016-04-27  6:43     ` Johannes Schindelin
2016-04-27 18:51       ` Johannes Sixt
2016-04-28  8:03         ` Johannes Schindelin
2016-04-22 14:31 ` [PATCH 3/3] mmap(win32): avoid expensive fstat() call Johannes Schindelin

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).