[RFC PATCH 5/5] server: Support mounting a FUSE overlayfs on drive_c.

Rémi Bernon rbernon at codeweavers.com
Mon Mar 30 07:24:30 CDT 2020


This uses fuse-overlayfs [1] to stack layers under drive_c and save some
space. It is then possible to have a default wine prefix that will be
used as a read-only base for other wine prefixes, with only the new or
modified files saved into the upper dir.

The overlayfs is automatically mounted by the server on startup, and
unmount is requested when the server exits. If fuse-overlayfs fails for
any reason, it should fallback to normal prefix and the upper dir will
be updated.

The lower dirs are controlled by the WINEPREFIX_OVERLAYS environment
variable, which is passed as is after -olowerdir= to fuse-overlayfs. It
supports multiple layers, separated by a colon, from top to bottom.

Any other option supported by fuse-overlayfs can also be used and passed
after the lower dirs in WINEPREFIX_OVERLAYS, separated from them with
comma - for example uidmapping/gidmapping.

[1] https://github.com/containers/fuse-overlayfs
---
 server/main.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/server/main.c b/server/main.c
index 26986d34b305..00c4c56542e5 100644
--- a/server/main.c
+++ b/server/main.c
@@ -31,6 +31,9 @@
 #ifdef HAVE_GETOPT_H
 # include <getopt.h>
 #endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
 
 #include "object.h"
 #include "file.h"
@@ -124,6 +127,73 @@ static void sigterm_handler( int signum )
     exit(1);  /* make sure atexit functions get called */
 }
 
+static void detach_overlays(void)
+{
+    const char *config_dir = getenv( "WINEPREFIX" );
+    char *argv[] = {NULL, NULL, NULL, NULL};
+    int pid;
+
+    pid = fork();
+    if (pid == -1) fatal_error( "fork" );
+    if (!pid)
+    {
+        argv[0] = strdup( "fusermount" );
+        argv[1] = strdup( "-u" );
+
+        argv[2] = malloc( sizeof("/drive_c") + strlen( config_dir ) );
+        strcpy( argv[2], config_dir );
+        strcat( argv[2], "/drive_c" );
+
+        execvp( argv[0], argv );
+        fatal_error( "could not exec fusermount\n" );
+    }
+}
+
+static void mount_overlays(void)
+{
+    char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};
+    const char *config_dir = getenv( "WINEPREFIX" );
+    const char *overlays = getenv( "WINEPREFIX_OVERLAYS" );
+    int status;
+    int pid;
+
+    if (!overlays) return;
+
+    pid = fork();
+    if (pid == -1) fatal_error( "fork" );
+    if (!pid)
+    {
+        argv[0] = strdup( "fuse-overlayfs" );
+
+        argv[1] = malloc( sizeof("-olowerdir=") + strlen( overlays ) );
+        strcpy( argv[1], "-olowerdir=" );
+        strcat( argv[1], overlays );
+
+        argv[2] = malloc( sizeof("-oupperdir=/drive_c") + strlen( config_dir ) );
+        strcpy( argv[2], "-oupperdir=" );
+        strcat( argv[2], config_dir );
+        strcat( argv[2], "/drive_c" );
+
+        argv[3] = malloc( sizeof("-oworkdir=") + strlen( config_dir ) );
+        strcpy( argv[3], "-oworkdir=" );
+        strcat( argv[3], config_dir );
+
+        argv[4] = malloc( sizeof("/drive_c") + strlen( config_dir ) );
+        strcpy( argv[4], config_dir );
+        strcat( argv[4], "/drive_c" );
+
+        execvp( argv[0], argv );
+        fatal_error( "could not exec fuse-overlayfs\n" );
+    }
+
+    do waitpid( pid, &status, 0 );
+    while (!WIFEXITED(status));
+
+    if (WEXITSTATUS(status) != 0)
+        fatal_error( "fuse-overlayfs failed\n" );
+    atexit( detach_overlays );
+}
+
 int main( int argc, char *argv[] )
 {
     setvbuf( stderr, NULL, _IOLBF, 0 );
@@ -139,6 +209,7 @@ int main( int argc, char *argv[] )
 
     sock_init();
     open_master_socket();
+    mount_overlays();
 
     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
     init_signals();
-- 
2.26.0.rc2




More information about the wine-devel mailing list