1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

s3:locking: add current_share_mode_glck helper functions

We'll soon make use of callback functions passed to g_lock_lock(),
during these callback function we'll only be allowed to
call 'g_lock_lock_cb_state' based functions.

Given that nesting of share_mode call, we need to
make it transparent to the callers and the detail
that we optimize using g_lock_lock() callbacks.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15125

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Stefan Metzmacher 2022-08-29 12:50:20 +02:00 committed by Jeremy Allison
parent 17e496c6f9
commit b971a21aa3

View File

@ -75,6 +75,38 @@ struct share_mode_lock {
/* the locking database handle */
static struct g_lock_ctx *lock_ctx;
static struct g_lock_lock_cb_state *current_share_mode_glck = NULL;
static bool share_mode_g_lock_within_cb(TDB_DATA key);
static NTSTATUS share_mode_g_lock_dump(TDB_DATA key,
void (*fn)(struct server_id exclusive,
size_t num_shared,
const struct server_id *shared,
const uint8_t *data,
size_t datalen,
void *private_data),
void *private_data)
{
if (share_mode_g_lock_within_cb(key)) {
return g_lock_lock_cb_dump(current_share_mode_glck,
fn, private_data);
}
return g_lock_dump(lock_ctx, key, fn, private_data);
}
static NTSTATUS share_mode_g_lock_writev(TDB_DATA key,
const TDB_DATA *dbufs,
size_t num_dbufs)
{
if (share_mode_g_lock_within_cb(key)) {
return g_lock_lock_cb_writev(current_share_mode_glck,
dbufs, num_dbufs);
}
return g_lock_writev_data(lock_ctx, key, dbufs, num_dbufs);
}
static bool locking_init_internal(bool read_only)
{
@ -441,8 +473,7 @@ static NTSTATUS locking_tdb_data_fetch(
}
state.mem_ctx = result;
status = g_lock_dump(lock_ctx, key, locking_tdb_data_fetch_fn, &state);
status = share_mode_g_lock_dump(key, locking_tdb_data_fetch_fn, &state);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
/*
* Just return an empty record
@ -450,7 +481,7 @@ static NTSTATUS locking_tdb_data_fetch(
goto done;
}
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("g_lock_dump failed: %s\n",
DBG_ERR("share_mode_g_lock_dump failed: %s\n",
nt_errstr(status));
return status;
}
@ -487,9 +518,9 @@ static NTSTATUS locking_tdb_data_store(
/*
* Nothing to write
*/
status = g_lock_write_data(lock_ctx, key, NULL, 0);
status = share_mode_g_lock_writev(key, NULL, 0);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("g_lock_writev_data() failed: %s\n",
DBG_ERR("share_mode_g_lock_writev(NULL) failed: %s\n",
nt_errstr(status));
}
return status;
@ -521,9 +552,9 @@ static NTSTATUS locking_tdb_data_store(
num_share_mode_dbufs * sizeof(TDB_DATA));
}
status = g_lock_writev_data(lock_ctx, key, dbufs, ARRAY_SIZE(dbufs));
status = share_mode_g_lock_writev(key, dbufs, ARRAY_SIZE(dbufs));
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("g_lock_writev_data() failed: %s\n",
DBG_ERR("share_mode_g_lock_writev() failed: %s\n",
nt_errstr(status));
}
return status;
@ -732,6 +763,29 @@ static TDB_DATA share_mode_lock_key = {
};
static size_t share_mode_lock_key_refcount = 0;
static bool share_mode_g_lock_within_cb(TDB_DATA key)
{
int cmp;
if (current_share_mode_glck == NULL) {
return false;
}
cmp = tdb_data_cmp(share_mode_lock_key, key);
if (cmp != 0) {
struct file_id_buf existing;
DBG_ERR("Can not lock two share modes "
"simultaneously: existing %s requested %s\n",
file_id_str_buf(share_mode_lock_key_id, &existing),
hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
smb_panic(__location__);
return false;
}
return true;
}
/*
* We can only ever have one share mode locked. Use a static
* share_mode_data pointer that is shared by multiple nested
@ -823,14 +877,13 @@ static NTSTATUS get_static_share_mode_data(
SMB_ASSERT(static_share_mode_data == NULL);
status = g_lock_dump(
lock_ctx,
status = share_mode_g_lock_dump(
share_mode_lock_key,
get_static_share_mode_data_fn,
&state);
if (!NT_STATUS_IS_OK(status)) {
DBG_GET_SHARE_MODE_LOCK(status,
"g_lock_dump failed: %s\n",
"share_mode_g_lock_dump failed: %s\n",
nt_errstr(status));
return status;
}
@ -1051,6 +1104,11 @@ static void share_mode_wakeup_waiters_fn(
struct share_mode_lock *lck,
void *private_data)
{
if (share_mode_g_lock_within_cb(share_mode_lock_key)) {
g_lock_lock_cb_wake_watchers(current_share_mode_glck);
return;
}
g_lock_wake_watchers(lock_ctx, share_mode_lock_key);
}
@ -1125,12 +1183,12 @@ static NTSTATUS fsp_update_share_mode_flags(struct files_struct *fsp)
}
key = locking_key(&fsp->file_id);
status = g_lock_dump(lock_ctx, key,
status = share_mode_g_lock_dump(key,
fsp_update_share_mode_flags_fn,
&state);
if (!NT_STATUS_IS_OK(status)) {
/* no DBG_GET_SHARE_MODE_LOCK here! */
DBG_ERR("g_lock_dump returned %s\n",
DBG_ERR("share_mode_g_lock_dump returned %s\n",
nt_errstr(status));
return status;
}
@ -1364,6 +1422,7 @@ void share_mode_flags_set(
struct share_mode_watch_state {
bool blockerdead;
struct server_id blocker;
bool within_cb;
};
static void share_mode_watch_done(struct tevent_req *subreq);
@ -1385,9 +1444,19 @@ struct tevent_req *share_mode_watch_send(
return NULL;
}
subreq = g_lock_watch_data_send(state, ev, lock_ctx, key, blocker);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
if (share_mode_g_lock_within_cb(key)) {
state->within_cb = true;
subreq = g_lock_lock_cb_watch_data_send(state, ev,
current_share_mode_glck,
blocker);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
} else {
subreq = g_lock_watch_data_send(state, ev, lock_ctx, key, blocker);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
}
tevent_req_set_callback(subreq, share_mode_watch_done, req);
return req;
@ -1401,11 +1470,20 @@ static void share_mode_watch_done(struct tevent_req *subreq)
req, struct share_mode_watch_state);
NTSTATUS status;
status = g_lock_watch_data_recv(
subreq, &state->blockerdead, &state->blocker);
if (tevent_req_nterror(req, status)) {
return;
if (state->within_cb) {
status = g_lock_lock_cb_watch_data_recv(
subreq, &state->blockerdead, &state->blocker);
if (tevent_req_nterror(req, status)) {
return;
}
} else {
status = g_lock_watch_data_recv(
subreq, &state->blockerdead, &state->blocker);
if (tevent_req_nterror(req, status)) {
return;
}
}
tevent_req_done(req);
}
@ -1723,8 +1801,8 @@ static int share_mode_forall_fn(TDB_DATA key, void *private_data)
state->key = key;
status = g_lock_dump(
lock_ctx, key, share_mode_forall_dump_fn, private_data);
status = share_mode_g_lock_dump(
key, share_mode_forall_dump_fn, private_data);
if (!NT_STATUS_IS_OK(status)) {
DBG_GET_SHARE_MODE_LOCK(status,
"g_lock_dump failed: %s\n",