X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fopen.c;h=6d930be14f6f4b14faeb44e0beae7dbc3a59b1e1;hp=56f606664519ba286b0ffc1443d200480182fee7;hb=bb4d59ee1e914df9f8066e59a9c9a6604e581c40;hpb=2960e90f2d036935273d163593839d3777be7980 diff --git a/ccan/tdb2/open.c b/ccan/tdb2/open.c index 56f60666..6d930be1 100644 --- a/ccan/tdb2/open.c +++ b/ccan/tdb2/open.c @@ -1,4 +1,5 @@ #include "private.h" +#include /* all lock info, to detect double-opens (fcntl file don't nest!) */ static struct tdb_file *files = NULL; @@ -9,6 +10,7 @@ static struct tdb_file *find_file(dev_t device, ino_t ino) for (i = files; i; i = i->next) { if (i->device == device && i->inode == ino) { + i->refcnt++; break; } } @@ -174,6 +176,7 @@ static enum TDB_ERROR tdb_new_file(struct tdb_context *tdb) tdb->file->num_lockrecs = 0; tdb->file->lockrecs = NULL; tdb->file->allrecord_lock.count = 0; + tdb->file->refcnt = 1; return TDB_SUCCESS; } @@ -291,7 +294,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, "tdb_open: could not open file %s: %s", name, strerror(errno)); - goto fail; + goto fail_errno; } /* on exec, don't inherit the fd */ @@ -303,7 +306,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, "tdb_open: could not stat open %s: %s", name, strerror(errno)); - goto fail; + goto fail_errno; } ecode = tdb_new_file(tdb); @@ -316,13 +319,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb->file->inode = st.st_ino; tdb->file->map_ptr = NULL; tdb->file->map_size = sizeof(struct tdb_header); - } else { - /* FIXME */ - ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, - "tdb_open: %s (%d,%d) is already open in" - " this process", - name, (int)st.st_dev, (int)st.st_ino); - goto fail; } /* ensure there is only one process initialising at once */ @@ -332,7 +328,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } /* If they used O_TRUNC, read will return 0. */ - rlen = read(tdb->file->fd, &hdr, sizeof(hdr)); + rlen = pread(tdb->file->fd, &hdr, sizeof(hdr), 0); if (rlen == 0 && (open_flags & O_CREAT)) { ecode = tdb_new_database(tdb, seed, &hdr); if (ecode != TDB_SUCCESS) { @@ -416,51 +412,54 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, goto fail; } - /* Add to linked list. */ - files = tdb->file; + /* Add to linked list if we're new. */ + if (tdb->file->refcnt == 1) + files = tdb->file; return tdb; fail: /* Map ecode to some logical errno. */ - if (!saved_errno) { - switch (ecode) { - case TDB_ERR_CORRUPT: - case TDB_ERR_IO: - saved_errno = EIO; - break; - case TDB_ERR_LOCK: - saved_errno = EWOULDBLOCK; - break; - case TDB_ERR_OOM: - saved_errno = ENOMEM; - break; - case TDB_ERR_EINVAL: - saved_errno = EINVAL; - break; - default: - saved_errno = EINVAL; - break; - } + switch (ecode) { + case TDB_ERR_CORRUPT: + case TDB_ERR_IO: + saved_errno = EIO; + break; + case TDB_ERR_LOCK: + saved_errno = EWOULDBLOCK; + break; + case TDB_ERR_OOM: + saved_errno = ENOMEM; + break; + case TDB_ERR_EINVAL: + saved_errno = EINVAL; + break; + default: + saved_errno = EINVAL; + break; } +fail_errno: #ifdef TDB_TRACE close(tdb->tracefd); #endif free((char *)tdb->name); if (tdb->file) { tdb_unlock_all(tdb); - if (tdb->file->map_ptr) { - if (tdb->flags & TDB_INTERNAL) { - free(tdb->file->map_ptr); - } else - tdb_munmap(tdb->file); + if (--tdb->file->refcnt == 0) { + assert(tdb->file->num_lockrecs == 0); + if (tdb->file->map_ptr) { + if (tdb->flags & TDB_INTERNAL) { + free(tdb->file->map_ptr); + } else + tdb_munmap(tdb->file); + } + if (close(tdb->file->fd) != 0) + tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: failed to close tdb fd" + " on error: %s", strerror(errno)); + free(tdb->file->lockrecs); + free(tdb->file); } - if (close(tdb->file->fd) != 0) - tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: failed to close tdb fd" - " on error: %s", strerror(errno)); - free(tdb->file->lockrecs); - free(tdb->file); } free(tdb); @@ -487,17 +486,21 @@ int tdb_close(struct tdb_context *tdb) free((char *)tdb->name); if (tdb->file) { struct tdb_file **i; - ret = close(tdb->file->fd); - /* Remove from files list */ - for (i = &files; *i; i = &(*i)->next) { - if (*i == tdb->file) { - *i = tdb->file->next; - break; + tdb_unlock_all(tdb); + if (--tdb->file->refcnt == 0) { + ret = close(tdb->file->fd); + + /* Remove from files list */ + for (i = &files; *i; i = &(*i)->next) { + if (*i == tdb->file) { + *i = tdb->file->next; + break; + } } + free(tdb->file->lockrecs); + free(tdb->file); } - free(tdb->file->lockrecs); - free(tdb->file); } #ifdef TDB_TRACE