The branch, master has been updated via f8019ff... s4:dsdb Add a shortcut sequence number for schema reloads via fe3e1af... s4:dsdb Rework schema loading and add schema reloading via d0b5447... s4:dsdb Move dsdb_save_partition_usn() to be a module helper function via 639728a... s4:schema Expand the schema structure via 775c5ec... s4:dsdb Remove unused 'dsdb_make_schema_global' call from pyglue via 7fc94eb... s4:dsdb Add 'const' to some struct dsdb_schema variables via fc5a507... s4:dsdb Don't load the schema unconditionally from 8195832... s3: file_walk_table -> files_forall
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit f8019ff793a735563ccedf5581c72e015fd62014 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 18:44:51 2010 +1100 s4:dsdb Add a shortcut sequence number for schema reloads This uses the ldb sequence number, in a hope to detect an unchanged schema quicker. Andrew Bartlett commit fe3e1af901c970f738bee92baac5d7d4f5736e17 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 16:03:33 2010 +1100 s4:dsdb Rework schema loading and add schema reloading This commit reworks Samba4's schema loading code to detect when it needs to reload the schema. This is done by watching the @REPLCHANGED special DN. The reload happens by means of a callback, which is only set when the schema is loaded from the ldb - not when loaded from an LDIF file or DRS. We also rework the global schema handling - instead of storing the pointer to the global schema in each ldb, we store a flag indicating that the global schema should be returned at run time. This makes it much easier to switch to a new global schema. Andrew Bartlett commit d0b54476fc9f855d1e482597538a7ec60e04f331 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 16:00:39 2010 +1100 s4:dsdb Move dsdb_save_partition_usn() to be a module helper function This function should not traverse the module stack again, but instead run from this point. Also add a matching dsdb_module_load_partition_usn() and change repl_meta_data to match. Andrew Bartlett commit 639728a29873e4cf59dfa149a231eae353f3753a Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 15:41:51 2010 +1100 s4:schema Expand the schema structure We now store the location of the schema in the schema, and provide hooks for a future schema reloading mechanism. Andrew Bartlett commit 775c5ec1c57b4acf61c1c750c4832f64defcb5b6 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 15:20:47 2010 +1100 s4:dsdb Remove unused 'dsdb_make_schema_global' call from pyglue commit 7fc94eb9a7034c36943efbe04f4f4cdfb174c50e Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 15:19:55 2010 +1100 s4:dsdb Add 'const' to some struct dsdb_schema variables We don't currently require this, but we may move this way in future. commit fc5a507a86f37aecb6702d8c2c3bdc462e49f9fd Author: Andrew Bartlett <abart...@samba.org> Date: Mon Mar 22 15:17:58 2010 +1100 s4:dsdb Don't load the schema unconditionally Schema loads now come at a price, so avoid doing them if we don't have to (such as when doing an @REPLCHANGED or other special DN based search). Andrew Bartlett ----------------------------------------------------------------------- Summary of changes: source4/dsdb/common/util.c | 88 ------- source4/dsdb/samdb/ldb_modules/extended_dn_out.c | 7 +- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 23 +- source4/dsdb/samdb/ldb_modules/schema_data.c | 17 +- source4/dsdb/samdb/ldb_modules/schema_load.c | 296 ++++++++++++++-------- source4/dsdb/samdb/ldb_modules/util.c | 175 +++++++++++++ source4/dsdb/schema/schema.h | 11 + source4/dsdb/schema/schema_init.c | 2 + source4/dsdb/schema/schema_set.c | 80 ++++-- source4/lib/ldb_wrap.c | 5 +- source4/scripting/python/pyglue.c | 17 -- 11 files changed, 469 insertions(+), 252 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 9c29509..b469b06 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2585,94 +2585,6 @@ int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, return LDB_SUCCESS; } -/* - save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a - partition - */ -int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, - uint64_t uSN, uint64_t urgent_uSN) -{ - struct ldb_request *req; - struct ldb_message *msg; - struct dsdb_control_current_partition *p_ctrl; - int ret; - - msg = ldb_msg_new(ldb); - if (msg == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED"); - if (msg->dn == NULL) { - talloc_free(msg); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN); - if (ret != LDB_SUCCESS) { - talloc_free(msg); - return ret; - } - msg->elements[0].flags = LDB_FLAG_MOD_REPLACE; - - /* urgent_uSN is optional so may not be stored */ - if (urgent_uSN) { - ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN); - if (ret != LDB_SUCCESS) { - talloc_free(msg); - return ret; - } - msg->elements[1].flags = LDB_FLAG_MOD_REPLACE; - } - - - p_ctrl = talloc(msg, struct dsdb_control_current_partition); - if (p_ctrl == NULL) { - talloc_free(msg); - return LDB_ERR_OPERATIONS_ERROR; - } - p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION; - p_ctrl->dn = dn; - - ret = ldb_build_mod_req(&req, ldb, msg, - msg, - NULL, - NULL, ldb_op_default_callback, - NULL); -again: - if (ret != LDB_SUCCESS) { - talloc_free(msg); - return ret; - } - - ret = ldb_request_add_control(req, - DSDB_CONTROL_CURRENT_PARTITION_OID, - false, p_ctrl); - if (ret != LDB_SUCCESS) { - talloc_free(msg); - return ret; - } - - /* Run the new request */ - ret = ldb_request(ldb, req); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(req->handle, LDB_WAIT_ALL); - } - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - ret = ldb_build_add_req(&req, ldb, msg, - msg, - NULL, - NULL, ldb_op_default_callback, - NULL); - goto again; - } - - talloc_free(msg); - - return ret; -} - int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1, const struct drsuapi_DsReplicaCursor2 *c2) { diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c index b5f4567..f28ad8e 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c @@ -564,6 +564,11 @@ static int extended_dn_out_search(struct ldb_module *module, struct ldb_request struct extended_dn_out_private *p = talloc_get_type(ldb_module_get_private(module), struct extended_dn_out_private); + /* The schema manipulation does not apply to special DNs */ + if (ldb_dn_is_special(req->op.search.base)) { + return ldb_next_request(module, req); + } + /* check if there's an extended dn control */ control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID); if (control && control->data) { @@ -743,7 +748,7 @@ static int extended_dn_out_dereference_init(struct ldb_module *module, const cha struct dsdb_openldap_dereference_control *dereference_control; struct dsdb_attribute *cur; struct ldb_context *ldb = ldb_module_get_ctx(module); - struct dsdb_schema *schema; + const struct dsdb_schema *schema; ldb_module_set_private(module, p); diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index a7e2a48..8b4e012 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -454,15 +454,14 @@ static int replmd_notify_store(struct ldb_module *module) { struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); - struct ldb_context *ldb = ldb_module_get_ctx(module); while (replmd_private->ncs) { int ret; struct nc_entry *modified_partition = replmd_private->ncs; - ret = dsdb_save_partition_usn(ldb, modified_partition->dn, - modified_partition->mod_usn, - modified_partition->mod_usn_urgent); + ret = dsdb_module_save_partition_usn(module, modified_partition->dn, + modified_partition->mod_usn, + modified_partition->mod_usn_urgent); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n", ldb_dn_get_linearized(modified_partition->dn))); @@ -668,7 +667,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme struct ldb_context *ldb = ldb_module_get_ctx(module); /* We will take a reference to the schema in replmd_add_backlink */ - struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL); + const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL); NTTIME now; unix_to_nt_time(&now, t); @@ -1537,7 +1536,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d handle adding a linked attribute */ static int replmd_modify_la_add(struct ldb_module *module, - struct dsdb_schema *schema, + const struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, @@ -1656,7 +1655,7 @@ static int replmd_modify_la_add(struct ldb_module *module, handle deleting all active linked attributes */ static int replmd_modify_la_delete(struct ldb_module *module, - struct dsdb_schema *schema, + const struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, @@ -1775,7 +1774,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, handle replacing a linked attribute */ static int replmd_modify_la_replace(struct ldb_module *module, - struct dsdb_schema *schema, + const struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, @@ -1937,7 +1936,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message *old_msg; - struct dsdb_schema *schema; + const struct dsdb_schema *schema; struct GUID old_guid; if (seq_num == 0) { @@ -2235,7 +2234,7 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are is deleted */ static int replmd_delete_remove_link(struct ldb_module *module, - struct dsdb_schema *schema, + const struct dsdb_schema *schema, struct ldb_dn *dn, struct ldb_message_element *el, const struct dsdb_attribute *sa) @@ -2322,7 +2321,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) const struct ldb_val *rdn_value, *new_rdn_value; struct GUID guid; struct ldb_context *ldb = ldb_module_get_ctx(module); - struct dsdb_schema *schema; + const struct dsdb_schema *schema; struct ldb_message *msg, *old_msg; struct ldb_message_element *el; TALLOC_CTX *tmp_ctx; @@ -3510,7 +3509,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message *msg; TALLOC_CTX *tmp_ctx = talloc_new(la_entry); - struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx); + const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx); int ret; const struct dsdb_attribute *attr; struct dsdb_dn *dsdb_dn; diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index 25f2dce..655b489 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -417,12 +417,17 @@ static int schema_data_search(struct ldb_module *module, struct ldb_request *req int ret; struct schema_data_search_data *search_context; struct ldb_request *down_req; - struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL); + const struct dsdb_schema *schema; + if (!ldb_module_get_private(module)) { + /* If there is no module data, there is little we can do */ + return ldb_next_request(module, req); + } - if (!schema || !ldb_module_get_private(module)) { - /* If there is no schema, there is little we can do */ + /* The schema manipulation does not apply to special DNs */ + if (ldb_dn_is_special(req->op.search.base)) { return ldb_next_request(module, req); } + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) { break; @@ -434,6 +439,12 @@ static int schema_data_search(struct ldb_module *module, struct ldb_request *req return ldb_next_request(module, req); } + schema = dsdb_get_schema(ldb, NULL); + if (!schema || !ldb_module_get_private(module)) { + /* If there is no schema, there is little we can do */ + return ldb_next_request(module, req); + } + search_context = talloc(req, struct schema_data_search_data); if (!search_context) { ldb_oom(ldb); diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index 5ea70fb..d13b339 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -5,8 +5,8 @@ checkings, it also loads the dsdb_schema. Copyright (C) Stefan Metzmacher <me...@samba.org> 2007 - Copyright (C) Andrew Bartlett <abart...@samba.org> 2009 - + Copyright (C) Andrew Bartlett <abart...@samba.org> 2009-2010 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or @@ -31,19 +31,123 @@ #include "param/param.h" #include "dsdb/samdb/ldb_modules/util.h" +struct schema_load_private_data { + bool in_transaction; +}; + +static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn, + struct dsdb_schema **schema); + +struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct dsdb_schema *schema, bool is_global_schema) +{ + uint64_t current_usn; + int ret; + struct ldb_result *res; + struct ldb_request *treq; + struct ldb_seqnum_request *tseq; + struct ldb_seqnum_result *tseqr; + struct dsdb_control_current_partition *ctrl; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *new_schema; + + struct schema_load_private_data *private_data = talloc_get_type(ldb_module_get_private(module), struct schema_load_private_data); + if (!private_data) { + /* We can't refresh until the init function has run */ + return schema; + } + + /* We don't allow a schema reload during a transaction - nobody else can modify our schema behind our backs */ + if (private_data->in_transaction) { + return schema; + } + + res = talloc_zero(schema, struct ldb_result); + if (res == NULL) { + return NULL; + } + tseq = talloc_zero(res, struct ldb_seqnum_request); + if (tseq == NULL) { + talloc_free(res); + return NULL; + } + tseq->type = LDB_SEQ_HIGHEST_SEQ; + + ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res, + LDB_EXTENDED_SEQUENCE_NUMBER, + tseq, + NULL, + res, + ldb_extended_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return NULL; + } + + ctrl = talloc(treq, struct dsdb_control_current_partition); + if (!ctrl) { + talloc_free(res); + return NULL; + } + ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION; + ctrl->dn = schema->base_dn; + + ret = ldb_request_add_control(treq, + DSDB_CONTROL_CURRENT_PARTITION_OID, + false, ctrl); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return NULL; + } + + ret = ldb_next_request(module, treq); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return NULL; + } + ret = ldb_wait(treq->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return NULL; + } + tseqr = talloc_get_type(res->extended->data, + struct ldb_seqnum_result); + if (tseqr->seq_num == schema->reload_seq_number) { + talloc_free(res); + return schema; + } + + schema->reload_seq_number = tseqr->seq_num; + talloc_free(res); + + ret = dsdb_module_load_partition_usn(module, schema->base_dn, ¤t_usn, NULL); + if (ret != LDB_SUCCESS || current_usn == schema->loaded_usn) { + return schema; + } + + ret = dsdb_schema_from_db(module, schema->base_dn, current_usn, &new_schema); + if (ret != LDB_SUCCESS) { + return schema; + } + + if (is_global_schema) { + dsdb_make_schema_global(ldb, new_schema); + } + return new_schema; +} + + /* Given an LDB module (pointing at the schema DB), and the DN, set the populated schema */ -static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *module, - struct smb_iconv_convenience *iconv_convenience, - struct ldb_dn *schema_dn, - struct dsdb_schema **schema) +static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn, + struct dsdb_schema **schema) { + struct ldb_context *ldb = ldb_module_get_ctx(module); TALLOC_CTX *tmp_ctx; char *error_string; int ret; - struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_result *schema_res; struct ldb_result *a_res; struct ldb_result *c_res; @@ -55,7 +159,7 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo }; unsigned flags; - tmp_ctx = talloc_new(mem_ctx); + tmp_ctx = talloc_new(module); if (!tmp_ctx) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -71,6 +175,9 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo ret = dsdb_module_search_dn(module, tmp_ctx, &schema_res, schema_dn, schema_attrs, 0); if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_load_init: no schema head present: (skip schema loading)\n"); goto failed; } else if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, @@ -112,11 +219,31 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo schema_res, a_res, c_res, schema, &error_string); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, - "dsdb_schema load failed: %s", - error_string); + "dsdb_schema load failed: %s", + error_string); goto failed; } - talloc_steal(mem_ctx, *schema); + + (*schema)->refresh_fn = dsdb_schema_refresh; + (*schema)->loaded_from_module = module; + (*schema)->loaded_usn = current_usn; + + /* dsdb_set_schema() steal schema into the ldb_context */ + ret = dsdb_set_schema(ldb, (*schema)); + + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_set_schema() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + /* Ensure this module won't go away before the callback */ + if (talloc_reference(*schema, ldb) == NULL) { + ldb_oom(ldb); + ret = LDB_ERR_OPERATIONS_ERROR; + } failed: if (flags & LDB_FLG_ENABLE_TRACING) { @@ -130,18 +257,30 @@ failed: static int schema_load_init(struct ldb_module *module) { - struct ldb_context *ldb; - TALLOC_CTX *mem_ctx; - struct ldb_dn *schema_dn; + struct schema_load_private_data *private_data; struct dsdb_schema *schema; + struct ldb_context *ldb = ldb_module_get_ctx(module); int ret; + uint64_t current_usn; + struct ldb_dn *schema_dn; + + private_data = talloc_zero(module, struct schema_load_private_data); + if (private_data == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_module_set_private(module, private_data); ret = ldb_next_init(module); if (ret != LDB_SUCCESS) { return ret; } - ldb = ldb_module_get_ctx(module); + if (dsdb_get_schema(ldb, NULL)) { + return LDB_SUCCESS; + } + schema_dn = samdb_schema_dn(ldb); if (!schema_dn) { ldb_reset_err_string(ldb); @@ -150,54 +289,51 @@ static int schema_load_init(struct ldb_module *module) return LDB_SUCCESS; } - if (dsdb_get_schema(ldb, NULL)) { - return LDB_SUCCESS; + ret = dsdb_module_load_partition_usn(module, schema_dn, ¤t_usn, NULL); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_load_partition_usn failed: %s", -- Samba Shared Repository