Latest version of the daemon killing patch. I've cleaned up the previously rather contorted code paths for sharing in elflink.c. Next step per-user hugetlbfs directories. For sure, this time ;-).
Index: libhugetlbfs/HOWTO =================================================================== --- libhugetlbfs.orig/HOWTO 2006-10-26 13:49:40.000000000 +1000 +++ libhugetlbfs/HOWTO 2006-10-26 13:49:45.000000000 +1000 @@ -326,42 +326,26 @@ libhugetlbfs: Sharing remapped segments: -------------------------- -Sharing of program segments among processes is a two-fold process. - -First, a system-wide daemon must be started, hugetlbd. The executable -(which will be installed into $PREFIX/sbin by make install) should be -run as root and will automatically spawn a child process to wait for -segment sharing into the background. The process will log any output -requested to /tmp/hugetlbd.log. The complete usage for hugetlbd is: - -hugetlbd [-v] [-V verbosity] [-p timeout1] [-s timeout2] - -v: display this help and exit - -V: specify log level (1-3) [default=1] - 1: only log errors - 2: log errors and warnings - 3: log all output - -p: specify how long to wait before unlinking files in the hugetlbfs - mountpoint (seconds) [default=600] - -s: specify when a file last needs to have been shared for it not to be - unlinked (seconds) [default=600] - -Second, in the applications that wish to share segments, the -HUGETLB_SHARE environment variable must be set appropriately. The -variable takes on three values: 0, the default, indicates no segments -should be shared; 1 indicates that only read-only segments (text) should -be shared; and 2 indicates that all segments should be shared. Note, as -this is a per-process variable, it is important to keep its usage -consistent with HUGETLB_MINIMAL_COPY. If MINIMAL_COPY is used by the -first process to share a particular executable's segments, it should be -used by all subsequent ones, to guarantee no failures while copying -segments. Similarly, if MINIMAL_COPY is not used by the first process -sharing, it should not be used by subsequent ones. - -Having taken these two steps, the same application run twice with the -same environment variable settings will use the same file both times -(reducing the overall hugetlbfs file usage). If, for any reason, segment -sharing is requested but unavailable, the library will fallback to -unlinked files. +Sharing of program segments among processes is a simple process. For +the applications that wish to share segments, the HUGETLB_SHARE +environment variable must be set appropriately. The variable takes on +three values: 0, the default, indicates no segments should be shared; +1 indicates that only read-only segments (text) should be shared; and +2 indicates that all segments should be shared. Note, as this is a +per-process variable, it is important to keep its usage consistent +with HUGETLB_MINIMAL_COPY. If MINIMAL_COPY is used by the first +process to share a particular executable's segments, it should be used +by all subsequent ones, to guarantee no failures while copying +segments. Similarly, if MINIMAL_COPY is not used by the first process +sharing, it should not be used by subsequent ones. Additionally, as a +security precaution, sharing is only possible between users in the +same group. + +Now, the same application run twice with the same environment variable +settings will use the same file both times (reducing the overall +hugetlbfs file usage). If, for any reason, segment sharing is +requested but unavailable, the library will fallback to unlinked +files. Examples ======== Index: libhugetlbfs/Makefile =================================================================== --- libhugetlbfs.orig/Makefile 2006-10-26 13:49:40.000000000 +1000 +++ libhugetlbfs/Makefile 2006-10-26 13:49:45.000000000 +1000 @@ -2,7 +2,6 @@ PREFIX = /usr/local BASEOBJS = hugeutils.o version.o LIBOBJS = $(BASEOBJS) elflink.o morecore.o debug.o -SBINOBJS = hugetlbd INSTALL_OBJ_LIBS = libhugetlbfs.so libhugetlbfs.a LDSCRIPT_TYPES = B BDT LDSCRIPT_DIST_ELF = elf32ppclinux elf64ppc elf_i386 elf_x86_64 @@ -84,14 +83,13 @@ endif DEPFILES = $(LIBOBJS:%.o=%.d) -all: libs sbin tests +all: libs tests .PHONY: tests libs libs: $(foreach file,$(INSTALL_OBJ_LIBS),$(OBJDIRS:%=%/$(file))) -sbin: $(foreach file,$(SBINOBJS),$(OBJDIRS:%=%/$(file))) -tests: libs sbin # Force make to build the library first +tests: libs # Force make to build the library first tests: tests/all tests/%: @@ -168,14 +166,6 @@ obj64/%.s: %.c @$(VECHO) CC64 -S $@ $(CC64) $(CPPFLAGS) $(CFLAGS) -o $@ -S $< -obj32/hugetlbd: hugetlbd.c $(BASEOBJS:%=obj32/%) - @$(VECHO) CC32 $@ - $(CC32) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS32) -o $@ $^ - -obj64/hugetlbd: hugetlbd.c $(BASEOBJS:%=obj64/%) - @$(VECHO) CC64 $@ - $(CC64) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS64) -o $@ $^ - clean: @$(VECHO) CLEAN rm -f *~ *.o *.so *.a *.d *.i core a.out $(VERSION) Index: libhugetlbfs/elflink.c =================================================================== --- libhugetlbfs.orig/elflink.c 2006-10-26 13:49:40.000000000 +1000 +++ libhugetlbfs/elflink.c 2006-10-26 16:48:49.000000000 +1000 @@ -1,6 +1,6 @@ /* * libhugetlbfs - Easy use of Linux hugepages - * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Copyright (C) 2005-2006 David Gibson & dam Litke, IBM Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -24,17 +24,20 @@ #include <stdlib.h> #include <malloc.h> #include <string.h> +#include <unistd.h> +#include <fcntl.h> #include <signal.h> #include <sys/syscall.h> +#include <sys/file.h> #include <linux/unistd.h> #include <sys/mman.h> #include <errno.h> +#include <limits.h> #include <elf.h> #include <dlfcn.h> #include "hugetlbfs.h" #include "libhugetlbfs_internal.h" - #ifdef __LP64__ #define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr @@ -179,9 +182,18 @@ static void unmapped_abort(const char *f #define MAX_HTLB_SEGS 2 +struct seg_info { + void *vaddr; + unsigned long filesz, memsz; + int prot; + int fd; + int phdr; +}; + static struct seg_info htlb_seg_table[MAX_HTLB_SEGS]; static int htlb_num_segs; static int minimal_copy = 1; +static int sharing; /* =0 */ int __debug = 0; static Elf_Ehdr *ehdr; @@ -231,6 +243,7 @@ static void parse_phdrs(Elf_Ehdr *ehdr) htlb_seg_table[htlb_num_segs].filesz = filesz; htlb_seg_table[htlb_num_segs].memsz = memsz; htlb_seg_table[htlb_num_segs].prot = prot; + htlb_seg_table[htlb_num_segs].phdr = i; htlb_num_segs++; } } @@ -249,13 +262,63 @@ static void check_bss(unsigned long *sta } } +/** + * get_shared_file_name - create a shared file name from program name, gid and phdr + * @htlb_seg_info: pointer to program's segment data + * @file_path: pointer to a PATH_MAX array to store filename in + * + * The file name created is *not* intended to be unique, except when the name, + * gid or phdr number differ. The goal here is to have a standar means of + * accessing particular segments of particular executables. + * + * returns: + * -1, on failure + * 0, on success + */ +static int get_shared_file_name(struct seg_info *htlb_seg_info, char *file_path) +{ + int ret; + char binary[PATH_MAX]; + char *binary2; + const char *hugetlbfs_path; + + ret = readlink("/proc/self/exe", binary, PATH_MAX); + if (ret < 0) { + ERROR("shared_file: readlink() on /proc/self/exe " + "failed: %s\n", strerror(errno)); + return -1; + } + + binary2 = basename(binary); + if (!binary2) { + ERROR("shared_file: basename() on %s failed: %s\n", + binary, strerror(errno)); + return -1; + } + + hugetlbfs_path = hugetlbfs_find_path(); + if (!hugetlbfs_path) { + ERROR("shared_file: hugetlbfs_find_path() failed\n"); + return -1; + } + + ret = snprintf(file_path, PATH_MAX, "%s/%s_%d_%zd_%d", + hugetlbfs_path, binary2, getgid(), sizeof(unsigned long) * 8, + htlb_seg_info->phdr); + if (ret < 0) { + ERROR("shared_file: snprintf() failed\n"); + return -1; + } + + return 0; +} + /* * Subtle: Since libhugetlbfs depends on glibc, we allow it * it to be loaded before us. As part of its init functions, it * initializes stdin, stdout, and stderr in the bss. We need to * include these initialized variables in our copy. */ - static void get_extracopy(struct seg_info *seg, void **extra_start, void **extra_end) { @@ -387,7 +450,6 @@ bail3: * smallest amount of data possible, unless the user disables this * optimization via the HUGETLB_ELFMAP environment variable. */ - static int prepare_segment(struct seg_info *seg) { int hpage_size = gethugepagesize(); @@ -437,6 +499,139 @@ static int prepare_segment(struct seg_in return 0; } +/** + * find_or_prepare_shared_file - get one shareable file + * @htlb_seg_info: pointer to program's segment data + * + * returns: + * -1, on failure + * 0, on success + */ +static int find_or_prepare_shared_file(struct seg_info *htlb_seg_info) +{ + int fdx, fds; + int errnox, errnos; + int ret; + char final_path[PATH_MAX+1]; + char tmp_path[PATH_MAX+5]; + + ret = get_shared_file_name(htlb_seg_info, final_path); + if (ret < 0) + return -1; + strcpy(tmp_path, final_path); + strcat(tmp_path, ".tmp"); + + do { + /* NB: mode is modified by umask */ + fdx = open(tmp_path, O_CREAT | O_EXCL | O_RDWR, 0666); + errnox = errno; + fds = open(final_path, O_RDONLY); + errnos = errno; + + if (fds > 0) { + /* Got an already-prepared file -> use it */ + if (fdx > 0) { + /* Also got an exclusive file -> clean up */ + ret = unlink(tmp_path); + if (ret != 0) + ERROR("shared_file: unable to clean up" + " unneeded file %s: %s\n", + tmp_path, strerror(errno)); + close(fdx); + } else if (errnox != EEXIST) { + WARNING("shared_file: Unexpected failure on exclusive" + " open of %s: %s\n", tmp_path, + strerror(errnox)); + } + htlb_seg_info->fd = fds; + return 0; + } + + if (fdx > 0) { + /* It's our job to prepare */ + if (errnos != ENOENT) + WARNING("shared_file: Unexpected failure on" + " shared open of %s: %s\n", final_path, + strerror(errnos)); + + htlb_seg_info->fd = fdx; + + DEBUG("Got unpopulated shared fd -- Preparing\n"); + ret = prepare_segment(htlb_seg_info); + if (ret < 0) + goto fail; + + DEBUG("Prepare succeeded\n"); + /* move to permanent location */ + ret = rename(tmp_path, final_path); + if (ret != 0) { + ERROR("shared_file: unable to rename %s" + " to %s: %s\n", tmp_path, final_path, + strerror(errno)); + goto fail; + } + + return 0; + } + + /* Both opens failed, somebody else is still preparing */ + /* Wait and try again */ + sleep(1); + /* FIXME: should have a timeout */ + } while (1); + + fail: + if (fdx > 0) { + ret = unlink(tmp_path); + if (ret != 0) + ERROR("shared_file: Unable to clean up temp file %s on" + " failure: %s\n", tmp_path, strerror(errno)); + close(fdx); + } + if (fds > 0) + close(fds); + + return -1; +} + +/** + * obtain_prepared_file - multiplex callers depending on if + * sharing or not + * @htlb_seg_info: pointer to program's segment data + * + * returns: + * -1, on error + * 0, on success + */ +static int obtain_prepared_file(struct seg_info *htlb_seg_info) +{ + int fd = -1; + int ret; + + /* Either share all segments or share only read-only segments */ + if ((sharing == 2) || ((sharing == 1) && + !(htlb_seg_info->prot & PROT_WRITE))) { + /* first, try to share */ + ret = find_or_prepare_shared_file(htlb_seg_info); + if (ret == 0) + return 0; + /* but, fall through to unlinked files, if sharing fails */ + DEBUG("Falling back to unlinked files\n"); + } + fd = hugetlbfs_unlinked_fd(); + if (fd < 0) + return -1; + htlb_seg_info->fd = fd; + + ret = prepare_segment(htlb_seg_info); + if (ret < 0) { + DEBUG("Failed to prepare segment\n"); + return -1; + } + DEBUG("Prepare succeeded\n"); + return 0; +} + static void remap_segments(struct seg_info *seg, int num) { int hpage_size = gethugepagesize(); @@ -482,49 +677,6 @@ static void remap_segments(struct seg_in */ } -static int maybe_prepare(int fd_state, struct seg_info *seg) -{ - int ret, reply = 0; - - switch (fd_state) { - case 0: - DEBUG("Got populated shared fd -- Not preparing\n"); - return 0; - - case 1: - DEBUG("Got unpopulated shared fd -- Preparing\n"); - reply = 1; - break; - case 2: - DEBUG("Got unshared fd, wanted shared -- Preparing\n"); - break; - case 3: - DEBUG("Got unshared fd as expected -- Preparing\n"); - break; - - default: - ERROR("Unexpected fd state: %d in maybe_prepare\n", - fd_state); - return -1; - } - - ret = prepare_segment(seg); - if (ret < 0) { - /* notify daemon of failed prepare */ - DEBUG("Failed to prepare segment\n"); - finished_prepare(seg, -1); - return -1; - } - DEBUG("Prepare succeeded\n"); - if (reply) { - ret = finished_prepare(seg, 0); - if (ret < 0) - DEBUG("Failed to communicate successful " - "prepare to hugetlbd\n"); - } - return ret; -} - static int check_env(void) { char *env; @@ -550,6 +702,20 @@ static int check_env(void) minimal_copy = 0; } + env = getenv("HUGETLB_SHARE"); + if (env) + sharing = atoi(env); + DEBUG("HUGETLB_SHARE=%d, sharing ", sharing); + if (sharing == 2) { + DEBUG_CONT("enabled for all segments\n"); + } else { + if (sharing == 1) { + DEBUG_CONT("enabled for only read-only segments\n"); + } else { + DEBUG_CONT("disabled\n"); + } + } + env = getenv("HUGETLB_DEBUG"); if (env) { DEBUG("HUGETLB_DEBUG=%s, enabling extra checking\n", env); @@ -581,22 +747,13 @@ static void __attribute__ ((constructor) return; } - /* Step 1. Get access to the files we're going to mmap for the - * segments */ + /* Step 1. Obtain hugepage files with our program data */ for (i = 0; i < htlb_num_segs; i++) { - ret = hugetlbfs_set_fd(&htlb_seg_table[i]); + ret = obtain_prepared_file(&htlb_seg_table[i]); if (ret < 0) { DEBUG("Failed to setup hugetlbfs file\n"); return; } - - /* Step 2. Map the hugetlbfs files anywhere to copy data, if we - * need to prepare at all */ - ret = maybe_prepare(ret, &htlb_seg_table[i]); - if (ret < 0) { - DEBUG("Failed to prepare hugetlbfs file\n"); - return; - } } /* Step 3. Unmap the old segments, map in the new ones */ Index: libhugetlbfs/hugetlbd.c =================================================================== --- libhugetlbfs.orig/hugetlbd.c 2006-10-26 13:49:40.000000000 +1000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,872 +0,0 @@ -/* - * libhugetlbfs - Easy use of Linux hugepages - * Copyright (C) 2006 Nishanth Aravamudan, IBM Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <errno.h> -#include <getopt.h> -#include <signal.h> -#include <time.h> -#include <unistd.h> -#include <fcntl.h> - -#include <sys/mman.h> -#include <sys/poll.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/un.h> - -#include "libhugetlbfs_internal.h" -#include "hugetlbfs.h" -#include "hugetlbd.h" - -#define QUEUE_LENGTH SOMAXCONN -#define HUGETLBD_PORT 60046 /* some random number */ -/* how often to reap due to idleness */ -#define DEFAULT_POLL_TIMEOUT 600000 /* milliseconds */ -/* how long ago does a share need to have occurred to reap? */ -#define DEFAULT_SHARE_TIMEOUT 600 /* seconds */ - -struct shared_mapping { - /* unique identifier */ - exe_ident_t id; - /* filename */ - char path_to_file[PATH_MAX+1]; - /* virtual address of segments */ - vaddr_t vaddr; - /* timestamp for file cleanup */ - time_t timestamp; - /* linked-list pointer */ - struct shared_mapping *next; -}; - -static struct shared_mapping *head; - -/* visible for multiple manipulation points */ -static int sock; -/* visible for SIGALRM handling */ -static int timeout; -/* visible for error handling */ -static int shared_fd; -static FILE *logfd; -static unsigned int share_timeout; -static unsigned int poll_timeout; - -int __hugetlbfs_verbose = 0; - -static void usage() -{ - printf("Usage: hugetlbd [-v] [-V verbosity] [-p timeout1] [-s timeout2]\n" - "Start libhugetlbfs daemon for sharing program segments\n" - " -v: display this help and exit\n" - " -V: specify log level (1-3) [default=1]\n" - " 1: only log errors\n" - " 2: log errors and warnings\n" - " 3: log all output\n" - " -p: specify how long to wait before unlinking files in the hugetlbfs\n" - " mountpoint (seconds) [default=600]\n" - " -s: specify when a file last needs to have been shared for it not to\n" - " be unlinked (seconds) [default=600]\n" - "Report bugs to [EMAIL PROTECTED]"); -} - -/** - * reap_files - unlink all shared files - * @quitting: 1 if exiting daemon - * - * no return value - */ -static void reap_files(int quitting) -{ - struct shared_mapping *smptr, *nextsmptr; - time_t now = time(NULL); - - DEBUG("Reaping files\n"); - smptr = head; - /* list is sorted by timestamp, youngest is at head */ - while (smptr != NULL) { - /* - * Iterate through list until we get to an old enough - * sharing - */ - if (!quitting && (now - smptr->timestamp < share_timeout)) { - smptr = smptr->next; - continue; - } - /* keep pointer to the next one */ - nextsmptr = smptr->next; - unlink(smptr->path_to_file); - /* if we're deleting head, head has to move */ - if (smptr == head) { - head = nextsmptr; - } - free(smptr); - smptr = nextsmptr; - } -} - -/** - * kill_daemon - exit the daemon process - * @ret: if 0, expected quit - * 1, unexpected quit - * also functions as return value to exit with - * - * no return value - */ -static void kill_daemon(int ret) -{ - DEBUG("Killing daemon\n"); - reap_files(1); - /* - * Close the socket here, because we might dying due to an - * asynchronous signal. - */ - close(sock); - exit(ret); -} - -/** - * signal_handler - respond to catchable signals - * @signal: the signal to handle - * - * no return value - */ -static void signal_handler(int signal) -{ - switch (signal) { - case SIGHUP: - /* reap files */ - DEBUG("Caught SIGHUP\n"); - reap_files(1); - break; - case SIGINT: - /* expectedly quit */ - kill_daemon(0); - break; - case SIGALRM: - timeout = 1; - break; - } -} - -/** - * idcpy - copy id from src to dst - * @src: source id - * @dst: destination id - * - * Would need to be changed if exe_ident_t is changed to not be a basic - * type. - * - * no return value - */ -static void idcpy(exe_ident_t *dst, exe_ident_t *src) -{ - *dst = *src; -} - -/** - * idcmp - compare id1 to id2 - * @id1: first id - * @dst: second id - * - * Would need to be changed if exe_ident_t is changed to not be a basic - * type. - * - * returns: 0, if ids match - * 1, if ids don't match - */ -static int idcmp(exe_ident_t *i1, exe_ident_t *i2) -{ - if (*i1 == *i2) - return 0; - else - return 1; -} - -/** - * set_path_to_file - create new unique file in hugetlbfs - * @tgt: target character array to store filename in - * @size: size of @tgt - * - * Creates a new uniquely named file in the hugetlbfs mount point. File - * is opened in mkstemp, and the file descriptor is stored in a globally - * visible variable, because the caller's return value is already - * overloaded. - * - * Effectively identical to get_unlinked_fd(). - * - * no return value - */ -static void set_path_to_file(char *tgt, int size) -{ - const char *path; - shared_fd = -1; - - tgt[size - 1] = '\0'; - - path = hugetlbfs_find_path(); - if (!path) { - shared_fd = -1; - return; - } - - strcpy(tgt, path); - strncat(tgt, "/libhugetlbfs.tmp.XXXXXX", size - 1); - - shared_fd = mkstemp(tgt); - if (shared_fd > 0) { - /* prevent access to shared file */ - int ret = chmod(tgt, 0); - if (ret < 0) { - DEBUG("chmod failed\n"); - shared_fd = -1; - } - } -} - -/** - * do_shared_file - find shareable mapping, or create new one - * @req: contains executable id and virtual addresses of segments - * @resp: contains filename and whether prepare() needs to be run - * - * The core routine for sharing mappings. The request and response - * structures allow for accepting many parameters and returning many - * response values independent of the actual return value, which acts - * kind of like metadata about @resp. - * - * returns: -1, if failed to create mapping - * NULL, if sharing mapping already at head of list - * pointer to previous entry in linked list, else - */ -static struct shared_mapping *do_shared_file(struct client_request *creq, - struct daemon_response *dresp) -{ - struct shared_mapping *smptr, *prevsmptr; - - if (head == NULL) { - /* allocating first member of linked list */ - goto create_mapping; - } - - prevsmptr = NULL; - smptr = head; - - while (smptr != NULL) { - if (!idcmp(&(smptr->id), &(creq->id)) - && (smptr->vaddr == creq->vaddr)) - /* found match */ - goto share_mapping; - - /* - * Keep track of the previous entry in the list, because - * we're going to need to move the one we're currently - * at. This prevents an extra loop later. - */ - prevsmptr = smptr; - smptr = smptr->next; - } - -create_mapping: - /* first attempt to map this segment, create a new mapping */ - smptr = (struct shared_mapping *)malloc(sizeof(struct shared_mapping)); - if (smptr == NULL) { - ERROR("Failed to allocate new shared mapping: %s\n", - strerror(errno)); - return (struct shared_mapping *)-1; - } - - set_path_to_file(smptr->path_to_file, sizeof(smptr->path_to_file)); - if (shared_fd < 0) { - ERROR("Failed to create new shared file\n"); - free(smptr); - return (struct shared_mapping *)-1; - } - - DEBUG("created shared mapping to %s\n", smptr->path_to_file); - - /* grab data out of request */ - idcpy(&(smptr->id), &(creq->id)); - smptr->vaddr = creq->vaddr; - /* timestamp will be set upon insert */ - - /* client will need to prepare file */ - dresp->need_to_prepare = 1; - strcpy(dresp->path_to_file, smptr->path_to_file); - - /* - * Cannot be NULL. Caller is responsible for freeing if an error - * occurs - */ - return smptr; - -share_mapping: - /* store data in response */ - dresp->need_to_prepare = 0; - strcpy(dresp->path_to_file, smptr->path_to_file); - - DEBUG("sharing mapping to %s\n", smptr->path_to_file); - - /* - * Can be NULL, if sharing at the head of the list. Caller does - * not need to deal with freeing, but must deal with both NULL - * and non-NULL cases. - * We are moving smptr to the front of the list if the sharing - * succeeds, but send prevsmptr back so that we don't need to - * iterate to do the move. - */ - return prevsmptr; -} - -static int parse_args(int argc, char *argv[]) { - int opt; - int ret = 0; - while (1) { - opt = getopt(argc, argv, ":p:s:dV:v"); - if (opt == -1) - break; - - switch (opt) { - case 'p': - /* needs to be in milliseconds */ - poll_timeout = 1000*atoi(optarg); - break; - case 's': - share_timeout = atoi(optarg); - break; - case 'd': - /* do not daemonize */ - ret = 1; - break; - case 'V': - __hugetlbfs_verbose = atoi(optarg); - break; - case 'v': - usage(); - return -1; - case ':': - printf("getopt: missing parameter for option %c\n", optopt); - usage(); - return -1; - case '?': - printf("getopt: unknown option: %c\n", optopt); - usage(); - return -1; - default: - printf("getopt: returned character code 0%o\n", opt); - usage(); - return -1; - } - } - - if (poll_timeout == 0) { - poll_timeout = DEFAULT_POLL_TIMEOUT; - } - if (share_timeout == 0) { - share_timeout = DEFAULT_SHARE_TIMEOUT; - } - - return ret; -} - -static void daemonize() -{ - pid_t pid, sid; - - pid = fork(); - if (pid < 0) { - ERROR("daemonize: fork() failed\n"); - exit(1); - } - if (pid > 0) - exit(0); - - umask(0); - - sid = setsid(); - if (sid < 0) { - ERROR("daemonize: Failed to set session ID\n"); - exit(1); - } - - if ((chdir("/")) < 0) { - ERROR("daemonize: Failed to change directory\n"); - exit(1); - } - - logfd = fopen(LOGFILE, "a+"); - if (!logfd) { - ERROR("daemonize: Failed to open log file %s\n", LOGFILE); - exit(1); - } - - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - stderr = logfd; -} - -/** - * read_client_request - receive request from client - * @local_sock: socket to read from - * @cresp: pointer to store request in - * - * Wait for client's request for sharing - * - * returns 0, on success - * negative values, on failure - */ -static int read_client_request(int local_sock, struct client_request - *creq) -{ - int ret; - alarm(60); - ret = read(local_sock, creq, sizeof(*creq)); - /* cancel any alarms */ - alarm(0); - if (ret < 0) { - /* timeout == 1 means that the SIGALRM handler ran */ - if (timeout) { - DEBUG("read timed out\n"); - return -1; - } - ERROR("read failed: %s\n", strerror(errno)); - return -2; - } - if (ret != sizeof(*creq)) { - /* - * This should never happen, but is useful for - * debugging size issues with mixed environments - */ - DEBUG("short first read (got %d, should have been " - "%zu\n", ret, sizeof(*creq)); - return -1; - } - return 0; -} - -/** - * write_daemon_response - respond to client - * @local_sock: socket to write to - * @cresp: pointer to response - * - * Acknowledge a client's request with a filename and whether the caller - * needs to prepare - * - * returns 0, on success - * negative values, on failure - */ -static int write_daemon_response(int local_sock, struct daemon_response - *dresp) -{ - int ret; - alarm(60); - ret = write(local_sock, dresp, sizeof(*dresp)); - alarm(0); - /* - * If dresp.need_to_prepare is set, then we know we - * dynamically allocated an element (which is pointed to - * by smptr). We need to backout any changes it made to - * the system state (open file, memory consumption) on - * errors. - */ - if (ret < 0) { - if (timeout) { - DEBUG("write timed out\n"); - if (dresp->need_to_prepare) - return -1; - return -2; - } - ERROR("write failed: %s\n", strerror(errno)); - if (dresp->need_to_prepare) - return -3; - return -4; - } - if (ret != sizeof(*dresp)) { - DEBUG("short write (got %d, should have been %zu\n", - ret, sizeof(*dresp)); - if (dresp->need_to_prepare) - return -1; - return -2; - } /* else successfully wrote */ - return 0; -} - -/** - * read_client_response - wait for a client's ACK - * @local_sock: socket to read from - * @dresp: pointer to daemon's previous reponse - * @cresp: pointer to store response in - * - * Wait for notification that file is prepared and segments have been - * remapped. We need @dresp so that we can backout on errors - * appropriately. - * - * returns 0, on success - * negative values, on failure - */ -static int read_client_response(int local_sock, struct daemon_response - *dresp, struct client_response *cresp) -{ - int ret; - DEBUG("waiting for client's response\n"); - /* this may be unnecessarily long */ - alarm(300); - /* - */ - ret = read(local_sock, cresp, sizeof(*cresp)); - alarm(0); - if (ret < 0) { - if (timeout) { - DEBUG("read timed out\n"); - if (dresp->need_to_prepare) - return -1; - return -2; - } - ERROR("read failed: %s\n", strerror(errno)); - if (dresp->need_to_prepare) - return -3; - return -4; - } - if (ret != sizeof(*cresp)) { - DEBUG("short second read (got %d, should have been " - "%zu\n", ret, sizeof(*cresp)); - if (dresp->need_to_prepare) - return -1; - return -2; - } - return 0; -} - -/** - * sharing_control_loop - main event loop for sharing - * @sock: socket to wait on for connections - * - * This is expected to be an infinite loop. If we we ever return, it is - * a fail case. - * - * returns 1 - */ -static int sharing_control_loop(int sock) -{ - int ret; - struct sockaddr_un from; - socklen_t len = (socklen_t)sizeof(from); - /* - * Needed for socket messages -- could switch to dynamic - * allocation - */ - struct client_request creq; - struct daemon_response dresp; - struct client_response cresp; - int local_sock; - /* handle on some state that may need to be freed */ - struct shared_mapping *smptr; - mode_t mode; - /* needed for poll */ - struct pollfd ufds; - /* used to allow for handling SIGALRM and SIGHUP */ - struct sigaction sigact = { - .sa_handler = signal_handler, - .sa_flags = 0, - }; - struct sigaction prevact; - - sigemptyset(&(sigact.sa_mask)); - - /* We will poll on sock for any incoming connections */ - ufds.fd = sock; - ufds.events = POLLIN; - - /* install our custom signal-handler */ - sigaction(SIGINT, &sigact, NULL); - - for (;;) { - /* gets set by SIGALRM handler */ - timeout = 0; - /* not sure if this is necessary, but ok */ - ufds.revents = 0; - /* helps with error handling */ - dresp.need_to_prepare = 0; - /* reset mode of shared file */ - mode = 0; - - sigaction(SIGHUP, &sigact, &prevact); - -do_poll: - ret = poll(&ufds, 1, poll_timeout); - if (ret < 0) { - /* - * catch SIGHUP as non-fail case - * SIGINT will have made us exit already - */ - if (errno == EINTR) - goto do_poll; - ERROR("poll() failed: %s\n", strerror(errno)); - goto die; - } else if (ret == 0) { - /* poll timeout, reap any old files */ - DEBUG("poll() timed out\n"); - reap_files(0); - continue; - } - - switch (ufds.revents) { - case POLLERR: - ERROR("poll returned a POLLERR event\n"); - goto die; - break; - case POLLNVAL: - ERROR("poll returned a POLLNVAL event\n"); - goto die; - break; - case POLLHUP: - ERROR("poll returned a POLLHUP event\n"); - goto die; - break; - case POLLIN: - break; - default: - ERROR("poll() returned an event we did not expect: %d\n", ufds.revents); - goto die; - } - - local_sock = accept(sock, (struct sockaddr *)(&from), &len); - if (local_sock < 0) { - if (errno == ECONNABORTED) { - /* - * I think this is ok as a non-failure - * case, but not positive, since the - * client is what failed, not us. - */ - DEBUG("accept() returned connection aborted\n"); - continue; - } - /* - * Don't fail on a SIGHUP - */ - if (errno == EINTR) - goto do_poll; - ERROR("accept() failed: %s\n", strerror(errno)); - goto die; - } - - /* - * Disable the races due to removing files that may be - * sent to clients for sharing by just not handling - * SIGHUP for a bit - */ - sigaction(SIGHUP, &prevact, NULL); - sigaction(SIGALRM, &sigact, NULL); - - ret = read_client_request(local_sock, &creq); - switch (ret) { - case 0: - break; - case -1: - goto next; - case -2: - goto close_and_die; - } - - /* Use the request to figure out the mapping ... */ - smptr = do_shared_file(&creq, &dresp); - if (smptr == (struct shared_mapping *)-1) { - ERROR("do_shared_file failed\n"); - /* - * Just because we didn't get a hugetlbfs file, - * doesn't mean we should fail outright. For - * instance, if mkstemp() failed for some reason - * we should still continue sharing any - * previously shared segments. - */ - goto next; - } - - mode = S_IRUSR | S_IRGRP | S_IROTH; - /* only allow preparer to write to file */ - if (dresp.need_to_prepare) - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - ret = chmod(dresp.path_to_file, mode); - if (ret < 0) { - DEBUG("chmod(%s) to read (maybe writable) failed: %s\n", dresp.path_to_file, strerror(errno)); - if (dresp.need_to_prepare) - goto failed_next; - goto next; - } - - ret = write_daemon_response(local_sock, &dresp); - switch (ret) { - case 0: - break; - case -1: - goto failed_next; - case -2: - goto next; - case -3: - goto failed_close_and_die; - case -4: - goto failed_next; - } - - ret = read_client_response(local_sock, &dresp, &cresp); - switch (ret) { - case 0: - break; - case -1: - goto failed_next; - case -2: - goto next; - case -3: - goto failed_close_and_die; - case -4: - goto failed_next; - } - - /* - * Determine if the segments were prepared/remapped as - * expected. - */ - if (cresp.succeeded != 0) { - DEBUG("file not prepared\n"); - if (dresp.need_to_prepare) - goto failed_next; - goto next; - } - - DEBUG("File prepared / opened successfully\n"); - if (dresp.need_to_prepare) { - mode = S_IRUSR | S_IRGRP | S_IROTH; - ret = chmod(dresp.path_to_file, mode); - if (ret < 0) { - DEBUG("chmod(%s) to read-only failed: %s\n", dresp.path_to_file, strerror(errno)); - goto failed_next; - } - /* - * Insert new element at head of list - */ - if (head != NULL) - smptr->next = head; - else - smptr->next = NULL; - head = smptr; - - close(shared_fd); - } else { - /* - * Move element to head of list. We have pointer - * to the element just before the element to - * move. If it is NULL, then we are sharing at - * the head of the list, and no moving is - * necessary. Else, shift the pointers around. - * We obviously also know that head != NULL. - */ - if (smptr != NULL) { - struct shared_mapping *temp; - temp = smptr->next; - smptr->next = temp->next; - temp->next = head; - head = temp; - } - } - /* - * Shared mapping is at the head of the list now, update - * timestamp. - */ - head->timestamp = time(NULL); - - goto next; - -failed_next: - close(shared_fd); - unlink(dresp.path_to_file); - free(smptr); -next: - close(local_sock); - } - -failed_close_and_die: - close(shared_fd); - unlink(dresp.path_to_file); - free(smptr); -close_and_die: - close(local_sock); -die: - kill_daemon(1); - - /* indicate failure if we ever get this far */ - return 1; -} - -/** - * main - set up socket and enter central control loop - * @argc: number of command line arguments - * @argv: command line arguments - * - * returns: 0, on success - * -1, on failure - */ -int main(int argc, char *argv[]) -{ - int ret; - /* local socket structures */ - struct sockaddr_un sun; - - ret = parse_args(argc, argv); - if (ret < 0) - exit(1); - if (ret == 0) - /* Perform all the steps to become a real daemon */ - daemonize(); - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - ERROR("socket() failed: %s\n", strerror(errno)); - return -1; - } - - sun.sun_family = AF_UNIX; - /* clear out any previous socket */ - unlink("/tmp/libhugetlbfs-sock"); - strcpy(sun.sun_path, "/tmp/libhugetlbfs-sock"); - ret = bind(sock, (struct sockaddr *)(&sun), sizeof(sun)); - if (ret < 0) { - ERROR("bind() failed: %s\n", strerror(errno)); - goto die; - } - - chmod("/tmp/libhugetlbfs-sock", 0666); - - ret = listen(sock, QUEUE_LENGTH); - if (ret < 0) { - ERROR("listen() failed: %s\n", strerror(errno)); - goto die; - } - - return sharing_control_loop(sock); - -die: - kill_daemon(1); - - /* indicate failure if we ever get this far */ - return 1; -} Index: libhugetlbfs/hugetlbd.h =================================================================== --- libhugetlbfs.orig/hugetlbd.h 2006-10-26 13:49:40.000000000 +1000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - * libhugetlbfs - Easy use of Linux hugepages - * Copyright (C) 2006 Nishanth Aravamudan, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _HUGETLBD_H -#define _HUGETLBD_H - -#ifndef __LIBHUGETLBFS__ -#error This header should not be included by library users. -#endif /* __LIBHUGETLBFS__ */ - -#define ID_KEY 0x56 -#define LOGFILE "/tmp/hugetlbd.log" - -/* - * Ideally, would like to deal with this better, so that a 32-bit daemon - * only deals in 32-bit addresses. But, for now, this makes 32-bit and - * 64-bit apps deal ok with the socket messages. - */ -typedef uint64_t vaddr_t; -typedef uint64_t exe_ident_t; - -struct client_request { - /* - * unique identifer - * if id == 0, then the request is actually a response that the - * file is prepared - */ - exe_ident_t id; - /* - * to identify the segment - */ - vaddr_t vaddr; -}; - -struct client_response { - int succeeded; -}; - -struct daemon_response { - int need_to_prepare; - char path_to_file[PATH_MAX+1]; -}; - -#endif /* _HUGETLBD_H */ Index: libhugetlbfs/hugeutils.c =================================================================== --- libhugetlbfs.orig/hugeutils.c 2006-10-26 13:49:40.000000000 +1000 +++ libhugetlbfs/hugeutils.c 2006-10-26 13:49:45.000000000 +1000 @@ -36,18 +36,14 @@ #include <sys/vfs.h> #include <sys/statfs.h> #include <sys/types.h> -#include <sys/ipc.h> -#include <sys/socket.h> -#include <sys/un.h> #include <sys/mman.h> +#include <sys/file.h> #include "libhugetlbfs_internal.h" #include "hugetlbfs.h" -#include "hugetlbd.h" static int hpage_size; /* = 0 */ static char htlb_mount[PATH_MAX+1]; /* = 0 */ -int sharing; /* =0 */ /********************************************************************/ /* Internal functions */ @@ -247,297 +243,6 @@ int hugetlbfs_unlinked_fd(void) return fd; } -/** - * create_id - create unique id for current executable - * - * Uses IPC ftok() to generate a roughly unique identifier for our own - * executable. This is used to match shareable mappings. - * - * returns: -1, on error - * a unique identifier, otherwise - */ -static exe_ident_t create_id(void) -{ - exe_ident_t id; - int ret; - char my_exe[PATH_MAX]; - - ret = readlink("/proc/self/exe", my_exe, PATH_MAX); - if (ret < 0) { - ERROR("readlink failed: %s\n", strerror(errno)); - return -1; - } - - id = (exe_ident_t)ftok(my_exe, ID_KEY); - if (id < 0) { - ERROR("ftok failed: %s\n", strerror(errno)); - return -1; - } - - return id; -} - -static int sock; -static int timeout; -/* global to allow multiple callsites to set members */ - -static void signal_handler(int signal) -{ - switch (signal) { - case SIGALRM: - timeout = 1; - } -} - -static int client_complete(struct seg_info *htlb_seg_info, int success); - -/** - * hugetlbfs_shared_file - communicate with daemon to get one shareable file - * @htlb_seg_info: pointer to program's segment data - * - * returns: - * -1, on failure - * 0, on success, and caller does not need to prepare the segments - * 1, on success, and caller does need to prepare the segments - */ -static int hugetlbfs_shared_file(struct seg_info *htlb_seg_info) -{ - int ret, fd; - struct client_request creq; - struct daemon_response dresp; - struct sockaddr_un sun; - struct sigaction sigact = { - .sa_handler = signal_handler, - .sa_flags = 0, - }; - struct sigaction prev; - int open_flags; - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - ERROR("socket() failed: %s\n", strerror(errno)); - return -1; - } - - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, "/tmp/libhugetlbfs-sock"); - ret = connect(sock, &sun, sizeof(sun)); - if (ret < 0) { - ERROR("connect() failed: %s\n", strerror(errno)); - return -1; - } - - sigemptyset(&(sigact.sa_mask)); - - sigaction(SIGALRM, &sigact, &prev); - - /* add data to request */ - creq.id = create_id(); - /* - * This results in (non-harmful) compilation warning for - * 32-bit applications - */ - creq.vaddr = (vaddr_t)htlb_seg_info->vaddr; - - alarm(60); - ret = write(sock, &creq, sizeof(creq)); - /* cancel any alarms */ - alarm(0); - if (ret < 0) { - if (timeout) { - DEBUG("write timed out\n"); - goto fail; - } else { - ERROR("client request write failed: %s\n", - strerror(errno)); - goto fail; - } - } else if (ret != sizeof(creq)) { - DEBUG("short write (got %d, should have been %zu)\n", - ret, sizeof(creq)); - goto fail; - } /* else successfully wrote */ - - /* wait slightly longer for the response */ - alarm(120); - ret = read(sock, &dresp, sizeof(dresp)); - alarm(0); - if (ret < 0) { - if (timeout) { - DEBUG("read timed out\n"); - goto fail; - } else { - ERROR("read failed: %s\n", strerror(errno)); - goto fail; - } - } else if (ret != sizeof(dresp)) { - DEBUG("short read (got %d, should have been %zu)\n", - ret, sizeof(dresp)); - goto fail; - } /* else successfully read */ - - sigaction(SIGALRM, &prev, NULL); - - /* Convert daemon response to open mode bits */ - if (dresp.need_to_prepare) { - open_flags = O_RDWR; - } else { - open_flags = O_RDONLY; - } - - /* get local handle on file */ - fd = open(dresp.path_to_file, open_flags); - if (fd < 0) { - ERROR("open(%s) failed: %s\n", dresp.path_to_file, - strerror(errno)); - goto fail; - } - - if (dresp.need_to_prepare) { - DEBUG("daemon said to prepare\n"); - } else { - /* ACK right away (closes socket) */ - DEBUG("daemon said not to prepare\n"); - ret = client_complete(htlb_seg_info, 0); - if (ret < 0) - goto fail; - } - - htlb_seg_info->fd = fd; - - /* leave socket open until finished_prepare is called */ - return dresp.need_to_prepare; - -fail: - close(sock); - return -1; -} - -/** - * client_complete - send ACK to daemon that we no longer need file - * @htlb_seg_info: pointer to program's segment data - * @success: if 0, successful prepare, else failed - * - * returns: 0, if successful transmission (none occurs if - * not sharing) - * -1, if failed transmission - */ -static int client_complete(struct seg_info *htlb_seg_info, int success) -{ - struct sigaction sigact = { - .sa_handler = signal_handler, - .sa_flags = 0, - }; - struct sigaction prev; - struct client_response cresp; - int ret; - - sigemptyset(&(sigact.sa_mask)); - - sigaction(SIGALRM, &sigact, &prev); - - cresp.succeeded = success; - - alarm(60); - ret = write(sock, &cresp, sizeof(cresp)); - alarm(0); - if (ret < 0) { - if (timeout) { - DEBUG("write timed out\n"); - goto fail; - } else { - ERROR("client response write failed: %s\n", - strerror(errno)); - goto fail; - } - } else if (ret != sizeof(cresp)) { - DEBUG("short write (got %d, should have been %zu)\n", - ret, sizeof(cresp)); - goto fail; - } /* else successfully wrote */ - - sigaction(SIGALRM, &prev, NULL); - - if (success < 0) - /* back out open'd fd since we failed */ - close(htlb_seg_info->fd); - - close(sock); - return 0; - -fail: - close(htlb_seg_info->fd); - close(sock); - return -1; -} - -/** - * finished_prepare - callback for ACK'ing prepare is done - * @htlb_seg_info: pointer to program's segment data - * @success: if 0, successful prepare, else failed - * - * returns: 0, if successful transmission (none occurs if - * not sharing) - * -1, if failed transmission - */ -int finished_prepare(struct seg_info *htlb_seg_info, int success) -{ - if (sharing) - return client_complete(htlb_seg_info, success); - return 0; -} - -/** - * hugetlbfs_set_fds - multiplex callers depending on if sharing or not - * @htlb_seg_info: pointer to program's segment data - * - * returns: - * -1, on error - * 0, on success, caller expects and gets shared, does not need to prepare - * 1, on success, caller expects and gets shared, does need to prepare - * 2, on success, caller expects shared and gets unlinked, does need to prepare - * 3, on success, caller expects and gets unlinked, does need to prepare - */ -int hugetlbfs_set_fd(struct seg_info *htlb_seg_info) -{ - char *env; - int fd; - /* assume unlinked, all unlinked files need to be prepared */ - int ret = 3; - - env = getenv("HUGETLB_SHARE"); - if (env) - sharing = atoi(env); - DEBUG("HUGETLB_SHARE=%d, sharing ", sharing); - if (sharing == 2) { - DEBUG_CONT("enabled for all segments\n"); - } else { - if (sharing == 1) { - DEBUG_CONT("enabled for only read-only segments\n"); - } else { - DEBUG_CONT("disabled\n"); - } - } - - /* Either share all segments or share only read-only segments */ - if ((sharing == 2) || ((sharing == 1) && - !(htlb_seg_info->prot & PROT_WRITE))) { - /* first, try to share */ - ret = hugetlbfs_shared_file(htlb_seg_info); - if (ret >= 0) - return ret; - /* but, fall through to unlinked files, if sharing fails */ - ret = 2; - DEBUG("Falling back to unlinked files\n"); - } - fd = hugetlbfs_unlinked_fd(); - if (fd < 0) - return -1; - htlb_seg_info->fd = fd; - return ret; -} - - /********************************************************************/ /* Library user visible DIAGNOSES/DEBUGGING ONLY functions */ /********************************************************************/ Index: libhugetlbfs/libhugetlbfs_internal.h =================================================================== --- libhugetlbfs.orig/libhugetlbfs_internal.h 2006-10-26 13:49:40.000000000 +1000 +++ libhugetlbfs/libhugetlbfs_internal.h 2006-10-26 13:49:45.000000000 +1000 @@ -30,8 +30,6 @@ extern int __hugetlbfs_verbose; -extern int sharing; - #define ERROR(...) \ if (__hugetlbfs_verbose >= 1) \ fprintf(stderr, "libhugetlbfs: ERROR: " __VA_ARGS__) @@ -48,16 +46,6 @@ extern int sharing; if (__hugetlbfs_verbose >= 3) \ fprintf(stderr, __VA_ARGS__) -struct seg_info { - void *vaddr; - unsigned long filesz, memsz; - int prot; - int fd; -}; - -int finished_prepare(struct seg_info *htlb_seg_info, int success); -int hugetlbfs_set_fd(struct seg_info *htlb_seg_info); - #if defined(__powerpc64__) && !defined(__LP64__) /* Older binutils fail to provide this symbol */ #define __LP64__ Index: libhugetlbfs/tests/run_tests.sh =================================================================== --- libhugetlbfs.orig/tests/run_tests.sh 2006-10-26 13:49:42.000000000 +1000 +++ libhugetlbfs/tests/run_tests.sh 2006-10-26 13:49:45.000000000 +1000 @@ -13,6 +13,14 @@ function free_hpages() { echo "$H" } +function hugetlbfs_path() { + if [ -n "$HUGETLB_PATH" ]; then + echo "$HUGETLB_PATH" + else + grep hugetlbfs /proc/mounts | cut -f2 -d' ' + fi +} + TOTAL_HPAGES=$(grep 'HugePages_Total:' /proc/meminfo | cut -f2 -d:) [ -z "$TOTAL_HPAGES" ] && TOTAL_HPAGES=0 HPAGE_SIZE=$(grep 'Hugepagesize:' /proc/meminfo | awk '{print $2}') @@ -64,15 +72,15 @@ elfshare_test () { baseprog="${args[$N]}" unset args[$N] set -- "[EMAIL PROTECTED]" + # Run each elfshare test invocation independently - clean up the + # sharefiles before and after: + rm -f $(hugetlbfs_path)/{xB,xBDT}.$baseprog* NUM_THREADS=2 - killall -HUP hugetlbd run_test HUGETLB_SHARE=2 "$@" "xB.$baseprog" $NUM_THREADS - killall -HUP hugetlbd run_test HUGETLB_SHARE=1 "$@" "xB.$baseprog" $NUM_THREADS - killall -HUP hugetlbd run_test HUGETLB_SHARE=2 "$@" "xBDT.$baseprog" $NUM_THREADS - killall -HUP hugetlbd run_test HUGETLB_SHARE=1 "$@" "xBDT.$baseprog" $NUM_THREADS + rm -f $(hugetlbfs_path)/{xB,xBDT}.$baseprog* } setup_shm_sysctl() { @@ -131,21 +139,11 @@ functional_tests () { elflink_test linkhuge # Sharing tests - # stop all running instances for clean testing - killall -INT hugetlbd - # start the daemon in the bg - PATH=../obj32:../obj64:$PATH hugetlbd - # XXX: Wait for daemon to start - sleep 5 elfshare_test linkshare - # stop our instance of the daemon - killall -INT hugetlbd # Accounting bug tests # reset free hpages because sharing will have held some # alternatively, use -# killall -HUP hugetlbd -# to make the sharing daemon give up the files run_test chunk-overcommit `free_hpages` run_test alloc-instantiate-race `free_hpages` run_test truncate_reserve_wraparound -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ Libhugetlbfs-devel mailing list Libhugetlbfs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel