diff -Naur linux-2.4.22-5um.orig/arch/um/include/filemap.h linux-2.4.22-5um.new/arch/um/include/filemap.h --- linux-2.4.22-5um.orig/arch/um/include/filemap.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.22-5um.new/arch/um/include/filemap.h Thu Sep 25 20:29:17 2003 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2003 Steve Schmidtke + * Licensed under the GPL + */ + +#ifndef __FILEMAP_H__ +#define __FILEMAP_H__ + +extern int filemap_access(const char* table_name, const char* file_name); +extern int filemap_aquire(const char* table_name, const char* file_name); +extern int filemap_release(const char* table_name, int fd); + +#endif diff -Naur linux-2.4.22-5um.orig/arch/um/kernel/Makefile linux-2.4.22-5um.new/arch/um/kernel/Makefile --- linux-2.4.22-5um.orig/arch/um/kernel/Makefile Thu Sep 25 19:29:45 2003 +++ linux-2.4.22-5um.new/arch/um/kernel/Makefile Thu Sep 25 20:29:17 2003 @@ -11,7 +11,7 @@ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ - um_arch.o umid.o user_syms.o user_util.o + um_arch.o umid.o user_syms.o user_util.o filemap.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -29,7 +29,7 @@ # building anything in export-objs USER_OBJS = $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ - process.o tempfile.o time.o umid.o user_util.o + process.o tempfile.o time.o umid.o user_util.o filemap.o DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ diff -Naur linux-2.4.22-5um.orig/arch/um/kernel/filemap.c linux-2.4.22-5um.new/arch/um/kernel/filemap.c --- linux-2.4.22-5um.orig/arch/um/kernel/filemap.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.22-5um.new/arch/um/kernel/filemap.c Thu Sep 25 20:29:17 2003 @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2003 Steve Schmidtke + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include "init.h" +#include "sys/types.h" +#include "unistd.h" +#include "fcntl.h" + +#define STRFD_ISEND(c) ((c == '\0') || (c == ',') || (c == '-')) + +struct filemap_entry { + struct filemap_entry* next; + char* name; + int fd; + int count; + int cf; /* initial close on exec flag */ +}; + +struct filemap_ops { + int (*parse)(void* table, char* str); + int (*access)(void* table, char* filename); + int (*aquire)(void* table, char* filename); + int (*release)(void* table, int fd); + int (*shutdown)(void* table); +}; + +struct filemap_table { + char* name; + struct filemap_entry* entries; + struct filemap_ops* ops; +}; + +static struct filemap_entry* filemap_entry_alloc(void) +{ + return(malloc(sizeof(struct filemap_entry))); +} + +/* FIXME: the os_* versions of these routines below may recurse? */ + +static void seek_file(int fd, off_t offset) +{ + lseek(fd, offset, SEEK_SET); +} + +static int get_close_on_exec(int fd, int* close_on_exec) +{ + int ret; + + do { + ret = fcntl(fd, F_GETFD); + } while(ret<0 && errno==EINTR) ; + + if(ret < 0) + return(-errno); + + *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; + + return(ret); +} + +static int set_close_on_exec(int fd, int close_on_exec) +{ + int flag, err; + + if(close_on_exec) flag = FD_CLOEXEC; + else flag = 0; + + do { + err = fcntl(fd, F_SETFD, flag); + } while(err<0 && errno==EINTR) ; + + if(err < 0) + return(-errno); + + return(err); +} + +/* + * Add a fd (and filename) to a table in the db. + */ +static int filemap_add_entry(struct filemap_table* table, + int fdesc, char* file_name) +{ + struct filemap_entry* entry; + struct filemap_entry* dup; + int coeflag; + int err; + + if((table == NULL) || (fdesc < 0)) { + return(-EINVAL); + } + + dup = NULL; + for(entry = table->entries; entry; entry = entry->next) { + if(!dup && (fdesc == entry->fd)) { + dup = entry; + } + } + + if(dup) { + coeflag = dup->cf; + } else { + err = get_close_on_exec(fdesc, &coeflag); + if(err < 0) { + printk("filemap_add_entry: get close-on-exec flag" + " failed errno=%d fd=%d name=%s\n", + err, fdesc, file_name); + return(err); + } + + /* by default, exec calls should close filemaps */ + err = set_close_on_exec(fdesc, 1); + if(err < 0) { + printk("filemap_add_entry: set close-on-exec flag" + " failed errno=%d fd=%d name=%s\n", + err, fdesc, file_name); + return(err); + } + } + + entry = filemap_entry_alloc(); + if(entry == NULL) { + printk("filemap_add_entry: alloc failed fd=%d, name=%s\n", + fdesc, file_name); + return(-ENOMEM); + } + + printk("installing filemap: table=%s fd=%d, c-o-e=%d name=%s\n", + table->name, fdesc, coeflag, file_name); + + *entry = ((struct filemap_entry) { + .next = table->entries, + .name = file_name, + .fd = fdesc, + .count = 0, + .cf = coeflag + }); + + table->entries = entry; + + return(0); +} + +/* + * Find the matching filename in the db and return the filemap entry. + */ +static struct filemap_entry* filemap_lookup_name(struct filemap_table* table, + const char* file_name) +{ + struct filemap_entry* entry; + + for(entry = table->entries; entry; entry = entry->next) { + if(strcmp(file_name, entry->name) == 0) { + return(entry); + } + } + + return(NULL); +} + +/* + * Find a fresh file descriptor in a file pool + */ +static struct filemap_entry* filemap_lookup_unused(struct filemap_table* table) +{ + struct filemap_entry* entry; + + for(entry = table->entries; entry; entry = entry->next) { + if(entry->count == 0) { + return(entry); + } + } + + return(NULL); +} + +/* + * Find a matching fd in the db and return a filemap entry. + */ +static struct filemap_entry* filemap_lookup_fd(struct filemap_table* table, + const int fd) +{ + struct filemap_entry* entry; + + for(entry = table->entries; entry; entry = entry->next) { + if(fd == entry->fd) { + return(entry); + } + } + + return(NULL); +} + +/* + * set the filemapped file as pristine as possible + */ +static int filemap_scrub(struct filemap_entry* entry) +{ + int err; + + err = set_close_on_exec(entry->fd, entry->cf); + if(err < 0) { + printk("filemap_scrub: reset close-on-exec flag failed" + " err=%d fd=%d c-o-e=%d name=%s\n", + err, entry->fd, entry->cf, entry->name); + return(err); + } + + return(0); +} + +/* + * Return a disposable file descriptor for the one provided. + * dup() is used to guard against a close of the fd that was passed + * in. This is not ideal as concurrent uses of the same file may + * wreak havoc with the shared position pointer, etc. between the + * duplicated file descriptors. + */ +static int filemap_newfd(int oldfd) +{ + int newfd, err; + + if(oldfd < 0) + return(-EINVAL); + + do { + newfd = dup(oldfd); + } while(newfd<0 && errno==EINTR) ; + + if(newfd < 0) + return(-errno); + + err = set_close_on_exec(newfd, 0); + if(err < 0) { + printk("filemap_newfd: clear close-on-exec flag failed" + " err=%d fd=%d\n", err, newfd); + return(err); + } + + return(newfd); +} + +/* + * parse the setup string for a file descriptor (number) and + * return * a pointer on the next argument in the setup string. + */ +static __init char* set_fdesc(char* str, int* fd) +{ + char* end; + int num; + + if((str==NULL) || (*str=='\0')) + return(NULL); + + if(*str == ',') + return(str); + + num = strtoul(str, &end, 10); + if((end == str) || !STRFD_ISEND(*end)) { + printk("filemap: set_fd - invalid value '%s'\n", str); + goto endout; + } + + *fd = num; + +endout: + while(!STRFD_ISEND(*end)) end++; + if(*end == '\0') + return(NULL); + + return(end); +} + + +/************************************************ + *** Routines to support 'pool' type filemaps *** + ************************************************/ + +static int fm_pool_parse(void* data, char* str) +{ + struct filemap_table* table = data; + char* end; + unsigned int count; + int fdfirst, fdlast, err; + + end = set_fdesc(str, &fdfirst); + if(*end == '-') { + end = set_fdesc(end+1, &fdlast); + } else { + fdlast = fdfirst; + } + + /* NOTE: add_entry loop must interate first -> last *inclusive* */ + + if(fdfirst < fdlast) count = fdlast - fdfirst; + else count = fdfirst - fdlast; + + do { + err = filemap_add_entry(table, fdfirst, NULL); + if(err < 0) { + printk("WARNING: filemap error %d on '%s':'%s'\n", + err, table->name, str); + return(err); + } + + if(fdfirst < fdlast) fdfirst++; + else fdfirst--; + } while(count--) ; + + return(0); +} + +static int fm_pool_access(void* data, char* file_name) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + entry = filemap_lookup_unused(table); + + if(entry == NULL) + return(-ENOENT); + + entry->count++; + + return(entry->fd); +} + +static int fm_pool_aquire(void* data, char* file_name) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + int fd; + + entry = filemap_lookup_unused(table); + + if(entry == NULL) + return(-ENOENT); + + fd = filemap_newfd(entry->fd); + if(fd < 0) + return(fd); + + entry->count++; + + /* make sure this "new" file is rewound */ + seek_file(fd, 0); + + return(fd); +} + +static int fm_pool_release(void* data, int fd) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + /* the lookup_fd will always fail if the returned fd from _aquire is + * a dup of the real fd. This is OK: the caller will close the dup */ + entry=filemap_lookup_fd(table, fd); + + if(entry == NULL) + return(-ENOENT); + + if(entry->count > 0) + entry->count--; + + return(0); +} + +static int fm_pool_shutdown(void* data) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + for(entry = table->entries; entry; entry = entry->next) { + filemap_scrub(entry); + } + + return(0); +} + +static struct filemap_ops fm_ops_pool = { + .parse = fm_pool_parse, + .access = fm_pool_access, + .aquire = fm_pool_aquire, + .release = fm_pool_release, + .shutdown = fm_pool_shutdown, +}; + + +/************************************************ + *** Routines to support 'file' type filemaps *** + ************************************************/ + +static int fm_file_parse(void* data, char* str) +{ + struct filemap_table* table = data; + char* file_name; + int fd, err; + + file_name = set_fdesc(str, &fd); + if(*file_name == ',') + file_name++; + + err = filemap_add_entry(table, fd, file_name); + if(err < 0) { + printk("WARNING: filemap error %d on '%s':'%s'\n", + err, table->name, str); + return(err); + } + + return(0); +} + +static int fm_file_access(void* data, char* file_name) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + entry = filemap_lookup_name(table, file_name); + + if(entry == NULL) + return(-ENOENT); + + return(entry->fd); +} + +static int fm_file_aquire(void* data, char* file_name) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + int fd; + + entry = filemap_lookup_name(table, file_name); + + if(entry == NULL) + return(-ENOENT); + + fd = filemap_newfd(entry->fd); + if(fd < 0) + return(fd); + + /* make sure this "new" file is rewound */ + seek_file(fd, 0); + + return(fd); +} + +static int fm_file_release(void* data, int fd) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + /* the lookup_fd will always fail if the returned fd from _aquire is + * a dup of the real fd. This is OK: the caller will close the dup */ + entry = filemap_lookup_fd(table, fd); + + if(entry == NULL) + return(-ENOENT); + + return(0); +} + +static int fm_file_shutdown(void* data) +{ + struct filemap_table* table = data; + struct filemap_entry* entry; + + for(entry = table->entries; entry; entry = entry->next) { + filemap_scrub(entry); + } + + return(0); +} + +static struct filemap_ops fm_ops_file = { + .parse = fm_file_parse, + .access = fm_file_access, + .aquire = fm_file_aquire, + .release = fm_file_release, + .shutdown = fm_file_shutdown, +}; + + +/*********************** + *** Filemap Tables *** + ***********************/ + +static struct filemap_table filemap_tables[] = { + { + .name = "file", + .entries = NULL, + .ops = &fm_ops_file, + }, + { + .name = "vm", + .entries = NULL, + .ops = &fm_ops_pool, + }, +}; + +static struct filemap_table* filemap_get_table(const char* table_name) +{ + struct filemap_table* table; + int i; + + i = 0; + + while(i < sizeof(filemap_tables)/sizeof(filemap_tables[0])) { + table = &filemap_tables[i]; + + if(strcmp(table_name, table->name) == 0) + return(table); + + i++; + } + + return(NULL); +} + + +/********************************** + *** Filemap Interface Routines *** + **********************************/ + +/* + * Return THE file descriptor for the given filename from the db table. + * This is a raw interface for functions, like stat() wrappers that promise + * not to do IO, close the fd, or otherwise fiddle with the file state. + */ +int filemap_access(const char* table_name, char* file_name) +{ + struct filemap_table* table; + int fd; + + table = filemap_get_table(table_name); + + if(table == NULL) { + printk("ERROR: unknown filemap table '%s'\n", table_name); + return(0); + } + + fd = table->ops->access(table, file_name); + + return(fd); +} + +/* + * Return A NEW file descriptor for the given filename from the db. + * Assume the modes of the file descriptor was set up to match what is + * being asked for. + */ +int filemap_aquire(const char* table_name, char* file_name) +{ + struct filemap_table* table; + int fd; + + table = filemap_get_table(table_name); + + if(table == NULL) { + printk("ERROR: unknown filemap table '%s'\n", table_name); + return(0); + } + + fd = table->ops->aquire(table, file_name); + + return(fd); +} + +/* + * "Release" the file descriptor. Do nothing - if not in the db, + * return -ENOENT. The caller would want to use the close() system + * call on the fd in that event. + */ +int filemap_release(const char* table_name, const int fd) +{ + struct filemap_table* table; + int err; + + table = filemap_get_table(table_name); + + if(table == NULL) { + printk("ERROR: unknown filemap table '%s'\n", table_name); + return(-ENOENT); /* the caller expects ENOENT */ + } + + err = table->ops->release(table, fd); + + return(err); +} + +/* + * Do any table cleanup necessary before power cycle + */ +static void filemap_shutdown(void) +{ + struct filemap_table* table; + int i; + + i = 0; + + while(i < sizeof(filemap_tables)/sizeof(filemap_tables[0])) + { + table = &filemap_tables[i]; + + table->ops->shutdown(table); + + i++; + } +} + +__uml_exitcall(filemap_shutdown); + +static int __init parse_filemap(char* str, int* add) +{ + struct filemap_table* table; + char* table_name; + int err; + + *add = 0; + + table_name = str; + while(*str && *str != ',') str++; + if(*str == ',') *str++ = '\0'; + + table = filemap_get_table(table_name); + + if(table == NULL) { + printk("ERROR: unknown filemap table '%s'\n", table_name); + return(0); + } + + err = table->ops->parse(table, str); + if(err < 0) { + printk("ERROR: filemap parse error %d on '%s':'%s'\n", + err, table_name, str); + return(0); + } + + return(0); +} + +__uml_setup("filemap=", parse_filemap, +"filemap=,[-][,]\n" +" Map to (already opened) into db table named
.\n" +" Common tables: file=normal files, vm=virtual memory. Examples for bash:\n" +" ./linux ubd0=fs.cow,fs.dat filemap=file,10,fs.dat 10/dev/shm/vm-$$.1 21<>/dev/shm/vm-$$.2\n" +); diff -Naur linux-2.4.22-5um.orig/arch/um/kernel/mem_user.c linux-2.4.22-5um.new/arch/um/kernel/mem_user.c --- linux-2.4.22-5um.orig/arch/um/kernel/mem_user.c Thu Sep 25 19:29:45 2003 +++ linux-2.4.22-5um.new/arch/um/kernel/mem_user.c Thu Sep 25 20:29:17 2003 @@ -47,6 +47,8 @@ #include "tempfile.h" #include "kern_constants.h" +#include "filemap.h" + extern struct mem_region physmem_region; #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" @@ -56,6 +58,12 @@ int fd, err; char zero; + fd = filemap_aquire("vm",NULL); + if(fd >= 0) { + ftruncate(fd, len); /* use 0 instead of len to zero contents */ + goto sizefile; + } + fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); if(fd < 0) { os_print_error(fd, "make_tempfile"); @@ -66,6 +74,8 @@ os_print_error(err, "change_mode"); exit(1); } + +sizefile: err = os_seek_file(fd, len); if(err < 0){ os_print_error(err, "seek_file"); diff -Naur linux-2.4.22-5um.orig/arch/um/kernel/umid.c linux-2.4.22-5um.new/arch/um/kernel/umid.c --- linux-2.4.22-5um.orig/arch/um/kernel/umid.c Thu Sep 25 19:29:45 2003 +++ linux-2.4.22-5um.new/arch/um/kernel/umid.c Thu Sep 25 20:29:17 2003 @@ -19,6 +19,8 @@ #include "user_util.h" #include "choose-mode.h" +#include "filemap.h" + #define UMID_LEN 64 #define UML_DIR "~/.uml/" @@ -68,8 +70,24 @@ { int n; - if(!umid_inited && make_umid(printk)) return(-1); + if(umid_inited) { + char path[MAXPATHLEN + 1]; /* XXX use buf instead? */ + + n = snprintf(path, sizeof(path), "%s%s/%s", + uml_dir, umid, name); + if((n < 0) || (n >= sizeof(path))) + return(-1); + + /* just test for existence in the filemap file table */ + if(filemap_access("file", path) >= 0) { + goto handle_name; + } + } + + if(make_umid(printk)) + return(-1); +handle_name: n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; if(n > len){ printk("umid_file_name : buffer too short\n"); diff -Naur linux-2.4.22-5um.orig/arch/um/os-Linux/file.c linux-2.4.22-5um.new/arch/um/os-Linux/file.c --- linux-2.4.22-5um.orig/arch/um/os-Linux/file.c Thu Sep 25 19:29:45 2003 +++ linux-2.4.22-5um.new/arch/um/os-Linux/file.c Thu Sep 25 20:29:17 2003 @@ -19,6 +19,8 @@ #include "user.h" #include "kern_util.h" +#include "filemap.h" + static void copy_stat(struct uml_stat *dst, struct stat64 *src) { *dst = ((struct uml_stat) { @@ -57,12 +59,22 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf) { struct stat64 sbuf; - int err; + int fd, err; + + fd = filemap_access("file", file_name); + if(fd >= 0) { + do { + err = fstat64(fd, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + goto did_stat; + } do { err = stat64(file_name, &sbuf); } while((err < 0) && (errno == EINTR)) ; +did_stat: if(err < 0) return(-errno); @@ -74,6 +86,26 @@ int os_access(const char* file, int mode) { int amode, err; + int fd, flags; + + fd = filemap_access("file", file); + if(fd >= 0) { + do { + flags = fcntl(fd, F_GETFL); + } while((flags < 0) && (errno == EINTR)) ; + + if(flags < 0) + return(-errno); + + if(mode & OS_ACC_X_OK) + return(-EACCES); /* XXX not executable not true? */ + if((mode & OS_ACC_W_OK) && !(flags&O_RDWR || flags&O_WRONLY)) + return(-EACCES); + if((mode & OS_ACC_R_OK) && (flags&O_WRONLY)) + return(-EACCES); + + return(0); + } amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; @@ -257,6 +289,12 @@ { int fd, f = 0; + fd = filemap_aquire("file", file); + if(fd >= 0) { + printk("filemap aquire: fd=%d, file=%s\n", fd, file); + goto setfd; + } + if(flags.r && flags.w) f = O_RDWR; else if(flags.r) f = O_RDONLY; else if(flags.w) f = O_WRONLY; @@ -271,6 +309,7 @@ if(fd < 0) return(-errno); +setfd: if(flags.cl && fcntl(fd, F_SETFD, 1)){ os_close_file(fd); return(-errno); @@ -300,6 +339,13 @@ void os_close_file(int fd) { +#if 0 + /* filemapped files will return something other than -ENOENT */ + if(filemap_release("file", fd) != -ENOENT) { + return; + } +#endif + close(fd); } @@ -574,6 +620,12 @@ struct sockaddr_un addr; int sock, err; + sock = filemap_aquire("file", file); + if(sock >= 0) { + printk("filemap aquire: fd=%d, file=%s\n", sock, file); + goto setfd; + } + sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (sock < 0){ printk("create_unix_socket - socket failed, errno = %d\n", @@ -581,13 +633,6 @@ return(-errno); } - if(close_on_exec) { - err = os_set_exec_close(sock, 1); - if(err < 0) - printk("create_unix_socket : close_on_exec failed, " - "err = %d", -err); - } - addr.sun_family = AF_UNIX; /* XXX Be more careful about overflow */ @@ -598,6 +643,14 @@ printk("create_listening_socket - bind failed, errno = %d\n", errno); return(-errno); + } + +setfd: + if(close_on_exec) { + err = os_set_exec_close(sock, 1); + if(err < 0) + printk("create_unix_socket : close_on_exec failed, " + "err = %d", -err); } return(sock); diff -Naur linux-2.4.22-5um.orig/arch/um/drivers/daemon_user.c linux-2.4.22-5um.new/arch/um/drivers/daemon_user.c --- linux-2.4.22-5um.orig/arch/um/drivers/daemon_user.c Thu Sep 25 19:29:45 2003 +++ linux-2.4.22-5um.new/arch/um/drivers/daemon_user.c Thu Sep 25 20:29:17 2003 @@ -18,6 +18,8 @@ #include "user.h" #include "os.h" +#include "filemap.h" + #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) enum request_type { REQ_NEW_CONTROL }; @@ -53,6 +55,13 @@ struct request_v3 req; int fd, n, err; + pri->control = filemap_aquire("file", ctl_addr->sun_path); + if(pri->control >= 0) { + printk("filemap aquire: fd=%d, file=%s\n", + pri->control, ctl_addr->sun_path); + goto have_control; + } + pri->control = socket(AF_UNIX, SOCK_STREAM, 0); if(pri->control < 0){ printk("daemon_open : control socket failed, errno = %d\n", @@ -68,6 +77,7 @@ goto out; } +have_control: fd = socket(AF_UNIX, SOCK_DGRAM, 0); if(fd < 0){ printk("daemon_open : data socket failed, errno = %d\n",