]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
dsdb: Take out the transaction and prepare_commit locks in the same order
authorAndrew Bartlett <abartlet@samba.org>
Wed, 3 May 2017 20:51:30 +0000 (22:51 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 22 May 2017 23:13:25 +0000 (01:13 +0200)
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 <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
source4/dsdb/samdb/ldb_modules/partition.c

index b501ff1c0c5c3635167bbf878a99ee963bb7230a..f37b7513af644a1a5ce464562f9e6692c08bb9e0 100644 (file)
@@ -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);