diff options
author | Stefan Metzmacher <metze@samba.org> | 2012-12-17 11:30:26 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2013-01-01 19:28:07 +0100 |
commit | 91f7f2c04fd00e281b0755a331ca632a4905e3b5 (patch) | |
tree | 0ce001177910d5f212eb2e8950b2c13c207ae60f | |
parent | 7e511b58318cef1b325a8191685ee156a7fc0cb7 (diff) | |
download | samba-91f7f2c04fd00e281b0755a331ca632a4905e3b5.tar.gz samba-91f7f2c04fd00e281b0755a331ca632a4905e3b5.tar.bz2 samba-91f7f2c04fd00e281b0755a331ca632a4905e3b5.zip |
s4:drsuapi: make sure we never return the same highwatermark twice in a replication cycle (bug #9508)
If the highwatermark given by the client is not the one we expect,
we need to start a new replication cycle. Otherwise the destination dsa
skips objects and linked attribute values.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r-- | source4/rpc_server/drsuapi/getncchanges.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 1f597c606d..e06aeed9c2 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -45,6 +45,7 @@ struct drsuapi_getncchanges_state { struct ldb_dn *ncRoot_dn; bool is_schema_nc; uint64_t min_usn; + struct drsuapi_DsReplicaHighWaterMark last_hwm; struct ldb_dn *last_dn; struct drsuapi_DsReplicaLinkedAttribute *la_list; uint32_t la_count; @@ -1620,6 +1621,20 @@ allowed: } } + if (getnc_state) { + ret = drsuapi_DsReplicaHighWaterMark_cmp(&getnc_state->last_hwm, + &req10->highwatermark); + if (ret != 0) { + DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication " + "on DN %s %s highwatermark (last_dn %s)\n", + ldb_dn_get_linearized(getnc_state->ncRoot_dn), + (ret > 0) ? "older" : "newer", + ldb_dn_get_linearized(getnc_state->last_dn))); + talloc_free(getnc_state); + getnc_state = NULL; + } + } + if (getnc_state == NULL) { getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state); if (getnc_state == NULL) { @@ -1892,6 +1907,7 @@ allowed: uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; + r->out.ctr->ctr6.new_highwatermark.reserved_usn = 0; } if (obj->meta_data_ctr == NULL) { @@ -1993,6 +2009,7 @@ allowed: r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn; + r->out.ctr->ctr6.new_highwatermark.reserved_usn = 0; werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn, r->out.ctr->ctr6.uptodateness_vector); @@ -2002,6 +2019,25 @@ allowed: talloc_free(getnc_state); b_state->getncchanges_state = NULL; + } else { + ret = drsuapi_DsReplicaHighWaterMark_cmp(&r->out.ctr->ctr6.old_highwatermark, + &r->out.ctr->ctr6.new_highwatermark); + if (ret == 0) { + /* + * We need to make sure that we never return the + * same highwatermark within the same replication + * cycle more than once. Otherwise we cannot detect + * when the client uses an unexptected highwatermark. + * + * This is a HACK which is needed because our + * object ordering is wrong and set tmp_highest_usn + * to a value that is higher than what we already + * sent to the client (destination dsa). + */ + r->out.ctr->ctr6.new_highwatermark.reserved_usn += 1; + } + + getnc_state->last_hwm = r->out.ctr->ctr6.new_highwatermark; } if (req10->extended_op != DRSUAPI_EXOP_NONE) { |