Here is a revised version of Nish's patch to abolish hugetlbd. The main change is an improved method of synchronising the preparing process with other sharers: it's simpler than flock() and I *think* it's race free (make that thought it was race free, see below). It works like this: 1. each process first attempts an O_RDONLY open() on 'filename' (derived from executable name and other information as with Nish's original version). If that suceeds, it assumes the file is ready, maps and uses it. 2. If that fails with ENOENT, it assumes it has to prepare the file itself. It does an O_EXCL open() on 'filename.tmp' (note the different name). 3. If this fails with EEXIST, it assumes we raced with another process doing the same thing, and go back to step 1. (at the moment there's no timeout here, so we could loop forever if things go wrong in certain ways - this will need to be fixed, obviously). 4. If we do manage to exclusive open 'filename.tmp', we map it SHARED and copy the executable contents in. 5. Once the file is prepared we first hardlink 'filename.tmp' to 'filename' (with link(2)). This means any new sharers who enter will pick up the now prepared file. Then we unlink() 'filename.tmp'.
Of course, as I wrote the above, I spotted the race that is, in fact, there - the link() and unlink() could both occur between another processes two open()s, leading to a failure-to-share. Bother, oh well, I guess I'll think some more about this. This patch also moves the various elflink functions and declarations that had leaked into hugeutils.c back into elflink.c where they belong. There are a few other small cleanups. I'll next attempt to implement per-user directories for the sharefiles. Signed-off-by: David Gibson <[EMAIL PROTECTED]> Signed-off-by: Nishanth Aravamudan <[EMAIL PROTECTED]> Index: libhugetlbfs/HOWTO =================================================================== --- libhugetlbfs.orig/HOWTO 2006-10-24 16:05:10.000000000 +1000 +++ libhugetlbfs/HOWTO 2006-10-24 16:06:16.000000000 +1000 @@ -323,42 +323,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-24 16:05:10.000000000 +1000 +++ libhugetlbfs/Makefile 2006-10-24 16:06:16.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-24 16:05:10.000000000 +1000 +++ libhugetlbfs/elflink.c 2006-10-24 16:50:22.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,6 +262,191 @@ 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; +} + +/** + * hugetlbfs_shared_file - 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 fd; + int ret; + char file_path[PATH_MAX]; + char file_path_tmp[PATH_MAX+4]; + + ret = get_shared_file_name(htlb_seg_info, file_path); + if (ret < 0) + return -1; + strcpy(file_path_tmp, file_path); + strcat(file_path_tmp, ".tmp"); + + retry: + fd = open(file_path, O_RDONLY); + if (fd >= 0) { + /* Success, we got a pre-prepared shared file */ + htlb_seg_info->fd = fd; + return 0; + } + + if (errno != ENOENT) { + ERROR("shared_file: can't open shared hugetlbfs file %s: %s\n", + file_path, strerror(errno)); + return -1; + } + + /* Doesn't exist, we have to prepare it ourselves */ + /* Permissions are modified by umask */ + fd = open(file_path_tmp, O_CREAT | O_EXCL | O_RDWR, 0666); + if (fd < 0) { + if (errno == EEXIST) { + /* Somebody got in to prepare first */ + sleep(1); + goto retry; + } + + ERROR("shared_file: can't open temp hugetlbfs file %s: %s\n", + file_path_tmp, strerror(errno)); + return -1; + } + + htlb_seg_info->fd = fd; + return 1; +} + +/** + * finished_prepare - callback for ACK'ing prepare is done + * @htlb_seg_info: pointer to program's segment data + * + * returns: 0, if successful + * -1, if failed + */ +static int finished_prepare(struct seg_info *htlb_seg_info, int success) +{ + int ret; + char file_path[PATH_MAX]; + char file_path_tmp[PATH_MAX+4]; + + ret = get_shared_file_name(htlb_seg_info, file_path); + if (ret < 0) { + ERROR("finished_prepare: get_shared_file() failed\n"); + abort(); + } + + strcpy(file_path_tmp, file_path); + strcat(file_path_tmp, ".tmp"); + + if (success) { + /* link to final location */ + ret = link(file_path_tmp, file_path); + if (ret != 0) { + ERROR("finished_prepare: unable to link %s to %s: %s\n", + file_path_tmp, file_path, strerror(errno)); + return -1; + } + } + + /* And clean up by unlinking the temp file */ + ret = unlink(file_path_tmp); + if (ret != 0) { + ERROR("finished_prepare: unable to unlink %s: %s\n", + file_path_tmp, strerror(errno)); + /* not return here, we can continue without the cleanup */ + } + + 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 + */ +static 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; + + /* 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; +} + /* * Subtle: Since libhugetlbfs depends on glibc, we allow it * it to be loaded before us. As part of its init functions, it @@ -510,17 +708,16 @@ static int maybe_prepare(int fd_state, s ret = prepare_segment(seg); if (ret < 0) { - /* notify daemon of failed prepare */ DEBUG("Failed to prepare segment\n"); - finished_prepare(seg, -1); + finished_prepare(seg, 0); return -1; } DEBUG("Prepare succeeded\n"); if (reply) { - ret = finished_prepare(seg, 0); + ret = finished_prepare(seg, 1); if (ret < 0) - DEBUG("Failed to communicate successful " - "prepare to hugetlbd\n"); + DEBUG("Failed to successfully unlock the " + "hugetlbfs file\n"); } return ret; } @@ -550,6 +747,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); Index: libhugetlbfs/hugetlbd.c =================================================================== --- libhugetlbfs.orig/hugetlbd.c 2006-10-24 16:05:10.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-24 16:05:10.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-24 16:05:10.000000000 +1000 +++ libhugetlbfs/hugeutils.c 2006-10-24 16:47:42.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-24 16:05:10.000000000 +1000 +++ libhugetlbfs/libhugetlbfs_internal.h 2006-10-24 16:48:26.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-24 16:05:33.000000000 +1000 +++ libhugetlbfs/tests/run_tests.sh 2006-10-24 16:35:48.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() { @@ -129,21 +137,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` } -- 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