author | Alberto Bertogli
<albertito@gmail.com> 2005-03-03 06:16:40 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-07-15 13:47:24 UTC |
parent | f926924d56de8e5ba5267d886b127353dbb6fa34 |
bindings/preload/libjio_preload.c | +135 | -12 |
diff --git a/bindings/preload/libjio_preload.c b/bindings/preload/libjio_preload.c index 6d201ec..26696af 100644 --- a/bindings/preload/libjio_preload.c +++ b/bindings/preload/libjio_preload.c @@ -58,11 +58,14 @@ static int (*c_ftruncate64)(int fd, off64_t length); static off_t (*c_lseek)(int fd, off_t offset, int whence); static off64_t (*c_lseek64)(int fd, off64_t offset, int whence); static int (*c_fsync)(int fd); +static int (*c_dup)(int oldfd); +static int (*c_dup2)(int oldfd, int newfd); /* file descriptor table, to translate fds to jfs */ struct fd_entry { int fd; + unsigned int *refcount; struct jfs *fs; pthread_mutex_t lock; }; @@ -96,6 +99,7 @@ static struct fd_entry fd_table[MAXFD]; if (called) \ fprintf(stderr, "\t"); \ called++; \ + fprintf(stderr, "%5.5d ", getpid()); \ fprintf(stderr, "%s(): ", __FUNCTION__ ); \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ @@ -108,26 +112,44 @@ static struct fd_entry fd_table[MAXFD]; * catch out of bounds accesses */ static inline int fd_lock(int fd) { + int r; + if (fd < 0 || fd >= MAXFD) { printd("locking out of bounds fd %d\n", fd); return 0; } //printd("L %d\n", fd); - pthread_mutex_lock(&(fd_table[fd].lock)); + r = pthread_mutex_lock(&(fd_table[fd].lock)); //printd("OK %d\n", fd); - return 1; + return !r; +} + +static inline int fd_trylock(int fd) +{ + int r; + + if (fd < 0 || fd >= MAXFD) { + printd("locking out of bounds fd %d\n", fd); + return 0; + } + //printd("L %d\n", fd); + r = pthread_mutex_trylock(&(fd_table[fd].lock)); + //printd("OK %d\n", fd); + return !r; } static inline int fd_unlock(int fd) { + int r; + if (fd < 0 || fd >= MAXFD) { printd("unlocking out of bounds fd %d\n", fd); return 0; } //printd("U %d\n", fd); - pthread_mutex_unlock(&(fd_table[fd].lock)); + r = pthread_mutex_unlock(&(fd_table[fd].lock)); //printd("OK %d\n", fd); - return 1; + return !r; } @@ -178,6 +200,8 @@ static int __attribute__((constructor)) init(void) libc_load(lseek); libc_load(lseek64); libc_load(fsync); + libc_load(dup); + libc_load(dup2); printd("done\n"); return 1; @@ -251,6 +275,8 @@ int open(const char *pathname, int flags, ...) fd_lock(fd); fd_table[fd].fd = fd; + fd_table[fd].refcount = malloc(sizeof(unsigned int)); + *fd_table[fd].refcount = 1; fd_table[fd].fs = fs; fd_unlock(fd); @@ -323,6 +349,8 @@ int open64(const char *pathname, int flags, ...) fd_lock(fd); fd_table[fd].fd = fd; + fd_table[fd].refcount = malloc(sizeof(unsigned int)); + *fd_table[fd].refcount = 1; fd_table[fd].fs = fs; fd_unlock(fd); @@ -330,6 +358,37 @@ int open64(const char *pathname, int flags, ...) return fd; } +/* close() is split in two functions: unlocked_close() that performs the real + * actual close and cleanup, and close() which takes care of the locking and + * calls unlocked_close(); this is because in dup*() we need to close with + * locks already held to avoid races. */ +int unlocked_close(int fd) +{ + int r; + + if (*fd_table[fd].refcount >= 1) { + /* we still have references, don't really close */ + printd("not closing, refcount: %d\n", *fd_table[fd].refcount); + *fd_table[fd].refcount--; + fd_table[fd].fd = -1; + fd_table[fd].refcount = NULL; + fd_table[fd].fs = NULL; + return 0; + } + + rec_inc(); + r = jclose(fd_table[fd].fs); + if (fd_table[fd].fs != NULL) { + fd_table[fd].fd = -1; + free(fd_table[fd].refcount); + fd_table[fd].refcount = NULL; + free(fd_table[fd].fs); + fd_table[fd].fs = NULL; + } + rec_dec(); + + return r; +} int close(int fd) { @@ -353,14 +412,7 @@ int close(int fd) } printd("libjio\n"); - rec_inc(); - r = jclose(fs); - if (fd_table[fd].fs != NULL) { - free(fd_table[fd].fs); - fd_table[fd].fd = -1; - fd_table[fd].fs = NULL; - } - rec_dec(); + r = unlocked_close(fd); fd_unlock(fd); printd("return %d\n", r); @@ -389,6 +441,77 @@ int unlink(const char *pathname) return r; } +int dup(int oldfd) +{ + int r; + + if (called) { + printd("orig\n"); + return (*c_dup)(oldfd); + } + + printd("libjio\n"); + + if (!fd_lock(oldfd)) { + printd("out of bounds fd: %d\n", fd); + return -1; + } + + rec_inc(); + r = (*c_dup)(oldfd); + rec_dec(); + + if (r >= 0) { + fd_lock(r); + fd_table[r].fd = r; + fd_table[r].refcount = fd_table[oldfd].refcount; + *fd_table[r].refcount++; + fd_table[r].fs = fd_table[oldfd].fs; + fd_unlock(r); + } + + fd_unlock(oldfd); + printd("return %d\n", r); + return r; +} + +int dup2(int oldfd, int newfd) +{ + int r; + + if (called) { + printd("orig\n"); + return (*c_dup2)(oldfd, newfd); + } + + printd("libjio\n"); + + if (!fd_lock(oldfd)) { + printd("out of bounds fd: %d\n", fd); + return -1; + } + + rec_inc(); + r = (*c_dup2)(oldfd, newfd); + rec_dec(); + + if (r >= 0) { + fd_lock(newfd); + if (fd_table[newfd].fs != NULL) { + unlocked_close(newfd); + } + fd_table[newfd].fd = newfd; + fd_table[newfd].refcount = fd_table[oldfd].refcount; + *fd_table[newfd].refcount++; + fd_table[newfd].fs = fd_table[oldfd].fs; + fd_unlock(newfd); + } + + fd_unlock(oldfd); + printd("return %d\n", r); + return r; +} + /* the rest of the functions are automagically generated from the following * macro. The ugliest. I'm so proud. */