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

s3: Add a "lock_order" argument to db_open

This will be used to enforce a lock hierarchy between the databases. We have
seen deadlocks between locking.tdb, brlock.tdb, serverid.tdb and notify*.tdb.
These should be fixed by refusing a dbwrap_fetch_locked that does not follow a
defined lock hierarchy.
This commit is contained in:
Volker Lendecke 2012-01-06 17:19:54 +01:00 committed by Volker Lendecke
parent e75c436fe6
commit 45e61fcf61
30 changed files with 97 additions and 40 deletions

View File

@ -53,7 +53,8 @@ static bool init_group_mapping(void)
}
db = db_open(NULL, state_path("group_mapping.tdb"), 0,
TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
DEBUG(0, ("Failed to open group mapping database: %s\n",
strerror(errno)));

View File

@ -36,7 +36,8 @@ static struct db_context *connections_db_ctx(bool rw)
open_flags = rw ? (O_RDWR|O_CREAT) : O_RDONLY;
db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH|TDB_DEFAULT, open_flags, 0644);
TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH|TDB_DEFAULT,
open_flags, 0644, DBWRAP_LOCK_ORDER_1);
return db_ctx;
}

View File

@ -62,11 +62,26 @@ bool db_is_local(const char *name)
struct db_context *db_open(TALLOC_CTX *mem_ctx,
const char *name,
int hash_size, int tdb_flags,
int open_flags, mode_t mode)
int open_flags, mode_t mode,
enum dbwrap_lock_order lock_order)
{
struct db_context *result = NULL;
#ifdef CLUSTER_SUPPORT
const char *sockname = lp_ctdbd_socket();
const char *sockname;
#endif
if ((lock_order != DBWRAP_LOCK_ORDER_1) &&
(lock_order != DBWRAP_LOCK_ORDER_2)) {
/*
* Only allow 2 levels. ctdb gives us 3, and we will
* have the watchers database soon.
*/
errno = EINVAL;
return NULL;
}
#ifdef CLUSTER_SUPPORT
sockname = lp_ctdbd_socket();
if(!sockname || !*sockname) {
sockname = CTDB_PATH;

View File

@ -29,6 +29,11 @@ struct db_context;
*/
bool db_is_local(const char *name);
enum dbwrap_lock_order {
DBWRAP_LOCK_ORDER_1 = 1,
DBWRAP_LOCK_ORDER_2 = 2
};
/**
* Convenience function that will determine whether to
* open a tdb database via the tdb backend or via the ctdb
@ -38,6 +43,7 @@ bool db_is_local(const char *name);
struct db_context *db_open(TALLOC_CTX *mem_ctx,
const char *name,
int hash_size, int tdb_flags,
int open_flags, mode_t mode);
int open_flags, mode_t mode,
enum dbwrap_lock_order lock_order);
#endif /* __DBWRAP_OPEN_H__ */

View File

@ -23,6 +23,8 @@
#ifndef __DBWRAP_PRIVATE_H__
#define __DBWRAP_PRIVATE_H__
#include "dbwrap/dbwrap_open.h"
struct db_record {
TDB_DATA key, value;
NTSTATUS (*store)(struct db_record *rec, TDB_DATA data, int flag);

View File

@ -60,7 +60,8 @@ struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
result->db = db_open(result, lock_path("g_lock.tdb"), 0,
TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
O_RDWR|O_CREAT, 0600);
O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_2);
if (result->db == NULL) {
DEBUG(1, ("g_lock_init: Could not open g_lock.tdb\n"));
TALLOC_FREE(result);

View File

@ -76,7 +76,8 @@ static struct db_context *serverid_db(void)
return db;
}
db = db_open(NULL, lock_path("serverid.tdb"), 0,
TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0644);
TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2);
return db;
}

View File

@ -34,7 +34,8 @@ static struct db_context *session_db_ctx(void)
session_db_ctx_ptr = db_open(NULL, lock_path("sessionid.tdb"), 0,
TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
O_RDWR | O_CREAT, 0644);
O_RDWR | O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
return session_db_ctx_ptr;
}

View File

