1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source4/dsdb/repl/drepl_out_pull.c
Kamen Mazdrashki 3593298c7e s4-dreplsrv: Call dreplsrv_out_operation::callback in case we fail to even run the operation
Operation was scheduled already, so we need to call
the callback function for it to be able to do its job.

For instance, if we are blocking an rpc call until an
operation is completed and there is no memory, then
client will be blocked without knowing what is going on
with the server.
2010-09-09 18:26:51 +03:00

182 lines
5.0 KiB
C

/*
Unix SMB/CIFS mplementation.
DSDB replication service outgoing Pull-Replication
Copyright (C) Stefan Metzmacher 2007
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "dsdb/samdb/samdb.h"
#include "auth/auth.h"
#include "smbd/service.h"
#include "lib/events/events.h"
#include "lib/messaging/irpc.h"
#include "dsdb/repl/drepl_service.h"
#include "lib/ldb/include/ldb_errors.h"
#include "../lib/util/dlinklist.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "libcli/composite/composite.h"
#include "libcli/security/dom_sid.h"
WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
struct dreplsrv_partition_source_dsa *source,
enum drsuapi_DsExtendedOperation extended_op,
uint64_t fsmo_info,
dreplsrv_fsmo_callback_t callback,
void *cb_data)
{
struct dreplsrv_out_operation *op;
op = talloc_zero(s, struct dreplsrv_out_operation);
W_ERROR_HAVE_NO_MEMORY(op);
op->service = s;
op->source_dsa = source;
op->extended_op = extended_op;
op->fsmo_info = fsmo_info;
op->callback = callback;
op->cb_data = cb_data;
DLIST_ADD_END(s->ops.pending, op, struct dreplsrv_out_operation *);
return WERR_OK;
}
static WERROR dreplsrv_schedule_partition_pull(struct dreplsrv_service *s,
struct dreplsrv_partition *p,
TALLOC_CTX *mem_ctx)
{
WERROR status;
struct dreplsrv_partition_source_dsa *cur;
for (cur = p->sources; cur; cur = cur->next) {
status = dreplsrv_schedule_partition_pull_source(s, cur,
DRSUAPI_EXOP_NONE, 0,
NULL, NULL);
W_ERROR_NOT_OK_RETURN(status);
}
return WERR_OK;
}
WERROR dreplsrv_schedule_pull_replication(struct dreplsrv_service *s, TALLOC_CTX *mem_ctx)
{
WERROR status;
struct dreplsrv_partition *p;
for (p = s->partitions; p; p = p->next) {
status = dreplsrv_schedule_partition_pull(s, p, mem_ctx);
W_ERROR_NOT_OK_RETURN(status);
}
return WERR_OK;
}
static void dreplsrv_pending_op_callback(struct tevent_req *subreq)
{
struct dreplsrv_out_operation *op = tevent_req_callback_data(subreq,
struct dreplsrv_out_operation);
struct repsFromTo1 *rf = op->source_dsa->repsFrom1;
struct dreplsrv_service *s = op->service;
time_t t;
NTTIME now;
t = time(NULL);
unix_to_nt_time(&now, t);
rf->result_last_attempt = dreplsrv_op_pull_source_recv(subreq);
TALLOC_FREE(subreq);
if (W_ERROR_IS_OK(rf->result_last_attempt)) {
rf->consecutive_sync_failures = 0;
rf->last_success = now;
DEBUG(3,("dreplsrv_op_pull_source(%s)\n",
win_errstr(rf->result_last_attempt)));
goto done;
}
rf->consecutive_sync_failures++;
DEBUG(1,("dreplsrv_op_pull_source(%s/%s) for %s failures[%u]\n",
win_errstr(rf->result_last_attempt),
nt_errstr(werror_to_ntstatus(rf->result_last_attempt)),
ldb_dn_get_linearized(op->source_dsa->partition->dn),
rf->consecutive_sync_failures));
done:
if (op->callback) {
op->callback(s, rf->result_last_attempt, op->extended_ret, op->cb_data);
}
talloc_free(op);
s->ops.current = NULL;
dreplsrv_run_pending_ops(s);
dreplsrv_notify_run_ops(s);
}
void dreplsrv_run_pending_ops(struct dreplsrv_service *s)
{
struct dreplsrv_out_operation *op;
time_t t;
NTTIME now;
struct tevent_req *subreq;
if (s->ops.current || s->ops.n_current) {
/* if there's still one running, we're done */
return;
}
if (!s->ops.pending) {
/* if there're no pending operations, we're done */
return;
}
t = time(NULL);
unix_to_nt_time(&now, t);
op = s->ops.pending;
s->ops.current = op;
DLIST_REMOVE(s->ops.pending, op);
op->source_dsa->repsFrom1->last_attempt = now;
subreq = dreplsrv_op_pull_source_send(op, s->task->event_ctx, op);
if (!subreq) {
struct repsFromTo1 *rf = op->source_dsa->repsFrom1;
rf->result_last_attempt = WERR_NOMEM;
rf->consecutive_sync_failures++;
s->ops.current = NULL;
/*
* call the callback (if any) so it gets the chance
* to do its job just like in any other failure situation
*/
if (op->callback) {
op->callback(s, rf->result_last_attempt, op->extended_ret, op->cb_data);
}
DEBUG(1,("dreplsrv_op_pull_source(%s/%s) failures[%u]\n",
win_errstr(rf->result_last_attempt),
nt_errstr(werror_to_ntstatus(rf->result_last_attempt)),
rf->consecutive_sync_failures));
return;
}
tevent_req_set_callback(subreq, dreplsrv_pending_op_callback, op);
}