diff options
author | Volker Lendecke <vl@samba.org> | 2017-05-19 16:57:00 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2017-06-15 13:19:14 +0200 |
commit | 4b2826646bbcd9f84fe6e29417bd403f9e856ffc (patch) | |
tree | 161883a11e06d9dbbf5d00355cac89a07dfffaf8 | |
parent | 8f1cf7b4309cddc55feaceaff76db15305265567 (diff) | |
download | samba-4b2826646bbcd9f84fe6e29417bd403f9e856ffc.tar.gz |
g_lock: Allow lock upgrade/downgrade
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r-- | source3/lib/g_lock.c | 45 | ||||
-rw-r--r-- | source3/torture/test_g_lock.c | 2 |
2 files changed, 32 insertions, 15 deletions
diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c index db2f62ad9d4..9f3d6cc8b5e 100644 --- a/source3/lib/g_lock.c +++ b/source3/lib/g_lock.c @@ -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; diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c index 5a1ee605ead..ac45174a438 100644 --- a/source3/torture/test_g_lock.c +++ b/source3/torture/test_g_lock.c @@ -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; |