From: Matthew Dillon Date: Fri, 8 Jul 2011 23:05:42 +0000 (-0700) Subject: vkernel - enhance the pidfile option and fix memimg file scanning X-Git-Tag: v2.12.0~368 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/bc3cc25e9d9f4d967ae2ae3a552e42af0dd32ea1 vkernel - enhance the pidfile option and fix memimg file scanning * Enhance the pidfile option to leave the file descriptor open and hold an active lock on the pidfile while the vkernel is running. This allows scripts to test whether the pidfile is real or stale. * When scanning for memimg files only stop if we are unable to create a new file. Skip files owned by other users instead of giving up. * Adjust the vkernel manual page to document the pidfile feature. Also document that -I can take a vknetd socket path. --- diff --git a/share/man/man7/vkernel.7 b/share/man/man7/vkernel.7 index 8ad53ffae3..1d0e6ba6f1 100644 --- a/share/man/man7/vkernel.7 +++ b/share/man/man7/vkernel.7 @@ -54,7 +54,7 @@ .Op Fl l Ar cpulock .Op Fl m Ar size .Op Fl n Ar numcpus -.Op Fl p Ar file +.Op Fl p Ar pidfile .Op Fl r Ar file .Sh DESCRIPTION The @@ -110,10 +110,13 @@ The .Ar interface argument is the name of a .Xr tap 4 -device node. +device node or the path to a +.Xr vknetd 8 +socket. The .Pa /dev/ -path prefix does not have to be specified and will be automatically prepended. +path prefix does not have to be specified and will be automatically prepended +for a device node. Specifying .Cm auto will pick the first unused @@ -145,6 +148,12 @@ address is not assigned until the interface is brought up in the guest. The .Ar netmask argument applies to all interfaces for which an address is specified. +.Pp +When running multiple vkernels it is often more convenient to simply +connect to a +.Xr vknetd 8 +socket and let vknetd deal with the tap and/or bridge. An example of +this would be '/var/run/vknet:0.0.0.0:10.2.0.2/16'. .It Fl l Ar cpulock Specify which, if any, real CPUs to lock virtual CPUs to. .Ar cpulock @@ -186,9 +195,21 @@ Up to 16 CPUs are supported. The virtual kernel must be built with .Cd options SMP to use this option and will default to 2 CPUs unless otherwise specified. -.It Fl p Ar file -Specify a file in which to store the process ID. -A warning is issued if this file cannot be opened for writing. +.It Fl p Ar pidfile +Specify a pidfile in which to store the process ID. +Scripts can use this file to locate the vkernel pid for the purpose of +shutting down or killing it. +.Pp +The vkernel will hold a lock on the pidfile while running. +Scripts may test for the lock to determine if the pidfile is valid or +stale so as to avoid accidently killing a random process. +Something like '/usr/bin/lockf -ks -t 0 pidfile echo -n' may be used +to test the lock. +A non-zero exit code indicates that the pidfile represents a running +vkernel. +.Pp +An error is issued and the vkernel exits if this file cannot be opened for +writing or if it is already locked by an active vkernel process. .It Fl r Ar file Specify a R/W disk image .Ar file diff --git a/sys/platform/vkernel/platform/init.c b/sys/platform/vkernel/platform/init.c index 3f46fc81f7..dc9fb9e854 100644 --- a/sys/platform/vkernel/platform/init.c +++ b/sys/platform/vkernel/platform/init.c @@ -380,7 +380,6 @@ init_sys_memory(char *imageFile) * Figure out the system memory image size. If an image file was * specified and -m was not specified, use the image file's size. */ - if (imageFile && stat(imageFile, &st) == 0 && Maxmem_bytes == 0) Maxmem_bytes = (vm_paddr_t)st.st_size; if ((imageFile == NULL || stat(imageFile, &st) < 0) && @@ -405,13 +404,18 @@ init_sys_memory(char *imageFile) * Generate an image file name if necessary, then open/create the * file exclusively locked. Do not allow multiple virtual kernels * to use the same image file. + * + * Don't iterate through a million files if we do not have write + * access to the directory, stop if our open() failed on a + * non-existant file. Otherwise opens can fail for any number + * of reasons (lock failed, file not owned or writable by us, etc). */ if (imageFile == NULL) { for (i = 0; i < 1000000; ++i) { asprintf(&imageFile, "/var/vkernel/memimg.%06d", i); fd = open(imageFile, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644); - if (fd < 0 && errno == EWOULDBLOCK) { + if (fd < 0 && stat(imageFile, &st) == 0) { free(imageFile); continue; } @@ -1221,24 +1225,34 @@ init_netif(char *netifExp[], int netifExpNum) close(s); } +/* + * Create the pid file and leave it open and locked while the vkernel is + * running. This allows a script to use /usr/bin/lockf to probe whether + * a vkernel is still running (so as not to accidently kill an unrelated + * process from a stale pid file). + */ static void -writepid( void ) +writepid(void) { - pid_t self; - FILE *fp; + char buf[32]; + int fd; if (pid_file != NULL) { - self = getpid(); - fp = fopen(pid_file, "w"); - - if (fp != NULL) { - fprintf(fp, "%ld\n", (long)self); - fclose(fp); - } - else { - perror("Warning: couldn't open pidfile"); + snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); + fd = open(pid_file, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0666); + if (fd < 0) { + if (errno == EWOULDBLOCK) { + perror("Failed to lock pidfile, " + "vkernel already running"); + } else { + perror("Failed to create pidfile"); + } + exit(EX_SOFTWARE); } + ftruncate(fd, 0); + write(fd, buf, strlen(buf)); + /* leave the file open to maintain the lock */ } } @@ -1247,7 +1261,7 @@ void cleanpid( void ) { if (pid_file != NULL) { - if ( unlink(pid_file) != 0 ) + if (unlink(pid_file) < 0) perror("Warning: couldn't remove pidfile"); } } diff --git a/sys/platform/vkernel64/platform/init.c b/sys/platform/vkernel64/platform/init.c index ad6af1721a..33ed964706 100644 --- a/sys/platform/vkernel64/platform/init.c +++ b/sys/platform/vkernel64/platform/init.c @@ -379,7 +379,6 @@ init_sys_memory(char *imageFile) * Figure out the system memory image size. If an image file was * specified and -m was not specified, use the image file's size. */ - if (imageFile && stat(imageFile, &st) == 0 && Maxmem_bytes == 0) Maxmem_bytes = (vm_paddr_t)st.st_size; if ((imageFile == NULL || stat(imageFile, &st) < 0) && @@ -404,13 +403,17 @@ init_sys_memory(char *imageFile) * Generate an image file name if necessary, then open/create the * file exclusively locked. Do not allow multiple virtual kernels * to use the same image file. + * + * Don't iterate through a million files if we do not have write + * access to the directory, stop if our open() failed on a + * non-existant file. Otherwise opens can fail for any number */ if (imageFile == NULL) { for (i = 0; i < 1000000; ++i) { asprintf(&imageFile, "/var/vkernel/memimg.%06d", i); fd = open(imageFile, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644); - if (fd < 0 && errno == EWOULDBLOCK) { + if (fd < 0 && stat(imageFile, &st) == 0) { free(imageFile); continue; } @@ -1185,24 +1188,34 @@ init_netif(char *netifExp[], int netifExpNum) close(s); } +/* + * Create the pid file and leave it open and locked while the vkernel is + * running. This allows a script to use /usr/bin/lockf to probe whether + * a vkernel is still running (so as not to accidently kill an unrelated + * process from a stale pid file). + */ static void -writepid( void ) +writepid(void) { - pid_t self; - FILE *fp; + char buf[32]; + int fd; if (pid_file != NULL) { - self = getpid(); - fp = fopen(pid_file, "w"); - - if (fp != NULL) { - fprintf(fp, "%ld\n", (long)self); - fclose(fp); - } - else { - perror("Warning: couldn't open pidfile"); + snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); + fd = open(pid_file, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0666); + if (fd < 0) { + if (errno == EWOULDBLOCK) { + perror("Failed to lock pidfile, " + "vkernel already running"); + } else { + perror("Failed to create pidfile"); + } + exit(EX_SOFTWARE); } + ftruncate(fd, 0); + write(fd, buf, strlen(buf)); + /* leave the file open to maintain the lock */ } } @@ -1211,7 +1224,7 @@ void cleanpid( void ) { if (pid_file != NULL) { - if ( unlink(pid_file) != 0 ) + if (unlink(pid_file) < 0) perror("Warning: couldn't remove pidfile"); } }