1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

dbwrap: Simplify dbwrap_lock_order_[un]lock()

Directly pass the database name and lock order to the core functions,
avoid passing struct db_context.

In the next steps these functions will become public: locking.tdb will
be based on g_lock.c to avoid holding a tdb-level locking.tdb mutex
while doing complex file system operations like unlink() which can
take ages on FAT for example.

This means that g_lock.c will participate in the dbwrap lock order
protection and needs access to dbwrap_lock_order_[un]lock() without
providing a direct db_context.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Volker Lendecke 2019-11-21 13:23:39 +01:00 committed by Jeremy Allison
parent 01db877c77
commit 38a80a3005

View File

@ -123,79 +123,96 @@ NTSTATUS dbwrap_record_delete(struct db_record *rec)
return NT_STATUS_OK; return NT_STATUS_OK;
} }
static void debug_lock_order(int level, struct db_context *dbs[]) const char *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
static void debug_lock_order(int level)
{ {
int i; int i;
DEBUG(level, ("lock order: ")); DEBUG(level, ("lock order: "));
for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) { for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) {
DEBUGADD(level, (" %d:%s", i + 1, dbs[i] ? dbs[i]->name : "<none>")); DEBUGADD(level,
(" %d:%s",
i + 1,
locked_dbs[i] ? locked_dbs[i] : "<none>"));
} }
DEBUGADD(level, ("\n")); DEBUGADD(level, ("\n"));
} }
static void dbwrap_lock_order_lock(struct db_context *db, static void dbwrap_lock_order_lock(const char *db_name,
struct db_context ***lockptr) enum dbwrap_lock_order lock_order)
{ {
static struct db_context *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
int idx; int idx;
DBG_INFO("check lock order %d for %s\n", (int)db->lock_order, DBG_INFO("check lock order %d for %s\n",
db->name); (int)lock_order,
db_name);
if (!DBWRAP_LOCK_ORDER_VALID(db->lock_order)) { if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
DBG_ERR("Invalid lock order %d of %s\n", DBG_ERR("Invalid lock order %d of %s\n",
(int)db->lock_order, db->name); lock_order,
db_name);
smb_panic("lock order violation"); smb_panic("lock order violation");
} }
for (idx=db->lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) { for (idx=lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) {
if (locked_dbs[idx] != NULL) { if (locked_dbs[idx] != NULL) {
DBG_ERR("Lock order violation: Trying %s at %d while " DBG_ERR("Lock order violation: Trying %s at %d while "
"%s at %d is locked\n", "%s at %d is locked\n",
db->name, (int)db->lock_order, db_name,
locked_dbs[idx]->name, idx + 1); (int)lock_order,
debug_lock_order(0, locked_dbs); locked_dbs[idx],
idx + 1);
debug_lock_order(0);
smb_panic("lock order violation"); smb_panic("lock order violation");
} }
} }
locked_dbs[db->lock_order-1] = db; locked_dbs[lock_order-1] = db_name;
*lockptr = &locked_dbs[db->lock_order-1];
debug_lock_order(10, locked_dbs); debug_lock_order(10);
} }
static void dbwrap_lock_order_unlock(struct db_context *db, static void dbwrap_lock_order_unlock(const char *db_name,
struct db_context **lockptr) enum dbwrap_lock_order lock_order)
{ {
DBG_INFO("release lock order %d for %s\n", DBG_INFO("release lock order %d for %s\n",
(int)db->lock_order, db->name); (int)lock_order,
db_name);
if (*lockptr == NULL) { if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
DBG_ERR("db %s at order %d unlocked\n", db->name, DBG_ERR("Invalid lock order %d of %s\n",
(int)db->lock_order); lock_order,
db_name);
smb_panic("lock order violation"); smb_panic("lock order violation");
} }
if (*lockptr != db) { if (locked_dbs[lock_order-1] == NULL) {
DBG_ERR("db %s at order %d unlocked\n",
db_name,
(int)lock_order);
smb_panic("lock order violation");
}
if (locked_dbs[lock_order-1] != db_name) {
DBG_ERR("locked db at lock order %d is %s, expected %s\n", DBG_ERR("locked db at lock order %d is %s, expected %s\n",
(int)(*lockptr)->lock_order, (*lockptr)->name, (int)lock_order,
db->name); locked_dbs[lock_order-1],
db_name);
smb_panic("lock order violation"); smb_panic("lock order violation");
} }
*lockptr = NULL; locked_dbs[lock_order-1] = NULL;
} }
struct dbwrap_lock_order_state { struct dbwrap_lock_order_state {
struct db_context *db; struct db_context *db;
struct db_context **lockptr;
}; };
static int dbwrap_lock_order_state_destructor( static int dbwrap_lock_order_state_destructor(
struct dbwrap_lock_order_state *s) struct dbwrap_lock_order_state *s)
{ {
dbwrap_lock_order_unlock(s->db, s->lockptr); struct db_context *db = s->db;
dbwrap_lock_order_unlock(db->name, db->lock_order);
return 0; return 0;
} }
@ -211,7 +228,7 @@ static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
} }
state->db = db; state->db = db;
dbwrap_lock_order_lock(db, &state->lockptr); dbwrap_lock_order_lock(db->name, db->lock_order);
talloc_set_destructor(state, dbwrap_lock_order_state_destructor); talloc_set_destructor(state, dbwrap_lock_order_state_destructor);
return state; return state;
@ -540,18 +557,16 @@ NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
struct db_record *rec; struct db_record *rec;
if (db->do_locked != NULL) { if (db->do_locked != NULL) {
struct db_context **lockptr = NULL;
NTSTATUS status; NTSTATUS status;
if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) { if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
dbwrap_lock_order_lock(db, &lockptr); dbwrap_lock_order_lock(db->name, db->lock_order);
} }
status = db->do_locked(db, key, fn, private_data); status = db->do_locked(db, key, fn, private_data);
if (db->lock_order != DBWRAP_LOCK_ORDER_NONE && if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
lockptr != NULL) { dbwrap_lock_order_unlock(db->name, db->lock_order);
dbwrap_lock_order_unlock(db, lockptr);
} }
return status; return status;