mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
9b009c9009
(This used to be commit 37425495f3
)
248 lines
6.1 KiB
C
248 lines
6.1 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
ctdb clustering hooks
|
|
|
|
Copyright (C) Andrew Tridgell 2006
|
|
|
|
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 "lib/events/events.h"
|
|
#include "cluster/cluster.h"
|
|
#include "system/filesys.h"
|
|
#include "cluster/cluster_private.h"
|
|
#include "lib/tdb/include/tdb.h"
|
|
#include "include/ctdb.h"
|
|
#include "db_wrap.h"
|
|
#include "lib/util/dlinklist.h"
|
|
#include "param/param.h"
|
|
#include "librpc/gen_ndr/misc.h"
|
|
|
|
/* a linked list of messaging handlers, allowing incoming messages
|
|
to be directed to the right messaging context */
|
|
struct cluster_messaging_list {
|
|
struct cluster_messaging_list *next, *prev;
|
|
struct cluster_state *state;
|
|
struct messaging_context *msg;
|
|
struct server_id server;
|
|
cluster_message_fn_t handler;
|
|
};
|
|
|
|
struct cluster_state {
|
|
struct ctdb_context *ctdb;
|
|
struct cluster_messaging_list *list;
|
|
uint32_t vnn;
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
return a server_id for a ctdb node
|
|
*/
|
|
static struct server_id ctdb_id(struct cluster_ops *ops, uint32_t id)
|
|
{
|
|
struct cluster_state *state = (struct cluster_state *)ops->private;
|
|
struct ctdb_context *ctdb = state->ctdb;
|
|
struct server_id server_id;
|
|
server_id.node = ctdb_get_vnn(ctdb);
|
|
server_id.id = id;
|
|
return server_id;
|
|
}
|
|
|
|
|
|
/*
|
|
return a server_id as a string
|
|
*/
|
|
static const char *ctdb_id_string(struct cluster_ops *ops,
|
|
TALLOC_CTX *mem_ctx, struct server_id id)
|
|
{
|
|
return talloc_asprintf(mem_ctx, "%u.%u", id.node, id.id);
|
|
}
|
|
|
|
/*
|
|
this is an interim method for subsystems that have not yet been
|
|
converted to use the ctdb api. It opens a shared database in the
|
|
cluster temporary area, using TDB_CLEAR_IF_FIRST which relies on
|
|
correct operation of fcntl locks on the shared fileystem.
|
|
*/
|
|
static struct tdb_wrap *ctdb_tdb_tmp_open(struct cluster_ops *ops,
|
|
TALLOC_CTX *mem_ctx, const char *dbname,
|
|
int flags)
|
|
{
|
|
const char *dir = lp_parm_string(NULL, "ctdb", "shared data");
|
|
char *path;
|
|
struct tdb_wrap *w;
|
|
if (dir == NULL) {
|
|
DEBUG(0,("ERROR: You must set 'ctdb:shared data' to a cluster shared path\n"));
|
|
return NULL;
|
|
}
|
|
path = talloc_asprintf(mem_ctx, "%s/%s", dir, dbname);
|
|
w = tdb_wrap_open(mem_ctx, path, 0,
|
|
flags | TDB_CLEAR_IF_FIRST,
|
|
O_RDWR|O_CREAT, 0600);
|
|
talloc_free(path);
|
|
return w;
|
|
}
|
|
|
|
/*
|
|
get at the ctdb handle
|
|
*/
|
|
static void *ctdb_backend_handle(struct cluster_ops *ops)
|
|
{
|
|
struct cluster_state *state = (struct cluster_state *)ops->private;
|
|
return (void *)state->ctdb;
|
|
}
|
|
|
|
struct ctdb_handler_state {
|
|
struct cluster_state *state;
|
|
cluster_message_fn_t handler;
|
|
struct messaging_context *msg;
|
|
};
|
|
|
|
/*
|
|
dispatch incoming ctdb messages
|
|
*/
|
|
static void ctdb_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
|
|
TDB_DATA data, void *private)
|
|
{
|
|
struct ctdb_handler_state *s = talloc_get_type(private,
|
|
struct ctdb_handler_state);
|
|
DATA_BLOB blob;
|
|
blob.data = data.dptr;
|
|
blob.length = data.dsize;
|
|
s->handler(s->msg, blob);
|
|
}
|
|
|
|
static int ctdb_handler_destructor(struct ctdb_handler_state *s)
|
|
{
|
|
/* XXX - tell ctdb to de-register the message handler */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
setup a handler for ctdb messages
|
|
*/
|
|
static NTSTATUS ctdb_message_init(struct cluster_ops *ops,
|
|
struct messaging_context *msg,
|
|
struct server_id server,
|
|
cluster_message_fn_t handler)
|
|
{
|
|
struct cluster_state *state = (struct cluster_state *)ops->private;
|
|
struct ctdb_handler_state *h;
|
|
int ret;
|
|
|
|
h = talloc(msg, struct ctdb_handler_state);
|
|
NT_STATUS_HAVE_NO_MEMORY(h);
|
|
|
|
h->state = state;
|
|
h->handler = handler;
|
|
h->msg = msg;
|
|
|
|
talloc_set_destructor(h, ctdb_handler_destructor);
|
|
|
|
/* setup a message handler */
|
|
ret = ctdb_set_message_handler(state->ctdb, server.id,
|
|
ctdb_message_handler, h);
|
|
if (ret == -1) {
|
|
DEBUG(0,("ctdb_set_message_handler failed - %s\n",
|
|
ctdb_errstr(state->ctdb)));
|
|
exit(1);
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
send a ctdb message to another node
|
|
*/
|
|
static NTSTATUS ctdb_message_send(struct cluster_ops *ops,
|
|
struct server_id server, DATA_BLOB *data)
|
|
{
|
|
struct cluster_state *state = (struct cluster_state *)ops->private;
|
|
struct ctdb_context *ctdb = state->ctdb;
|
|
TDB_DATA tdata;
|
|
int ret;
|
|
|
|
tdata.dptr = data->data;
|
|
tdata.dsize = data->length;
|
|
|
|
ret = ctdb_send_message(ctdb, server.node, server.id, tdata);
|
|
if (ret != 0) {
|
|
return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
|
}
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
static struct cluster_ops cluster_ctdb_ops = {
|
|
.cluster_id = ctdb_id,
|
|
.cluster_id_string = ctdb_id_string,
|
|
.cluster_tdb_tmp_open = ctdb_tdb_tmp_open,
|
|
.backend_handle = ctdb_backend_handle,
|
|
.message_init = ctdb_message_init,
|
|
.message_send = ctdb_message_send,
|
|
.private = NULL
|
|
};
|
|
|
|
/* initialise ctdb */
|
|
void cluster_ctdb_init(struct event_context *ev, const char *model)
|
|
{
|
|
struct cluster_state *state;
|
|
int ret;
|
|
|
|
if (!lp_parm_bool(NULL, "ctdb", "enable", false)) {
|
|
return;
|
|
}
|
|
|
|
state = talloc(ev, struct cluster_state);
|
|
if (state == NULL) goto failed;
|
|
|
|
state->ctdb = ctdb_init(ev);
|
|
if (state->ctdb == NULL) goto failed;
|
|
|
|
ret = ctdb_socket_connect(state->ctdb);
|
|
if (ret == -1) {
|
|
DEBUG(0,(__location__ " Failed to connect to ctdb socket\n"));
|
|
goto failed;
|
|
}
|
|
|
|
/* get our vnn */
|
|
state->vnn = ctdb_ctrl_getvnn(state->ctdb, timeval_zero(), CTDB_CURRENT_NODE);
|
|
if (state->vnn == (uint32_t)-1) {
|
|
DEBUG(0,(__location__ " Failed to get ctdb vnn\n"));
|
|
goto failed;
|
|
}
|
|
|
|
state->list = NULL;
|
|
|
|
cluster_ctdb_ops.private = state;
|
|
|
|
cluster_set_ops(&cluster_ctdb_ops);
|
|
|
|
#if 0
|
|
/* nasty hack for now ... */
|
|
{
|
|
void brl_ctdb_init_ops(void);
|
|
brl_ctdb_init_ops();
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
|
|
failed:
|
|
DEBUG(0,("cluster_ctdb_init failed\n"));
|
|
talloc_free(state);
|
|
}
|