From 4aa785b1b23d0add18d5fec6fb6c5b37a6feecac Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 28 Mar 2004 02:18:38 +0000 Subject: merge some recent tdb changed from samba3 (This used to be commit 0e845ecd49841c620f7f9c5ba6c5bfbb0c572032) --- source4/lib/tdb/spinlock.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ source4/lib/tdb/tdb.c | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/source4/lib/tdb/spinlock.c b/source4/lib/tdb/spinlock.c index dc7fa3b784..1b789d4daa 100644 --- a/source4/lib/tdb/spinlock.c +++ b/source4/lib/tdb/spinlock.c @@ -149,6 +149,47 @@ static inline int __spin_is_locked(spinlock_t *lock) return (*lock != 1); } +#elif defined(MIPS_SPINLOCKS) && defined(sgi) && (_COMPILER_VERSION >= 730) + +/* Implement spinlocks on IRIX using the MIPSPro atomic fetch operations. See + * sync(3) for the details of the intrinsic operations. + * + * "sgi" and "_COMPILER_VERSION" are always defined by MIPSPro. + */ + +#if defined(STANDALONE) + +/* MIPSPro 7.3 has "__inline" as an extension, but not "inline. */ +#define inline __inline + +#endif /* STANDALONE */ + +/* Returns 0 if the lock is acquired, EBUSY otherwise. */ +static inline int __spin_trylock(spinlock_t *lock) +{ + unsigned int val; + val = __lock_test_and_set(lock, 1); + return val == 0 ? 0 : EBUSY; +} + +static inline void __spin_unlock(spinlock_t *lock) +{ + __lock_release(lock); +} + +static inline void __spin_lock_init(spinlock_t *lock) +{ + __lock_release(lock); +} + +/* Returns 1 if the lock is held, 0 otherwise. */ +static inline int __spin_is_locked(spinlock_t *lock) +{ + unsigned int val; + val = __add_and_fetch(lock, 0); + return val; +} + #elif defined(MIPS_SPINLOCKS) static inline unsigned int load_linked(unsigned long addr) @@ -227,7 +268,11 @@ static void yield_cpu(void) static int this_is_smp(void) { +#if defined(HAVE_SYSCONF) && defined(SYSCONF_SC_NPROC_ONLN) + return (sysconf(_SC_NPROC_ONLN) > 1) ? 1 : 0; +#else return 0; +#endif } /* diff --git a/source4/lib/tdb/tdb.c b/source4/lib/tdb/tdb.c index 5367842cbb..47ba2cb52c 100644 --- a/source4/lib/tdb/tdb.c +++ b/source4/lib/tdb/tdb.c @@ -247,10 +247,14 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, tdb->fd, offset, rw_type, lck_type)); return TDB_ERRCODE(TDB_ERR_LOCK_TIMEOUT, -1); } - /* Otherwise - generic lock error. */ - /* errno set by fcntl */ + /* Otherwise - generic lock error. errno set by fcntl. + * EAGAIN is an expected return from non-blocking + * locks. */ + if (errno != EAGAIN) { TDB_LOG((tdb, 5, "tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d: %s\n", - tdb->fd, offset, rw_type, lck_type, strerror(errno))); + tdb->fd, offset, rw_type, lck_type, + strerror(errno))); + } return TDB_ERRCODE(TDB_ERR_LOCK, -1); } return 0; @@ -858,6 +862,8 @@ static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length, tdb_off rec_ptr, last_ptr, newrec_ptr; struct list_struct newrec; + memset(&newrec, '\0', sizeof(newrec)); + if (tdb_lock(tdb, -1, F_WRLCK) == -1) return 0; @@ -1706,7 +1712,7 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, { TDB_CONTEXT *tdb; struct stat st; - int rev = 0, locked; + int rev = 0, locked = 0; unsigned char *vp; u32 vertest; @@ -1764,8 +1770,8 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, } /* 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)) - && (tdb_flags & TDB_CLEAR_IF_FIRST)) { + if ((tdb_flags & TDB_CLEAR_IF_FIRST) && + (locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))) { open_flags |= O_CREAT; if (ftruncate(tdb->fd, 0) == -1) { TDB_LOG((tdb, 0, "tdb_open_ex: " @@ -1838,10 +1844,19 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, name, strerror(errno))); goto fail; } + } + + /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if + we didn't get the initial exclusive lock as we need to let all other + users know we're using it. */ + + if (tdb_flags & TDB_CLEAR_IF_FIRST) { /* leave this lock in place to indicate it's in use */ if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) goto fail; + } + internal: /* Internal (memory-only) databases skip all the code above to @@ -2019,12 +2034,14 @@ void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , cons } -/* reopen a tdb - this is used after a fork to ensure that we have an independent +/* reopen a tdb - this can be used after a fork to ensure that we have an independent seek pointer from our parent and to re-establish locks */ int tdb_reopen(TDB_CONTEXT *tdb) { struct stat st; + if (tdb->flags & TDB_INTERNAL) + return 0; /* Nothing to do. */ if (tdb_munmap(tdb) != 0) { TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno))); goto fail; @@ -2045,7 +2062,7 @@ int tdb_reopen(TDB_CONTEXT *tdb) goto fail; } tdb_mmap(tdb); - if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) { + if ((tdb->flags & TDB_CLEAR_IF_FIRST) && (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) { TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n")); goto fail; } @@ -2063,7 +2080,10 @@ int tdb_reopen_all(void) TDB_CONTEXT *tdb; for (tdb=tdbs; tdb; tdb = tdb->next) { - if (tdb_reopen(tdb) != 0) return -1; + /* Ensure no clear-if-first. */ + tdb->flags &= ~TDB_CLEAR_IF_FIRST; + if (tdb_reopen(tdb) != 0) + return -1; } return 0; -- cgit