]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
tdb: Factor out the retry loop from tdb_allrecord_upgrade
authorVolker Lendecke <vl@samba.org>
Sat, 16 Feb 2013 15:49:56 +0000 (16:49 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 19 Feb 2013 14:46:45 +0000 (15:46 +0100)
For the mutex code we will have to lock the hashchain and the record
lock area independently. So we will have to call the loop twice. And,
it's a small refactoring for the better anyway I think.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/tdb/common/lock.c

index 16963df097c852ebc7411cde133d84fe685546a8..25ed8779009c9d190906838510e3234770b60688 100644 (file)
@@ -198,14 +198,42 @@ int tdb_brunlock(struct tdb_context *tdb,
 }
 
 /*
-  upgrade a read lock to a write lock. This needs to be handled in a
-  special way as some OSes (such as solaris) have too conservative
-  deadlock detection and claim a deadlock when progress can be
-  made. For those OSes we may loop for a while.
+ * Do a tdb_brlock in a loop. Some OSes (such as solaris) have too
+ * conservative deadlock detection and claim a deadlock when progress can be
+ * made. For those OSes we may loop for a while.
+ */
+
+static int tdb_brlock_retry(struct tdb_context *tdb,
+                           int rw_type, tdb_off_t offset, size_t len,
+                           enum tdb_lock_flags flags)
+{
+       int count = 1000;
+
+       while (count--) {
+               struct timeval tv;
+               int ret;
+
+               ret = tdb_brlock(tdb, rw_type, offset, len, flags);
+               if (ret == 0) {
+                       return 0;
+               }
+               if (errno != EDEADLK) {
+                       break;
+               }
+               /* sleep for as short a time as we can - more portable than usleep() */
+               tv.tv_sec = 0;
+               tv.tv_usec = 1;
+               select(0, NULL, NULL, NULL, &tv);
+       }
+       return -1;
+}
+
+/*
+  upgrade a read lock to a write lock.
 */
 int tdb_allrecord_upgrade(struct tdb_context *tdb)
 {
-       int count = 1000;
+       int ret;
 
        if (tdb->allrecord_lock.count != 1) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR,
@@ -220,21 +248,12 @@ int tdb_allrecord_upgrade(struct tdb_context *tdb)
                return -1;
        }
 
-       while (count--) {
-               struct timeval tv;
-               if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
-                              TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
-                       tdb->allrecord_lock.ltype = F_WRLCK;
-                       tdb->allrecord_lock.off = 0;
-                       return 0;
-               }
-               if (errno != EDEADLK) {
-                       break;
-               }
-               /* sleep for as short a time as we can - more portable than usleep() */
-               tv.tv_sec = 0;
-               tv.tv_usec = 1;
-               select(0, NULL, NULL, NULL, &tv);
+       ret = tdb_brlock_retry(tdb, F_WRLCK, FREELIST_TOP, 0,
+                              TDB_LOCK_WAIT|TDB_LOCK_PROBE);
+       if (ret == 0) {
+               tdb->allrecord_lock.ltype = F_WRLCK;
+               tdb->allrecord_lock.off = 0;
+               return 0;
        }
        TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
        return -1;