@ -148,7 +148,8 @@ bool share_info_db_init(void)
}
share_db = db_open(NULL, state_path("share_info.tdb"), 0,
TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
if (share_db == NULL) {
DEBUG(0,("Failed to open share info database %s (%s)\n",
state_path("share_info.tdb"), strerror(errno) ));

View File

@ -290,7 +290,8 @@ void brl_init(bool read_only)
brlock_db = db_open(NULL, lock_path("brlock.tdb"),
lp_open_files_db_hash_size(), tdb_flags,
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644,
DBWRAP_LOCK_ORDER_2);
if (!brlock_db) {
DEBUG(0,("Failed to open byte range locking database %s\n",
lock_path("brlock.tdb")));

View File

@ -65,7 +65,8 @@ static bool locking_init_internal(bool read_only)
lock_db = db_open(NULL, lock_path("locking.tdb"),
lp_open_files_db_hash_size(),
TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
read_only?O_RDONLY:O_RDWR|O_CREAT, 0644);
read_only?O_RDONLY:O_RDWR|O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (!lock_db) {
DEBUG(0,("ERROR: Failed to initialise locking database\n"));

View File

@ -590,7 +590,8 @@ static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
become_root();
mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
O_RDONLY, 0600);
O_RDONLY, 0600,
DBWRAP_LOCK_ORDER_1);
unbecome_root();
if (mapping_db == NULL) {

View File

@ -59,7 +59,8 @@ static bool acl_tdb_init(void)
}
become_root();
acl_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
acl_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
unbecome_root();
if (acl_db == NULL) {

View File

@ -601,7 +601,8 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
/* now we know dbname is not NULL */
become_root();
db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_2);
unbecome_root();
if (db == NULL) {

View File

@ -220,12 +220,13 @@ bool init_account_policy(void)
}
db = db_open(NULL, state_path("account_policy.tdb"), 0, TDB_DEFAULT,
O_RDWR, 0600);
O_RDWR, 0600, DBWRAP_LOCK_ORDER_1);
if (db == NULL) { /* the account policies files does not exist or open
* failed, try to create a new one */
db = db_open(NULL, state_path("account_policy.tdb"), 0,
TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
DEBUG(0,("Failed to open account policy database\n"));
return False;

View File

@ -224,7 +224,8 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
* it to stay around after we return from here. */
tmp_db = db_open(NULL, tmp_fname, 0,
TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
DBWRAP_LOCK_ORDER_1);
if (tmp_db == NULL) {
DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
"[%s]\n", tmp_fname));
@ -290,7 +291,8 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
/* re-open the converted TDB */
orig_db = db_open(NULL, dbname, 0,
TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
DBWRAP_LOCK_ORDER_1);
if (orig_db == NULL) {
DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
"converted passdb TDB [%s]\n", dbname));
@ -440,7 +442,8 @@ static bool tdbsam_open( const char *name )
/* Try to open tdb passwd. Create a new one if necessary */
db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
DBWRAP_LOCK_ORDER_1);
if (db_sam == NULL) {
DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
"[%s]\n", name));

View File

@ -75,7 +75,8 @@ bool secrets_init_path(const char *private_dir)
}
db_ctx = db_open(NULL, fname, 0,
TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
if (db_ctx == NULL) {
DEBUG(0,("Failed to open %s\n", fname));

View File

@ -40,7 +40,7 @@ static struct db_context *get_printer_list_db(void)
}
db = db_open(NULL, PL_DB_NAME(), 0,
TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
O_RDWR|O_CREAT, 0644);
O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_1);
return db;
}

View File

@ -727,10 +727,12 @@ WERROR regdb_init(void)
}
regdb = db_open(NULL, state_path("registry.tdb"), 0,
REG_TDB_FLAGS, O_RDWR, 0600);
REG_TDB_FLAGS, O_RDWR, 0600,
DBWRAP_LOCK_ORDER_1);
if (!regdb) {
regdb = db_open(NULL, state_path("registry.tdb"), 0,
REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600);
REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1);
if (!regdb) {
werr = ntstatus_to_werror(map_nt_error_from_unix(errno));
DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n",
@ -844,7 +846,8 @@ WERROR regdb_open( void )
become_root();
regdb = db_open(NULL, state_path("registry.tdb"), 0,
REG_TDB_FLAGS, O_RDWR, 0600);
REG_TDB_FLAGS, O_RDWR, 0600,
DBWRAP_LOCK_ORDER_1);
if ( !regdb ) {
result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",

View File

@ -102,7 +102,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
notify->db_recursive = db_open(notify, lock_path("notify.tdb"),
0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
O_RDWR|O_CREAT, 0644);
O_RDWR|O_CREAT, 0644,
DBWRAP_LOCK_ORDER_2);
if (notify->db_recursive == NULL) {
talloc_free(notify);
return NULL;
@ -110,7 +111,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"),
0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
O_RDWR|O_CREAT, 0644);
O_RDWR|O_CREAT, 0644,
DBWRAP_LOCK_ORDER_2);
if (notify->db_onelevel == NULL) {
talloc_free(notify);
return NULL;

View File

@ -8561,7 +8561,7 @@ static bool run_local_dbtrans(int dummy)
TDB_DATA value;
db = db_open(talloc_tos(), "transtest.tdb", 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0600);
O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
printf("Could not open transtest.db\n");
return false;

View File

@ -463,7 +463,8 @@ int main(int argc, const char **argv)
goto done;
}
db = db_open(mem_ctx, dbname, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
db = db_open(mem_ctx, dbname, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
d_fprintf(stderr, "ERROR: could not open dbname\n");
goto done;

View File

@ -308,7 +308,8 @@ int main(int argc, const char *argv[])
tdb_flags |= TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH;
}
db = db_open(mem_ctx, db_name, 0, tdb_flags, O_RDWR | O_CREAT, 0644);
db = db_open(mem_ctx, db_name, 0, tdb_flags, O_RDWR | O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
d_fprintf(stderr, "failed to open db '%s': %s\n", db_name,

View File

@ -131,7 +131,8 @@ static int net_idmap_dump(struct net_context *c, int argc, const char **argv)
}
d_fprintf(stderr, _("dumping id mapping from %s\n"), dbfile);
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDONLY, 0);
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDONLY, 0,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
dbfile, strerror(errno));
@ -240,7 +241,8 @@ static int net_idmap_restore(struct net_context *c, int argc, const char **argv)
input = stdin;
}
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
dbfile, strerror(errno));
@ -444,7 +446,8 @@ static int net_idmap_delete(struct net_context *c, int argc, const char **argv)
}
d_fprintf(stderr, _("deleting id mapping from %s\n"), dbfile);
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR, 0);
db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR, 0,
DBWRAP_LOCK_ORDER_1);
if (db == NULL) {
d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
dbfile, strerror(errno));
@ -616,7 +619,8 @@ static int net_idmap_aclmapset(struct net_context *c, int argc, const char **arg
}
if (!(db = db_open(mem_ctx, argv[0], 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0600))) {
O_RDWR|O_CREAT, 0600,
DBWRAP_LOCK_ORDER_1))) {
d_fprintf(stderr, _("db_open failed: %s\n"), strerror(errno));
goto fail;
}

