From b8ba0103bf45670c31384c56d6cd63bbef760a0c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 3 May 2017 22:51:30 +0200 Subject: [PATCH] dsdb: Take out the transaction and prepare_commit locks in the same order We must, when starting the transaction and preparing to commit the transaction, take out the locks in the same order across all the databases, otherwise we may deadlock. Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam --- source4/dsdb/samdb/ldb_modules/partition.c | 32 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index b501ff1c0c5..f37b7513af6 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -815,6 +815,8 @@ static int partition_start_trans(struct ldb_module *module) if (ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> (metadata partition)"); } + + /* This order must match that in prepare_commit() */ ret = ldb_next_start_trans(module); if (ret != LDB_SUCCESS) { return ret; @@ -826,12 +828,6 @@ static int partition_start_trans(struct ldb_module *module) return ret; } - ret = partition_metadata_start_trans(module); - if (ret != LDB_SUCCESS) { - ldb_next_del_trans(module); - return ret; - } - for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> %s", @@ -849,6 +845,20 @@ static int partition_start_trans(struct ldb_module *module) } } + /* + * Because in prepare_commit this must come last, to ensure + * lock ordering we have to do this last here also + */ + ret = partition_metadata_start_trans(module); + if (ret != LDB_SUCCESS) { + /* Back it out, if it fails on one */ + for (i--; i >= 0; i--) { + ldb_next_del_trans(data->partitions[i]->module); + } + ldb_next_del_trans(module); + return ret; + } + data->in_transaction++; return LDB_SUCCESS; @@ -862,6 +872,11 @@ static int partition_prepare_commit(struct ldb_module *module) struct partition_private_data); int ret; + ret = ldb_next_prepare_commit(module); + if (ret != LDB_SUCCESS) { + return ret; + } + for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_prepare_commit() -> %s", @@ -880,11 +895,6 @@ static int partition_prepare_commit(struct ldb_module *module) ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_prepare_commit() -> (metadata partition)"); } - ret = ldb_next_prepare_commit(module); - if (ret != LDB_SUCCESS) { - return ret; - } - /* metadata prepare commit must come last, as other partitions could modify * the database inside the prepare commit method of a module */ return partition_metadata_prepare_commit(module); -- 2.11.4.GIT