mirror of
https://github.com/samba-team/samba.git
synced 2025-12-13 16:23:50 +03:00
Merge CTDB-related fixes from samba-ctdb 3.0 branch (http://samba.org/~tridge/3_0-ctdb)
Signed-off-by: Alexander Bokovoy <ab@samba.org>
This commit is contained in:
@@ -17,6 +17,9 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _CTDBD_CONN_H
|
||||||
|
#define _CTDBD_CONN_H
|
||||||
|
|
||||||
struct ctdbd_connection;
|
struct ctdbd_connection;
|
||||||
|
|
||||||
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
|
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
|
||||||
@@ -62,3 +65,6 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
|
|||||||
|
|
||||||
NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn);
|
NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn);
|
||||||
|
|
||||||
|
NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
|
||||||
|
|
||||||
|
#endif /* _CTDBD_CONN_H */
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ struct db_context {
|
|||||||
void *private_data);
|
void *private_data);
|
||||||
int (*get_seqnum)(struct db_context *db);
|
int (*get_seqnum)(struct db_context *db);
|
||||||
void *private_data;
|
void *private_data;
|
||||||
|
bool persistent;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct db_context *db_open(TALLOC_CTX *mem_ctx,
|
struct db_context *db_open(TALLOC_CTX *mem_ctx,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ static struct db_context *connections_db_ctx(bool rw)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
|
db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
|
||||||
TDB_DEFAULT, O_RDONLY, 0);
|
TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDONLY, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return db_ctx;
|
return db_ctx;
|
||||||
|
|||||||
@@ -1203,6 +1203,42 @@ NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn)
|
|||||||
return register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE);
|
return register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
persstent store. Used when we update a record in a persistent database
|
||||||
|
*/
|
||||||
|
NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data)
|
||||||
|
{
|
||||||
|
int cstatus=0;
|
||||||
|
struct ctdb_rec_data *rec;
|
||||||
|
TDB_DATA recdata;
|
||||||
|
size_t length;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
length = offsetof(struct ctdb_rec_data, data) + key.dsize + data.dsize;
|
||||||
|
|
||||||
|
rec = (struct ctdb_rec_data *)talloc_size(conn, length);
|
||||||
|
NT_STATUS_HAVE_NO_MEMORY(rec);
|
||||||
|
|
||||||
|
rec->length = length;
|
||||||
|
rec->reqid = db_id;
|
||||||
|
rec->keylen = key.dsize;
|
||||||
|
rec->datalen= data.dsize;
|
||||||
|
memcpy(&rec->data[0], key.dptr, key.dsize);
|
||||||
|
memcpy(&rec->data[key.dsize], data.dptr, data.dsize);
|
||||||
|
|
||||||
|
recdata.dptr = (uint8_t *)rec;
|
||||||
|
recdata.dsize = length;
|
||||||
|
|
||||||
|
status = ctdbd_control(conn, CTDB_CURRENT_NODE,
|
||||||
|
CTDB_CONTROL_PERSISTENT_STORE,
|
||||||
|
0, recdata, NULL, NULL, &cstatus);
|
||||||
|
if (cstatus != 0) {
|
||||||
|
return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
|
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
#ifdef CLUSTER_SUPPORT
|
||||||
|
#include "ctdb_private.h"
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Fall back using fetch_locked if no genuine fetch operation is provided
|
* Fall back using fetch_locked if no genuine fetch operation is provided
|
||||||
*/
|
*/
|
||||||
@@ -46,10 +48,16 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
|
|||||||
int open_flags, mode_t mode)
|
int open_flags, mode_t mode)
|
||||||
{
|
{
|
||||||
struct db_context *result = NULL;
|
struct db_context *result = NULL;
|
||||||
|
#ifdef CLUSTER_SUPPORT
|
||||||
|
const char *sockname = lp_ctdbd_socket();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CLUSTER_SUPPORT
|
#ifdef CLUSTER_SUPPORT
|
||||||
|
if(!sockname || !*sockname) {
|
||||||
|
sockname = CTDB_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
if (lp_clustering()) {
|
if (lp_clustering() && socket_exist(sockname)) {
|
||||||
const char *partname;
|
const char *partname;
|
||||||
/* ctdb only wants the file part of the name */
|
/* ctdb only wants the file part of the name */
|
||||||
partname = strrchr(name, '/');
|
partname = strrchr(name, '/');
|
||||||
|
|||||||
@@ -18,16 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
#ifdef CLUSTER_SUPPORT
|
#ifdef CLUSTER_SUPPORT
|
||||||
|
|
||||||
#include "ctdb.h"
|
#include "ctdb.h"
|
||||||
#include "ctdb_private.h"
|
#include "ctdb_private.h"
|
||||||
|
#include "ctdbd_conn.h"
|
||||||
|
|
||||||
struct db_ctdb_ctx {
|
struct db_ctdb_ctx {
|
||||||
struct tdb_wrap *wtdb;
|
struct tdb_wrap *wtdb;
|
||||||
uint32 db_id;
|
uint32 db_id;
|
||||||
struct ctdbd_connection *conn;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct db_ctdb_rec {
|
struct db_ctdb_rec {
|
||||||
@@ -35,8 +33,6 @@ struct db_ctdb_rec {
|
|||||||
struct ctdb_ltdb_header header;
|
struct ctdb_ltdb_header header;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ctdbd_connection *db_ctdbd_conn(struct db_ctdb_ctx *ctx);
|
|
||||||
|
|
||||||
static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
|
static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
|
||||||
{
|
{
|
||||||
struct db_ctdb_rec *crec = talloc_get_type_abort(
|
struct db_ctdb_rec *crec = talloc_get_type_abort(
|
||||||
@@ -60,6 +56,42 @@ static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
|
|||||||
return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
|
return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* for persistent databases the store is a bit different. We have to
|
||||||
|
ask the ctdb daemon to push the record to all nodes after the
|
||||||
|
store */
|
||||||
|
static NTSTATUS db_ctdb_store_persistent(struct db_record *rec, TDB_DATA data, int flag)
|
||||||
|
{
|
||||||
|
struct db_ctdb_rec *crec = talloc_get_type_abort(
|
||||||
|
rec->private_data, struct db_ctdb_rec);
|
||||||
|
TDB_DATA cdata;
|
||||||
|
int ret;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
cdata.dsize = sizeof(crec->header) + data.dsize;
|
||||||
|
|
||||||
|
if (!(cdata.dptr = SMB_MALLOC_ARRAY(uint8, cdata.dsize))) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
crec->header.rsn++;
|
||||||
|
|
||||||
|
memcpy(cdata.dptr, &crec->header, sizeof(crec->header));
|
||||||
|
memcpy(cdata.dptr + sizeof(crec->header), data.dptr, data.dsize);
|
||||||
|
|
||||||
|
ret = tdb_store(crec->ctdb_ctx->wtdb->tdb, rec->key, cdata, TDB_REPLACE);
|
||||||
|
status = (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||||
|
|
||||||
|
/* now tell ctdbd to update this record on all other nodes */
|
||||||
|
if (NT_STATUS_IS_OK(status)) {
|
||||||
|
status = ctdbd_persistent_store(messaging_ctdbd_connection(), crec->ctdb_ctx->db_id, rec->key, cdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE(cdata.dptr);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS db_ctdb_delete(struct db_record *rec)
|
static NTSTATUS db_ctdb_delete(struct db_record *rec)
|
||||||
{
|
{
|
||||||
struct db_ctdb_rec *crec = talloc_get_type_abort(
|
struct db_ctdb_rec *crec = talloc_get_type_abort(
|
||||||
@@ -110,6 +142,7 @@ static struct db_record *db_ctdb_fetch_locked(struct db_context *db,
|
|||||||
struct db_ctdb_rec *crec;
|
struct db_ctdb_rec *crec;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
TDB_DATA ctdb_data;
|
TDB_DATA ctdb_data;
|
||||||
|
int migrate_attempts = 0;
|
||||||
|
|
||||||
if (!(result = talloc(mem_ctx, struct db_record))) {
|
if (!(result = talloc(mem_ctx, struct db_record))) {
|
||||||
DEBUG(0, ("talloc failed\n"));
|
DEBUG(0, ("talloc failed\n"));
|
||||||
@@ -153,7 +186,11 @@ again:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->store = db_ctdb_store;
|
if (db->persistent) {
|
||||||
|
result->store = db_ctdb_store_persistent;
|
||||||
|
} else {
|
||||||
|
result->store = db_ctdb_store;
|
||||||
|
}
|
||||||
result->delete_rec = db_ctdb_delete;
|
result->delete_rec = db_ctdb_delete;
|
||||||
talloc_set_destructor(result, db_ctdb_record_destr);
|
talloc_set_destructor(result, db_ctdb_record_destr);
|
||||||
|
|
||||||
@@ -175,12 +212,14 @@ again:
|
|||||||
tdb_chainunlock(ctx->wtdb->tdb, key);
|
tdb_chainunlock(ctx->wtdb->tdb, key);
|
||||||
talloc_set_destructor(result, NULL);
|
talloc_set_destructor(result, NULL);
|
||||||
|
|
||||||
|
migrate_attempts += 1;
|
||||||
|
|
||||||
DEBUG(10, ("ctdb_data.dptr = %p, dmaster = %u (%u)\n",
|
DEBUG(10, ("ctdb_data.dptr = %p, dmaster = %u (%u)\n",
|
||||||
ctdb_data.dptr, ctdb_data.dptr ?
|
ctdb_data.dptr, ctdb_data.dptr ?
|
||||||
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster : -1,
|
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster : -1,
|
||||||
get_my_vnn()));
|
get_my_vnn()));
|
||||||
|
|
||||||
status = ctdbd_migrate(db_ctdbd_conn(ctx), ctx->db_id, key);
|
status = ctdbd_migrate(messaging_ctdbd_connection(),ctx->db_id, key);
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
DEBUG(5, ("ctdb_migrate failed: %s\n",
|
DEBUG(5, ("ctdb_migrate failed: %s\n",
|
||||||
nt_errstr(status)));
|
nt_errstr(status)));
|
||||||
@@ -191,6 +230,11 @@ again:
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (migrate_attempts > 10) {
|
||||||
|
DEBUG(0, ("db_ctdb_fetch_locked needed %d attempts\n",
|
||||||
|
migrate_attempts));
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&crec->header, ctdb_data.dptr, sizeof(crec->header));
|
memcpy(&crec->header, ctdb_data.dptr, sizeof(crec->header));
|
||||||
|
|
||||||
result->value.dsize = ctdb_data.dsize - sizeof(crec->header);
|
result->value.dsize = ctdb_data.dsize - sizeof(crec->header);
|
||||||
@@ -226,10 +270,12 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
|
|||||||
/*
|
/*
|
||||||
* See if we have a valid record and we are the dmaster. If so, we can
|
* See if we have a valid record and we are the dmaster. If so, we can
|
||||||
* take the shortcut and just return it.
|
* take the shortcut and just return it.
|
||||||
|
* we bypass the dmaster check for persistent databases
|
||||||
*/
|
*/
|
||||||
if ((ctdb_data.dptr != NULL) &&
|
if ((ctdb_data.dptr != NULL) &&
|
||||||
(ctdb_data.dsize >= sizeof(struct ctdb_ltdb_header)) &&
|
(ctdb_data.dsize >= sizeof(struct ctdb_ltdb_header)) &&
|
||||||
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn()) {
|
(db->persistent ||
|
||||||
|
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn())) {
|
||||||
/* we are the dmaster - avoid the ctdb protocol op */
|
/* we are the dmaster - avoid the ctdb protocol op */
|
||||||
|
|
||||||
data->dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header);
|
data->dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header);
|
||||||
@@ -254,8 +300,7 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
|
|||||||
SAFE_FREE(ctdb_data.dptr);
|
SAFE_FREE(ctdb_data.dptr);
|
||||||
|
|
||||||
/* we weren't able to get it locally - ask ctdb to fetch it for us */
|
/* we weren't able to get it locally - ask ctdb to fetch it for us */
|
||||||
status = ctdbd_fetch(db_ctdbd_conn(ctx), ctx->db_id, key, mem_ctx,
|
status = ctdbd_fetch(messaging_ctdbd_connection(),ctx->db_id, key, mem_ctx, data);
|
||||||
data);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
DEBUG(5, ("ctdbd_fetch failed: %s\n", nt_errstr(status)));
|
DEBUG(5, ("ctdbd_fetch failed: %s\n", nt_errstr(status)));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -283,6 +328,22 @@ static void traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data)
|
|||||||
talloc_free(tmp_ctx);
|
talloc_free(tmp_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int traverse_persistent_callback(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct traverse_state *state = (struct traverse_state *)private_data;
|
||||||
|
struct db_record *rec;
|
||||||
|
TALLOC_CTX *tmp_ctx = talloc_new(state->db);
|
||||||
|
int ret = 0;
|
||||||
|
/* we have to give them a locked record to prevent races */
|
||||||
|
rec = db_ctdb_fetch_locked(state->db, tmp_ctx, kbuf);
|
||||||
|
if (rec && rec->value.dsize > 0) {
|
||||||
|
ret = state->fn(rec, state->private_data);
|
||||||
|
}
|
||||||
|
talloc_free(tmp_ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int db_ctdb_traverse(struct db_context *db,
|
static int db_ctdb_traverse(struct db_context *db,
|
||||||
int (*fn)(struct db_record *rec,
|
int (*fn)(struct db_record *rec,
|
||||||
void *private_data),
|
void *private_data),
|
||||||
@@ -296,6 +357,13 @@ static int db_ctdb_traverse(struct db_context *db,
|
|||||||
state.fn = fn;
|
state.fn = fn;
|
||||||
state.private_data = private_data;
|
state.private_data = private_data;
|
||||||
|
|
||||||
|
if (db->persistent) {
|
||||||
|
/* for persistent databases we don't need to do a ctdb traverse,
|
||||||
|
we can do a faster local traverse */
|
||||||
|
return tdb_traverse(ctx->wtdb->tdb, traverse_persistent_callback, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ctdbd_traverse(ctx->db_id, traverse_callback, &state);
|
ctdbd_traverse(ctx->db_id, traverse_callback, &state);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -322,6 +390,27 @@ static void traverse_read_callback(TDB_DATA key, TDB_DATA data, void *private_da
|
|||||||
state->fn(&rec, state->private_data);
|
state->fn(&rec, state->private_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int traverse_persistent_callback_read(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct traverse_state *state = (struct traverse_state *)private_data;
|
||||||
|
struct db_record rec;
|
||||||
|
rec.key = kbuf;
|
||||||
|
rec.value = dbuf;
|
||||||
|
rec.store = db_ctdb_store_deny;
|
||||||
|
rec.delete_rec = db_ctdb_delete_deny;
|
||||||
|
rec.private_data = state->db;
|
||||||
|
|
||||||
|
if (rec.value.dsize <= sizeof(struct ctdb_ltdb_header)) {
|
||||||
|
/* a deleted record */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rec.value.dsize -= sizeof(struct ctdb_ltdb_header);
|
||||||
|
rec.value.dptr += sizeof(struct ctdb_ltdb_header);
|
||||||
|
|
||||||
|
return state->fn(&rec, state->private_data);
|
||||||
|
}
|
||||||
|
|
||||||
static int db_ctdb_traverse_read(struct db_context *db,
|
static int db_ctdb_traverse_read(struct db_context *db,
|
||||||
int (*fn)(struct db_record *rec,
|
int (*fn)(struct db_record *rec,
|
||||||
void *private_data),
|
void *private_data),
|
||||||
@@ -335,6 +424,12 @@ static int db_ctdb_traverse_read(struct db_context *db,
|
|||||||
state.fn = fn;
|
state.fn = fn;
|
||||||
state.private_data = private_data;
|
state.private_data = private_data;
|
||||||
|
|
||||||
|
if (db->persistent) {
|
||||||
|
/* for persistent databases we don't need to do a ctdb traverse,
|
||||||
|
we can do a faster local traverse */
|
||||||
|
return tdb_traverse_read(ctx->wtdb->tdb, traverse_persistent_callback_read, &state);
|
||||||
|
}
|
||||||
|
|
||||||
ctdbd_traverse(ctx->db_id, traverse_read_callback, &state);
|
ctdbd_traverse(ctx->db_id, traverse_read_callback, &state);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -346,41 +441,6 @@ static int db_ctdb_get_seqnum(struct db_context *db)
|
|||||||
return tdb_get_seqnum(ctx->wtdb->tdb);
|
return tdb_get_seqnum(ctx->wtdb->tdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the ctdbd connection for a database. If possible, re-use the messaging
|
|
||||||
* ctdbd connection
|
|
||||||
*/
|
|
||||||
static struct ctdbd_connection *db_ctdbd_conn(struct db_ctdb_ctx *ctx)
|
|
||||||
{
|
|
||||||
struct ctdbd_connection *result;
|
|
||||||
|
|
||||||
result = messaging_ctdbd_connection();
|
|
||||||
|
|
||||||
if (result != NULL) {
|
|
||||||
|
|
||||||
if (ctx->conn == NULL) {
|
|
||||||
/*
|
|
||||||
* Someone has initialized messaging since we
|
|
||||||
* initialized our own connection, we don't need it
|
|
||||||
* anymore.
|
|
||||||
*/
|
|
||||||
TALLOC_FREE(ctx->conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->conn == NULL) {
|
|
||||||
NTSTATUS status;
|
|
||||||
status = ctdbd_init_connection(ctx, &ctx->conn);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
set_my_vnn(ctdbd_vnn(ctx->conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx->conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -390,7 +450,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
|||||||
struct db_context *result;
|
struct db_context *result;
|
||||||
struct db_ctdb_ctx *db_ctdb;
|
struct db_ctdb_ctx *db_ctdb;
|
||||||
char *db_path;
|
char *db_path;
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
if (!lp_clustering()) {
|
if (!lp_clustering()) {
|
||||||
DEBUG(10, ("Clustering disabled -- no ctdb\n"));
|
DEBUG(10, ("Clustering disabled -- no ctdb\n"));
|
||||||
@@ -409,20 +468,15 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
db_ctdb->conn = NULL;
|
if (!NT_STATUS_IS_OK(ctdbd_db_attach(messaging_ctdbd_connection(),name, &db_ctdb->db_id, tdb_flags))) {
|
||||||
|
DEBUG(0, ("ctdbd_db_attach failed for %s\n", name));
|
||||||
status = ctdbd_db_attach(db_ctdbd_conn(db_ctdb), name,
|
|
||||||
&db_ctdb->db_id, tdb_flags);
|
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
|
|
||||||
nt_errstr(status)));
|
|
||||||
TALLOC_FREE(result);
|
TALLOC_FREE(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
db_path = ctdbd_dbpath(db_ctdbd_conn(db_ctdb), db_ctdb,
|
db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb, db_ctdb->db_id);
|
||||||
db_ctdb->db_id);
|
|
||||||
|
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
|
||||||
|
|
||||||
/* only pass through specific flags */
|
/* only pass through specific flags */
|
||||||
tdb_flags &= TDB_SEQNUM;
|
tdb_flags &= TDB_SEQNUM;
|
||||||
@@ -447,16 +501,4 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
|
|
||||||
const char *name,
|
|
||||||
int hash_size, int tdb_flags,
|
|
||||||
int open_flags, mode_t mode)
|
|
||||||
{
|
|
||||||
DEBUG(0, ("no clustering compiled in\n"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Be aware that this is just sample code that has not seen too much testing
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
struct db_file_ctx {
|
struct db_file_ctx {
|
||||||
@@ -367,6 +363,7 @@ struct db_context *db_open_file(TALLOC_CTX *mem_ctx,
|
|||||||
result->fetch_locked = db_file_fetch_locked;
|
result->fetch_locked = db_file_fetch_locked;
|
||||||
result->traverse = db_file_traverse;
|
result->traverse = db_file_traverse;
|
||||||
result->traverse_read = db_file_traverse;
|
result->traverse_read = db_file_traverse;
|
||||||
|
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
|
||||||
|
|
||||||
ctx->locked_record = NULL;
|
ctx->locked_record = NULL;
|
||||||
if (!(ctx->dirname = talloc_strdup(ctx, name))) {
|
if (!(ctx->dirname = talloc_strdup(ctx, name))) {
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ static int db_tdb_record_destr(struct db_record* data)
|
|||||||
struct db_tdb_ctx *ctx =
|
struct db_tdb_ctx *ctx =
|
||||||
talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
|
talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
|
||||||
|
|
||||||
|
/* This hex_encode() call allocates memory on data context. By way how current
|
||||||
|
__talloc_free() code works, it is OK to allocate in the destructor as
|
||||||
|
the children of data will be freed after call to the destructor and this
|
||||||
|
new 'child' will be caught and freed correctly.
|
||||||
|
*/
|
||||||
DEBUG(10, (DEBUGLEVEL > 10
|
DEBUG(10, (DEBUGLEVEL > 10
|
||||||
? "Unlocking key %s\n" : "Unlocking key %.20s\n",
|
? "Unlocking key %s\n" : "Unlocking key %.20s\n",
|
||||||
hex_encode(data, (unsigned char *)data->key.dptr,
|
hex_encode(data, (unsigned char *)data->key.dptr,
|
||||||
@@ -88,8 +93,9 @@ static struct db_record *db_tdb_fetch_locked(struct db_context *db,
|
|||||||
struct tdb_fetch_locked_state state;
|
struct tdb_fetch_locked_state state;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (DEBUGLEVEL >= 10) {
|
/* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
|
||||||
char *keystr = hex_encode(NULL, key.dptr, key.dsize);
|
if(DEBUGLEVEL >= 10) {
|
||||||
|
char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
|
||||||
DEBUG(10, (DEBUGLEVEL > 10
|
DEBUG(10, (DEBUGLEVEL > 10
|
||||||
? "Locking key %s\n" : "Locking key %.20s\n",
|
? "Locking key %s\n" : "Locking key %.20s\n",
|
||||||
keystr));
|
keystr));
|
||||||
@@ -191,15 +197,9 @@ static NTSTATUS db_tdb_delete(struct db_record *rec)
|
|||||||
{
|
{
|
||||||
struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
|
struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
|
||||||
struct db_tdb_ctx);
|
struct db_tdb_ctx);
|
||||||
int res;
|
|
||||||
|
|
||||||
res = tdb_delete(ctx->wtdb->tdb, rec->key);
|
|
||||||
|
|
||||||
if (res == 0) {
|
return (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) ?
|
||||||
return NT_STATUS_OK;
|
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
|
||||||
}
|
|
||||||
|
|
||||||
return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct db_tdb_traverse_ctx {
|
struct db_tdb_traverse_ctx {
|
||||||
@@ -318,6 +318,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
|
|||||||
result->traverse = db_tdb_traverse;
|
result->traverse = db_tdb_traverse;
|
||||||
result->traverse_read = db_tdb_traverse_read;
|
result->traverse_read = db_tdb_traverse_read;
|
||||||
result->get_seqnum = db_tdb_get_seqnum;
|
result->get_seqnum = db_tdb_get_seqnum;
|
||||||
|
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
90
source/lib/dbwrap_util.c
Normal file
90
source/lib/dbwrap_util.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
Unix SMB/CIFS implementation.
|
||||||
|
Utility functions for the dbwrap API
|
||||||
|
Copyright (C) Volker Lendecke 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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
|
||||||
|
{
|
||||||
|
TDB_DATA dbuf;
|
||||||
|
int32 ret;
|
||||||
|
|
||||||
|
if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
|
||||||
|
TALLOC_FREE(dbuf.dptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = IVAL(dbuf.dptr, 0);
|
||||||
|
TALLOC_FREE(dbuf.dptr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
|
||||||
|
{
|
||||||
|
struct db_record *rec;
|
||||||
|
int32 v_store;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
|
||||||
|
if (rec == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIVAL(&v_store, 0, v);
|
||||||
|
|
||||||
|
status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
|
||||||
|
sizeof(v_store)),
|
||||||
|
TDB_REPLACE);
|
||||||
|
TALLOC_FREE(rec);
|
||||||
|
return NT_STATUS_IS_OK(status) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
|
||||||
|
uint32_t *oldval, uint32_t change_val)
|
||||||
|
{
|
||||||
|
struct db_record *rec;
|
||||||
|
uint32 val = -1;
|
||||||
|
TDB_DATA data;
|
||||||
|
|
||||||
|
if (!(rec = db->fetch_locked(db, NULL,
|
||||||
|
string_term_tdb_data(keystr)))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rec->value.dptr != NULL)
|
||||||
|
&& (rec->value.dsize == sizeof(val))) {
|
||||||
|
val = IVAL(rec->value.dptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
val += change_val;
|
||||||
|
|
||||||
|
data.dsize = sizeof(val);
|
||||||
|
data.dptr = (uint8 *)&val;
|
||||||
|
|
||||||
|
rec->store(rec, data, TDB_REPLACE);
|
||||||
|
|
||||||
|
TALLOC_FREE(rec);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -22,6 +22,10 @@
|
|||||||
#ifdef CLUSTER_SUPPORT
|
#ifdef CLUSTER_SUPPORT
|
||||||
|
|
||||||
#include "librpc/gen_ndr/messaging.h"
|
#include "librpc/gen_ndr/messaging.h"
|
||||||
|
#include "ctdb.h"
|
||||||
|
#include "ctdb_private.h"
|
||||||
|
#include "ctdbd_conn.h"
|
||||||
|
|
||||||
|
|
||||||
struct messaging_ctdbd_context {
|
struct messaging_ctdbd_context {
|
||||||
struct ctdbd_connection *conn;
|
struct ctdbd_connection *conn;
|
||||||
|
|||||||
@@ -505,6 +505,19 @@ bool file_exist(const char *fname,SMB_STRUCT_STAT *sbuf)
|
|||||||
return((S_ISREG(sbuf->st_mode)) || (S_ISFIFO(sbuf->st_mode)));
|
return((S_ISREG(sbuf->st_mode)) || (S_ISFIFO(sbuf->st_mode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
Check if a unix domain socket exists - call vfs_file_exist for samba files.
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
bool socket_exist(const char *fname)
|
||||||
|
{
|
||||||
|
SMB_STRUCT_STAT st;
|
||||||
|
if (sys_stat(fname,&st) != 0)
|
||||||
|
return(False);
|
||||||
|
|
||||||
|
return S_ISSOCK(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Check a files mod time.
|
Check a files mod time.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ static struct db_context *brlock_db;
|
|||||||
|
|
||||||
static void print_lock_struct(unsigned int i, struct lock_struct *pls)
|
static void print_lock_struct(unsigned int i, struct lock_struct *pls)
|
||||||
{
|
{
|
||||||
DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %s, ",
|
DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %u, ",
|
||||||
i,
|
i,
|
||||||
(unsigned int)pls->context.smbpid,
|
(unsigned int)pls->context.smbpid,
|
||||||
(unsigned int)pls->context.tid,
|
(unsigned int)pls->context.tid,
|
||||||
procid_str_static(&pls->context.pid) ));
|
(unsigned int)procid_to_pid(&pls->context.pid) ));
|
||||||
|
|
||||||
DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n",
|
DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n",
|
||||||
(double)pls->start,
|
(double)pls->start,
|
||||||
@@ -263,10 +263,9 @@ void brl_init(bool read_only)
|
|||||||
if (brlock_db) {
|
if (brlock_db) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
brlock_db = db_open(NULL, lock_path("brlock.tdb"), 0,
|
brlock_db = db_open(NULL, lock_path("brlock.tdb"),
|
||||||
TDB_DEFAULT
|
lp_open_files_db_hash_size(),
|
||||||
|TDB_VOLATILE
|
TDB_DEFAULT | TDB_CLEAR_IF_FIRST,
|
||||||
|(read_only?0x0:TDB_CLEAR_IF_FIRST),
|
|
||||||
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
|
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
|
||||||
if (!brlock_db) {
|
if (!brlock_db) {
|
||||||
DEBUG(0,("Failed to open byte range locking database %s\n",
|
DEBUG(0,("Failed to open byte range locking database %s\n",
|
||||||
@@ -1495,14 +1494,16 @@ static int traverse_fn(struct db_record *rec, void *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i=0; i<num_locks; i++) {
|
if (cb->fn) {
|
||||||
cb->fn(*key,
|
for ( i=0; i<num_locks; i++) {
|
||||||
locks[i].context.pid,
|
cb->fn(*key,
|
||||||
locks[i].lock_type,
|
locks[i].context.pid,
|
||||||
locks[i].lock_flav,
|
locks[i].lock_type,
|
||||||
locks[i].start,
|
locks[i].lock_flav,
|
||||||
locks[i].size,
|
locks[i].start,
|
||||||
cb->private_data);
|
locks[i].size,
|
||||||
|
cb->private_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_FREE(locks);
|
SAFE_FREE(locks);
|
||||||
|
|||||||
@@ -117,6 +117,15 @@ int count_current_connections( const char *sharename, bool clear )
|
|||||||
return cs.curr_connections;
|
return cs.curr_connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Count the number of connections open across all shares.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int count_all_current_connections(void)
|
||||||
|
{
|
||||||
|
return count_current_connections(NULL, True /* clear stale entries */);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Claim an entry in the connections database.
|
Claim an entry in the connections database.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -93,17 +93,27 @@ static void set_capability(unsigned capability)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.effective |= (1<<capability);
|
if (0 == (data.effective & (1<<capability))) {
|
||||||
|
data.effective |= (1<<capability);
|
||||||
|
|
||||||
if (capset(&header, &data) == -1) {
|
if (capset(&header, &data) == -1) {
|
||||||
DEBUG(3,("Unable to set %d capability (%s)\n",
|
DEBUG(3,("Unable to set %d capability (%s)\n",
|
||||||
capability, strerror(errno)));
|
capability, strerror(errno)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Call to set the kernel lease signal handler
|
* public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c)
|
||||||
*/
|
*/
|
||||||
|
void linux_set_lease_capability(void)
|
||||||
|
{
|
||||||
|
set_capability(CAP_LEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call to set the kernel lease signal handler
|
||||||
|
*/
|
||||||
int linux_set_lease_sighandler(int fd)
|
int linux_set_lease_sighandler(int fd)
|
||||||
{
|
{
|
||||||
if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
|
if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
|
||||||
|
|||||||
@@ -268,10 +268,20 @@ static void add_child_pid(pid_t pid)
|
|||||||
num_children += 1;
|
num_children += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_child_pid(pid_t pid)
|
static void remove_child_pid(pid_t pid, bool unclean_shutdown)
|
||||||
{
|
{
|
||||||
struct child_pid *child;
|
struct child_pid *child;
|
||||||
|
|
||||||
|
if (unclean_shutdown) {
|
||||||
|
/* a child terminated uncleanly so tickle all processes to see
|
||||||
|
if they can grab any of the pending locks
|
||||||
|
*/
|
||||||
|
messaging_send_buf(smbd_messaging_context(), procid_self(),
|
||||||
|
MSG_SMB_BRL_VALIDATE, NULL, 0);
|
||||||
|
message_send_all(smbd_messaging_context(),
|
||||||
|
MSG_SMB_UNLOCK, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (lp_max_smbd_processes() == 0) {
|
if (lp_max_smbd_processes() == 0) {
|
||||||
/* Don't bother with the child list if we don't care anyway */
|
/* Don't bother with the child list if we don't care anyway */
|
||||||
return;
|
return;
|
||||||
@@ -560,10 +570,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
|
|||||||
|
|
||||||
if (got_sig_cld) {
|
if (got_sig_cld) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
got_sig_cld = False;
|
got_sig_cld = False;
|
||||||
|
|
||||||
while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
|
while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
|
||||||
remove_child_pid(pid);
|
bool unclean_shutdown = False;
|
||||||
|
|
||||||
|
/* If the child terminated normally, assume
|
||||||
|
it was an unclean shutdown unless the
|
||||||
|
status is 0
|
||||||
|
*/
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
unclean_shutdown = WEXITSTATUS(status);
|
||||||
|
}
|
||||||
|
/* If the child terminated due to a signal
|
||||||
|
we always assume it was unclean.
|
||||||
|
*/
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
unclean_shutdown = True;
|
||||||
|
}
|
||||||
|
remove_child_pid(pid, unclean_shutdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,6 +630,15 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If the idle timeout fired and we don't have any connected
|
||||||
|
* users, exit gracefully. We should be running under a process
|
||||||
|
* controller that will restart us if necessry.
|
||||||
|
*/
|
||||||
|
if (num == 0 && count_all_current_connections() == 0) {
|
||||||
|
exit_server_cleanly("idle timeout");
|
||||||
|
}
|
||||||
|
|
||||||
/* process pending nDNS responses */
|
/* process pending nDNS responses */
|
||||||
if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
|
if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
|
||||||
@@ -906,6 +942,29 @@ void exit_server_fault(void)
|
|||||||
exit_server("critical server fault");
|
exit_server("critical server fault");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
received when we should release a specific IP
|
||||||
|
****************************************************************************/
|
||||||
|
static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data,
|
||||||
|
uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
|
||||||
|
{
|
||||||
|
const char *ip = (const char *)data->data;
|
||||||
|
char addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
|
||||||
|
/* we can't afford to do a clean exit - that involves
|
||||||
|
database writes, which would potentially mean we
|
||||||
|
are still running after the failover has finished -
|
||||||
|
we have to get rid of this process ID straight
|
||||||
|
away */
|
||||||
|
DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
|
||||||
|
ip));
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Initialise connect, service and file structs.
|
Initialise connect, service and file structs.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -1305,6 +1364,8 @@ extern void build_options(bool screen);
|
|||||||
/* register our message handlers */
|
/* register our message handlers */
|
||||||
messaging_register(smbd_messaging_context(), NULL,
|
messaging_register(smbd_messaging_context(), NULL,
|
||||||
MSG_SMB_FORCE_TDIS, msg_force_tdis);
|
MSG_SMB_FORCE_TDIS, msg_force_tdis);
|
||||||
|
messaging_register(smbd_messaging_context(), NULL,
|
||||||
|
MSG_SMB_RELEASE_IP, msg_release_ip);
|
||||||
|
|
||||||
if ((lp_keepalive() != 0)
|
if ((lp_keepalive() != 0)
|
||||||
&& !(event_add_idle(smbd_event_context(), NULL,
|
&& !(event_add_idle(smbd_event_context(), NULL,
|
||||||
|
|||||||
Reference in New Issue
Block a user