--- ../samba-orig/source/tdb/tdb.h Wed Feb 5 16:25:48 2003 +++ source/tdb/tdb.h Sun Feb 15 08:28:24 2004 @@ -96,6 +96,7 @@ ino_t inode; /* uniquely identifies this tdb */ void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */ int open_flags; /* flags used in the open - needed by reopen */ + int fd_active_lock; } TDB_CONTEXT; typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *); --- ../samba-orig/source/tdb/tdb.c Thu Feb 12 21:07:18 2004 +++ source/tdb/tdb.c Sun Feb 15 10:06:33 2004 @@ -69,6 +69,7 @@ /* lock offsets */ #define GLOBAL_LOCK 0 #define ACTIVE_LOCK 4 +#define USE_ACTIVE_LOCK 1 #ifndef MAP_FILE #define MAP_FILE 0 @@ -182,8 +183,8 @@ On error, errno is also set so that errors are passed back properly through tdb_open(). */ -static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, - int rw_type, int lck_type, int probe) +static int tdb_brlock_fd(TDB_CONTEXT *tdb, int fd, tdb_off offset, + int rw_type, int lck_type, int probe) { struct flock fl; int ret; @@ -202,7 +203,7 @@ fl.l_pid = 0; do { - ret = fcntl(tdb->fd,lck_type,&fl); + ret = fcntl(fd,lck_type,&fl); if (ret == -1 && errno == EINTR && palarm_fired && *palarm_fired) break; } while (ret == -1 && errno == EINTR); @@ -210,7 +211,7 @@ if (ret == -1) { if (!probe && lck_type != F_SETLK) { TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n", - tdb->fd, offset, rw_type, lck_type)); + fd, offset, rw_type, lck_type)); } /* Was it an alarm timeout ? */ if (errno == EINTR && palarm_fired && *palarm_fired) @@ -222,6 +223,13 @@ return 0; } + +static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, + int rw_type, int lck_type, int probe) +{ + return tdb_brlock_fd(tdb, tdb->fd, offset, rw_type, lck_type, probe); +} + /* lock a list in the database. list -1 is the alloc list */ static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype) { @@ -291,6 +299,87 @@ return ret; } + +#define OLD_ACTIVE_LOCK_CODE 0 + +#if OLD_ACTIVE_LOCK_CODE +static int tdb_active_lock_exclusive(TDB_CONTEXT *tdb) +{ + return tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0); +} + +static int tdb_active_lock_unlock(TDB_CONTEXT *tdb) +{ + return tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0); +} + +static int tdb_active_lock_shared(TDB_CONTEXT *tdb) +{ + return tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0); +} +#else + + +static int tdb_active_lock_create(TDB_CONTEXT *tdb) +{ + char *name = NULL; + + if (tdb->fd_active_lock != -1) { + return tdb->fd_active_lock; + } + + asprintf(&name, "%s.lck", tdb->name); + if (!name) { + TDB_LOG((tdb, 0, "Failed to allocate active lock name\n")); + errno = ENOMEM; + return -1; + } + tdb->fd_active_lock = open(name, O_CREAT|O_RDWR, 0600); + free(name); + if (tdb->fd_active_lock == -1) { + TDB_LOG((tdb, 0, "Failed to create active lock file\n")); + return -1; + } + return tdb->fd_active_lock; +} + +static int tdb_active_lock_exclusive(TDB_CONTEXT *tdb) +{ + int fd = tdb_active_lock_create(tdb); + if (fd == -1) { + return -1; + } + + return tdb_brlock_fd(tdb, fd, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0); +} + +static int tdb_active_lock_unlock(TDB_CONTEXT *tdb) +{ + int fd = tdb_active_lock_create(tdb); + if (fd == -1) { + return -1; + } + + return tdb_brlock_fd(tdb, fd, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0); +} + +static int tdb_active_lock_shared(TDB_CONTEXT *tdb) +{ + int fd = tdb_active_lock_create(tdb); + if (fd == -1) { + return -1; + } + + /* we also try to get an exclusive lock on the old active lock + range on the main tdb file. This greatly reduces the chance + of old tools from destroying our database */ + tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0); + + return tdb_brlock_fd(tdb, fd, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0); +} + +#endif + /* This is based on the hash algorithm from gdbm */ static u32 tdb_hash(TDB_DATA *key) { @@ -1679,6 +1768,7 @@ goto fail; } tdb->fd = -1; + tdb->fd_active_lock = -1; tdb->name = NULL; tdb->map_ptr = NULL; tdb->lockedkeys = NULL; @@ -1726,8 +1816,14 @@ goto fail; /* errno set by tdb_brlock */ } + if (!(tdb->name = (char *)strdup(name))) { + errno = ENOMEM; + goto fail; + } + /* we need to zero database if we are the only one with it open */ - if ((locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0)) +#if USE_ACTIVE_LOCK + if ((locked = (tdb_active_lock_exclusive(tdb) == 0)) && (tdb_flags & TDB_CLEAR_IF_FIRST)) { open_flags |= O_CREAT; if (ftruncate(tdb->fd, 0) == -1) { @@ -1737,15 +1833,17 @@ goto fail; /* errno set by ftruncate */ } } +#endif if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header) || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0 - || tdb->header.version != TDB_VERSION - || (tdb->header.hash_size != hash_size + || (tdb->header.version != TDB_VERSION && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) { /* its not a valid database - possibly initialise it */ if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) { errno = EIO; /* ie bad format or something */ + TDB_LOG((tdb, 0, "Failed to open hash=%d tdbhash=%d\n", + hash_size, tdb->header.hash_size)); goto fail; } rev = (tdb->flags & TDB_CONVERT); @@ -1772,11 +1870,6 @@ goto fail; } - if (!(tdb->name = (char *)strdup(name))) { - errno = ENOMEM; - goto fail; - } - tdb->map_size = st.st_size; tdb->device = st.st_dev; tdb->inode = st.st_ino; @@ -1796,16 +1889,21 @@ "failed to clear spinlock\n")); goto fail; } - if (tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) { +#if USE_ACTIVE_LOCK + if (tdb_active_lock_unlock(tdb) == -1) { TDB_LOG((tdb, 0, "tdb_open_ex: " - "failed to take ACTIVE_LOCK on %s: %s\n", + "failed to release ACTIVE_LOCK on %s: %s\n", name, strerror(errno))); goto fail; } +#endif } + +#if USE_ACTIVE_LOCK /* leave this lock in place to indicate it's in use */ - if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) + if (tdb_active_lock_shared(tdb) == -1) goto fail; +#endif internal: /* Internal (memory-only) databases skip all the code above to @@ -1836,6 +1934,9 @@ if (tdb->fd != -1) if (close(tdb->fd) != 0) TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n")); + if (tdb->fd_active_lock != -1) + if (close(tdb->fd_active_lock) != 0) + TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd_active_lock on error!\n")); SAFE_FREE(tdb->locked); SAFE_FREE(tdb); errno = save_errno; @@ -1861,6 +1962,8 @@ SAFE_FREE(tdb->name); if (tdb->fd != -1) ret = close(tdb->fd); + if (tdb->fd_active_lock != -1) + ret = close(tdb->fd_active_lock); SAFE_FREE(tdb->locked); SAFE_FREE(tdb->lockedkeys); @@ -2026,6 +2129,9 @@ } if (close(tdb->fd) != 0) TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n")); + if (close(tdb->fd_active_lock) != 0) + TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd_active_lock failed!\n")); + tdb->fd_active_lock = -1; tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0); if (tdb->fd == -1) { TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno))); @@ -2040,10 +2146,12 @@ goto fail; } tdb_mmap(tdb); - if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) { +#if USE_ACTIVE_LOCK + if (tdb_active_lock_shared(tdb) == -1) { TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n")); goto fail; } +#endif END_PROFILE(tdb_reopen); return 0;