View File

@ -804,7 +804,8 @@ static bool check_open_db(struct check_ctx* ctx, const char* name, int oflags)
}
}
ctx->db = db_open(ctx, name, 0, TDB_DEFAULT, oflags, 0);
ctx->db = db_open(ctx, name, 0, TDB_DEFAULT, oflags, 0,
DBWRAP_LOCK_ORDER_1);
if (ctx->db == NULL) {
d_fprintf(stderr,
_("Could not open idmap db (%s) for writing: %s\n"),

View File

@ -354,7 +354,8 @@ static bool check_ctx_open_output(struct check_ctx *ctx)
ctx->opt.wipe = true;
}
ctx->odb = db_open(ctx, ctx->opt.output, 0, TDB_DEFAULT, oflags, 0644);
ctx->odb = db_open(ctx, ctx->opt.output, 0, TDB_DEFAULT, oflags, 0644,
DBWRAP_LOCK_ORDER_1);
if (ctx->odb == NULL) {
d_fprintf(stderr,
_("Could not open db (%s) for writing: %s\n"),
@ -366,7 +367,8 @@ static bool check_ctx_open_output(struct check_ctx *ctx)
static bool check_ctx_open_input(struct check_ctx *ctx) {
ctx->idb = db_open(ctx, ctx->fname, 0, TDB_DEFAULT, O_RDONLY, 0);
ctx->idb = db_open(ctx, ctx->fname, 0, TDB_DEFAULT, O_RDONLY, 0,
DBWRAP_LOCK_ORDER_1);
if (ctx->idb == NULL) {
d_fprintf(stderr,
_("Could not open db (%s) for reading: %s\n"),

View File

@ -455,7 +455,8 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
int result;
struct db_context *db;
db = db_open(NULL, lock_path("locking.tdb"), 0,
TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0);
TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
DBWRAP_LOCK_ORDER_1);
if (!db) {
d_printf("%s not initialised\n",

View File

@ -405,7 +405,8 @@ static NTSTATUS idmap_autorid_db_init(void)
/* Open idmap repository */
autorid_db = db_open(NULL, state_path("autorid.tdb"), 0,
TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (!autorid_db) {
DEBUG(0, ("Unable to open idmap_autorid database '%s'\n",

View File

@ -338,7 +338,8 @@ static NTSTATUS idmap_tdb_open_db(struct idmap_domain *dom)
DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
/* Open idmap repository */
db = db_open(mem_ctx, tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
db = db_open(mem_ctx, tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
if (!db) {
DEBUG(0, ("Unable to open idmap database\n"));
ret = NT_STATUS_UNSUCCESSFUL;

View File

@ -113,7 +113,8 @@ static NTSTATUS idmap_tdb2_open_db(struct idmap_domain *dom)
NT_STATUS_HAVE_NO_MEMORY(db_path);
/* Open idmap repository */
ctx->db = db_open(ctx, db_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
ctx->db = db_open(ctx, db_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644,
DBWRAP_LOCK_ORDER_1);
TALLOC_FREE(db_path);
if (ctx->db == NULL) {