summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2017-05-19 16:57:00 +0200
committerVolker Lendecke <vl@samba.org>2017-06-15 13:19:14 +0200
commit4b2826646bbcd9f84fe6e29417bd403f9e856ffc (patch)
tree161883a11e06d9dbbf5d00355cac89a07dfffaf8
parent8f1cf7b4309cddc55feaceaff76db15305265567 (diff)
downloadsamba-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.c45
-rw-r--r--source3/torture/test_g_lock.c2
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;