]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
g_lock: Allow lock upgrade/downgrade
authorVolker Lendecke <vl@samba.org>
Fri, 19 May 2017 14:57:00 +0000 (16:57 +0200)
committerVolker Lendecke <vl@samba.org>
Thu, 15 Jun 2017 11:19:14 +0000 (13:19 +0200)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/lib/g_lock.c
source3/torture/test_g_lock.c

index db2f62ad9d4b99db15a433a9bbe9336b4d009d1a..9f3d6cc8b5e48ee174f4127a36af4debc7dc7d1a 100644 (file)
@@ -257,7 +257,7 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
                               struct server_id *blocker)
 {
        TDB_DATA data, userdata;
-       size_t i, num_locks;
+       size_t i, num_locks, my_lock;
        struct g_lock_rec *locks, *tmp;
        NTSTATUS status;
        bool modified = false;
@@ -270,11 +270,27 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
                return status;
        }
 
+       my_lock = num_locks;    /* doesn't exist yet */
+
        for (i=0; i<num_locks; i++) {
-               if (serverid_equal(&self, &locks[i].pid)) {
-                       status = NT_STATUS_INTERNAL_ERROR;
-                       goto done;
+               struct g_lock_rec *lock = &locks[i];
+
+               if (serverid_equal(&self, &lock->pid)) {
+                       if (lock->lock_type == type) {
+                               status = NT_STATUS_WAS_LOCKED;
+                               goto done;
+                       }
+                       my_lock = i;
+                       break;
                }
+       }
+
+       for (i=0; i<num_locks; i++) {
+
+               if (i == my_lock) {
+                       continue;
+               }
+
                if (g_lock_conflicts(type, locks[i].lock_type)) {
                        struct server_id pid = locks[i].pid;
 
@@ -300,18 +316,19 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
                }
        }
 
-       tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
-                            num_locks+1);
-       if (tmp == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
+       if (my_lock >= num_locks) {
+               tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
+                                    num_locks+1);
+               if (tmp == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               locks = tmp;
+               my_lock = num_locks;
+               num_locks += 1;
        }
-       locks = tmp;
 
-       ZERO_STRUCT(locks[num_locks]);
-       locks[num_locks].pid = self;
-       locks[num_locks].lock_type = type;
-       num_locks += 1;
+       locks[my_lock] = (struct g_lock_rec){ .pid = self, .lock_type = type };
        modified = true;
 
        status = NT_STATUS_OK;
index 5a1ee605ead656d0739799817b63b3c4ec810706..ac45174a438be8c3afb071a6eb99741b8d5b20d7 100644 (file)
@@ -75,7 +75,7 @@ bool run_g_lock1(int dummy)
 
        status = g_lock_lock(ctx, lockname, G_LOCK_READ,
                             (struct timeval) { .tv_sec = 1 });
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
                fprintf(stderr, "Double lock got %s\n",
                        nt_errstr(status));
                goto fail;