X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fopen.c;h=56514ae533a4c925635e5df350ad690bff34710d;hp=56f606664519ba286b0ffc1443d200480182fee7;hb=156e5eb92f1d986957cb081b58320579c6e366dd;hpb=2960e90f2d036935273d163593839d3777be7980 diff --git a/ccan/tdb2/open.c b/ccan/tdb2/open.c index 56f60666..56514ae5 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; } } @@ -99,12 +101,13 @@ static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb, else newdb.hdr.hash_seed = random_number(tdb); newdb.hdr.hash_test = TDB_HASH_MAGIC; - newdb.hdr.hash_test = tdb->khash(&newdb.hdr.hash_test, - sizeof(newdb.hdr.hash_test), - newdb.hdr.hash_seed, - tdb->hash_priv); + newdb.hdr.hash_test = tdb->hash_fn(&newdb.hdr.hash_test, + sizeof(newdb.hdr.hash_test), + newdb.hdr.hash_seed, + tdb->hash_data); newdb.hdr.recovery = 0; newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK; + newdb.hdr.seqnum = 0; memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved)); /* Initial hashes are empty. */ memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable)); @@ -174,6 +177,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; } @@ -201,10 +205,11 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb->name = NULL; tdb->direct_access = 0; tdb->flags = tdb_flags; - tdb->logfn = NULL; + tdb->log_fn = NULL; tdb->transaction = NULL; tdb->stats = NULL; tdb->access = NULL; + tdb->last_error = TDB_SUCCESS; tdb->file = NULL; tdb_hash_init(tdb); tdb_io_init(tdb); @@ -212,12 +217,12 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, while (attr) { switch (attr->base.attr) { case TDB_ATTRIBUTE_LOG: - tdb->logfn = attr->log.log_fn; - tdb->log_private = attr->log.log_private; + tdb->log_fn = attr->log.fn; + tdb->log_data = attr->log.data; break; case TDB_ATTRIBUTE_HASH: - tdb->khash = attr->hash.hash_fn; - tdb->hash_priv = attr->hash.hash_private; + tdb->hash_fn = attr->hash.fn; + tdb->hash_data = attr->hash.data; break; case TDB_ATTRIBUTE_SEED: seed = &attr->seed; @@ -240,7 +245,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT - | TDB_NOSYNC)) { + | TDB_NOSYNC | TDB_SEQNUM)) { ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, "tdb_open: unknown flags %u", tdb_flags); goto fail; @@ -273,6 +278,16 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, if (ecode != TDB_SUCCESS) { goto fail; } + if (name) { + tdb->name = strdup(name); + if (!tdb->name) { + ecode = tdb_logerr(tdb, TDB_ERR_OOM, + TDB_LOG_ERROR, + "tdb_open: failed to" + " allocate name"); + goto fail; + } + } tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed)); tdb->hash_seed = hdr.hash_seed; tdb_ftable_init(tdb); @@ -291,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 open file %s: %s", name, strerror(errno)); - goto fail; + goto fail_errno; } /* on exec, don't inherit the fd */ @@ -303,7 +318,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 +331,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 +340,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 +424,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); + free(cast_const(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); + tdb_lock_cleanup(tdb); + 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); @@ -484,20 +495,24 @@ int tdb_close(struct tdb_context *tdb) else tdb_munmap(tdb->file); } - free((char *)tdb->name); + free(cast_const(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_lock_cleanup(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