This is the mail archive of the cygwin-patches mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 3/6] forkables: Create forkable hardlinks, yet unused.


(sorry about previous empty mail)

Hi Corinna,

This is a fixup for the race condition where multiple processes failed
to concurrently create identical hardlinks.

So I'm quite successful with the forkable hardlinks now...

/haubi/


On 03/30/2016 08:53 PM, Michael Haubenwallner wrote:
> In preparation to protect fork() against dll- and exe-updates, create
> hardlinks to the main executable and each loaded dll in subdirectories
> of /var/run/cygfork/, if that one exists on the NTFS file system.
> 
> The directory names consist of the user sid, the main executable's NTFS
> IndexNumber, and the most recent LastWriteTime of all involved binaries
> (dlls and main executable).  Next to the main.exe hardlink we create the
> empty file main.exe.local to enable dll redirection.
> 
> The name of the mutex to synchronize hardlink creation/cleanup also is
> assembled from these directory names, to allow for synchronized cleanup
> of even orphaned hardlink directories.
> 
> The hardlink to each dynamically loaded dll goes into another directory,
> named using the NTFS IndexNumber of the dll's original directory.
> 
> 	* dll_init.h (struct dll): Declare member variables fbi, fii,
> 	forkable_ntname.  Declare methods nominate_forkable,
> 	create_forkable.  Define inline method forkedntname.
> 	(struct dll_list): Declare enum forkables_needs.  Declare member
> 	variables forkables_dirx_size, forkables_dirx_ntname,
> 	forkables_mutex_name, forkables_mutex.  Declare private methods
> 	forkable_ntnamesize, prepare_forkables_nomination,
> 	update_forkables_needs, update_forkables, create_forkables,
> 	denominate_forkables, close_mutex, try_remove_forkables.
> 	Declare public method cleanup_forkables.
> 	* dll_init.cc (dll_list::alloc): Allocate memory to hold the
> 	name of the hardlink in struct dll member forkable_ntname.
> 	Initialize struct dll members fbi, fii.
> 	* forkable.cc: Implement static functions mkdirs, rmdirs,
> 	rmdirs_synchronized, read_fii, read_fbi, format_IndexNumber,
> 	rootname, sidname, exename, lwtimename.  Define static array
> 	forkable_nameparts.
> 	(struct dll): Implement nominate_forkable, create_forkable.
> 	(struct dll_list): Implement forkable_ntnamesize,
> 	prepare_forkables_nomination, update_forkables_needs,
> 	update_forkables, create_forkables, close_mutex,
> 	cleanup_forkables, try_remove_forkables, denominate_forkables.
> 	(dll_list::set_forkables_inheritance): Also for forkables_mutex.
> 	(dll_list::request_forkables): Use new methods to create the
> 	hardlinks as necessary.
> 	(dll_list::release_forkables): When hardlink creation turned out
> 	to be impossible, close all the related handles and free the
> 	distinct memory.
> 	* pinfo.cc (pinfo::exit): Call dlls.cleanup_forkables.
> 	* syscalls.cc (_unlink_nt): Rename public unlink_nt function to
> 	static _unlink_nt, with 'shareable' as additional argument.
> 	(unlink_nt): New, wrap _unlink_nt for original behaviour.
> 	(unlink_nt_shareable): New, wrap _unlink_nt to keep a binary
> 	file still loadable while removing one of its hardlinks.
> ---
>  winsup/cygwin/dll_init.cc |   28 +-
>  winsup/cygwin/dll_init.h  |   33 ++
>  winsup/cygwin/forkable.cc | 1036 +++++++++++++++++++++++++++++++++++++++++++++
>  winsup/cygwin/pinfo.cc    |    3 +
>  winsup/cygwin/syscalls.cc |   24 +-
>  5 files changed, 1115 insertions(+), 9 deletions(-)

>From 7a824877dbfe2aee0437378a52b8946000a38cbe Mon Sep 17 00:00:00 2001
From: Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
Date: Fri, 11 Nov 2016 14:29:21 +0100
Subject: [PATCH] forkables: fix creating dirs and .local file in parallel

---
 winsup/cygwin/forkable.cc | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/winsup/cygwin/forkable.cc b/winsup/cygwin/forkable.cc
index 0a8a528..b712834 100644
--- a/winsup/cygwin/forkable.cc
+++ b/winsup/cygwin/forkable.cc
@@ -65,14 +65,14 @@ mkdirs (PWCHAR ntdirname, int lastsepcount)
 	  IO_STATUS_BLOCK iosb;
 	  status = NtCreateFile (&dh, GENERIC_READ | SYNCHRONIZE,
 				 &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL,
-				 FILE_SHARE_READ,
-				 FILE_OPEN_IF, /* allow concurrency */
+				 FILE_SHARE_READ | FILE_SHARE_WRITE,
+				 FILE_CREATE,
 				 FILE_DIRECTORY_FILE
 				 | FILE_SYNCHRONOUS_IO_NONALERT,
 				 NULL, 0);
 	  if (NT_SUCCESS(status))
 	    NtClose (dh);
-	  else
+	  else if (status != STATUS_OBJECT_NAME_COLLISION) /* already exists */
 	    success = false;
 	  debug_printf ("%y = NtCreateFile (%p, dir %W)", status, dh, ntdirname);
 	}
@@ -806,14 +806,14 @@ dll_list::create_forkables ()
       IO_STATUS_BLOCK iosb;
       status = NtCreateFile (&hlocal, GENERIC_WRITE | SYNCHRONIZE,
 			     &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL,
-			     FILE_SHARE_READ,
-			     FILE_OPEN_IF, /* allow concurrency */
+			     FILE_SHARE_READ | FILE_SHARE_WRITE,
+			     FILE_CREATE,
 			     FILE_NON_DIRECTORY_FILE
 			     | FILE_SYNCHRONOUS_IO_NONALERT,
 			     NULL, 0);
       if (NT_SUCCESS (status))
 	CloseHandle (hlocal);
-      else
+      else if (status != STATUS_OBJECT_NAME_COLLISION) /* already exists */
 	success = false;
       debug_printf ("%y = NtCreateFile (%p, %W)", status, hlocal, ntname);
     }
@@ -874,7 +874,10 @@ rmdirs_synchronized (WCHAR ntbuf[NT_MAX_PATH], int depth, int maxdepth,
       if (mutex)
 	{
 	  if (lasterror != ERROR_ALREADY_EXISTS)
-	    rmdirs (ntbuf);
+	    {
+	      debug_printf ("cleaning up for mutex %W", mutexname);
+	      rmdirs (ntbuf);
+	    }
 	  BOOL bret = CloseHandle (mutex);
 	  debug_printf ("%d = CloseHandle (%p, %W): %E",
 			bret, mutex, mutexname);
-- 
2.8.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]