1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +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 used to be commit 0c8e23afbb)
This commit is contained in:
Alexander Bokovoy 2008-01-16 12:09:48 +03:00
parent f426949e88
commit 68694369fc
15 changed files with 387 additions and 108 deletions

View File

@ -17,6 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CTDBD_CONN_H
#define _CTDBD_CONN_H
struct ctdbd_connection;
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_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
#endif /* _CTDBD_CONN_H */

View File

@ -43,6 +43,7 @@ struct db_context {
void *private_data);
int (*get_seqnum)(struct db_context *db);
void *private_data;
bool persistent;
};
struct db_context *db_open(TALLOC_CTX *mem_ctx,

View File

@ -34,7 +34,7 @@ static struct db_context *connections_db_ctx(bool rw)
}
else {
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;

View File

@ -1203,6 +1203,42 @@ NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn)
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
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,

View File

@ -20,7 +20,9 @@
*/
#include "includes.h"
#ifdef CLUSTER_SUPPORT
#include "ctdb_private.h"
#endif
/*
* 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)
{
struct db_context *result = NULL;
#ifdef CLUSTER_SUPPORT
const char *sockname = lp_ctdbd_socket();
#endif
#ifdef CLUSTER_SUPPORT
if(!sockname || !*sockname) {
sockname = CTDB_PATH;
}
if (lp_clustering()) {
if (lp_clustering() && socket_exist(sockname)) {
const char *partname;
/* ctdb only wants the file part of the name */
partname = strrchr(name, '/');

View File

@ -18,16 +18,14 @@
*/
#include "includes.h"
#ifdef CLUSTER_SUPPORT
#include "ctdb.h"
#include "ctdb_private.h"
#include "ctdbd_conn.h"
struct db_ctdb_ctx {
struct tdb_wrap *wtdb;
uint32 db_id;
struct ctdbd_connection *conn;
};
struct db_ctdb_rec {
@ -35,8 +33,6 @@ struct db_ctdb_rec {
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)
{
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;
}
/* 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)
{
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;
NTSTATUS status;
TDB_DATA ctdb_data;
int migrate_attempts = 0;
if (!(result = talloc(mem_ctx, struct db_record))) {
DEBUG(0, ("talloc failed\n"));
@ -153,7 +186,11 @@ again:
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;
talloc_set_destructor(result, db_ctdb_record_destr);
@ -175,12 +212,14 @@ again:
tdb_chainunlock(ctx->wtdb->tdb, key);
talloc_set_destructor(result, NULL);
migrate_attempts += 1;
DEBUG(10, ("ctdb_data.dptr = %p, dmaster = %u (%u)\n",
ctdb_data.dptr, ctdb_data.dptr ?
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster : -1,
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)) {
DEBUG(5, ("ctdb_migrate failed: %s\n",
nt_errstr(status)));
@ -191,6 +230,11 @@ 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));
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
* take the shortcut and just return it.
* we bypass the dmaster check for persistent databases
*/
if ((ctdb_data.dptr != NULL) &&
(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 */
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);
/* 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,
data);
status = ctdbd_fetch(messaging_ctdbd_connection(),ctx->db_id, key, mem_ctx, data);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("ctdbd_fetch failed: %s\n", nt_errstr(status)));
return -1;
@ -283,6 +328,22 @@ static void traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data)
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,
int (*fn)(struct db_record *rec,
void *private_data),
@ -296,6 +357,13 @@ static int db_ctdb_traverse(struct db_context *db,
state.fn = fn;
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);
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);
}
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,
int (*fn)(struct db_record *rec,
void *private_data),
@ -335,6 +424,12 @@ static int db_ctdb_traverse_read(struct db_context *db,
state.fn = fn;
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);
return 0;
}
@ -346,41 +441,6 @@ static int db_ctdb_get_seqnum(struct db_context *db)
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,
const char *name,
@ -390,7 +450,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
struct db_context *result;
struct db_ctdb_ctx *db_ctdb;
char *db_path;
NTSTATUS status;
if (!lp_clustering()) {
DEBUG(10, ("Clustering disabled -- no ctdb\n"));
@ -409,20 +468,15 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
return NULL;
}
db_ctdb->conn = NULL;
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)));
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));
TALLOC_FREE(result);
return NULL;
}
db_path = ctdbd_dbpath(db_ctdbd_conn(db_ctdb), db_ctdb,
db_ctdb->db_id);
db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb, db_ctdb->db_id);
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
/* only pass through specific flags */
tdb_flags &= TDB_SEQNUM;
@ -447,16 +501,4 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
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

View File

@ -17,10 +17,6 @@
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"
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->traverse = db_file_traverse;
result->traverse_read = db_file_traverse;
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
ctx->locked_record = NULL;
if (!(ctx->dirname = talloc_strdup(ctx, name))) {

View File

@ -31,6 +31,11 @@ static int db_tdb_record_destr(struct db_record* data)
struct db_tdb_ctx *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
? "Unlocking key %s\n" : "Unlocking key %.20s\n",
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;
int res;
if (DEBUGLEVEL >= 10) {
char *keystr = hex_encode(NULL, key.dptr, key.dsize);
/* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
if(DEBUGLEVEL >= 10) {
char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
DEBUG(10, (DEBUGLEVEL > 10
? "Locking key %s\n" : "Locking key %.20s\n",
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);
int res;
res = tdb_delete(ctx->wtdb->tdb, rec->key);
if (res == 0) {
return NT_STATUS_OK;
}
return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
return (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) ?
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
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_read = db_tdb_traverse_read;
result->get_seqnum = db_tdb_get_seqnum;
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
return result;
fail:

90
source3/lib/dbwrap_util.c Normal file
View 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;
}

View File

@ -22,6 +22,10 @@
#ifdef CLUSTER_SUPPORT
#include "librpc/gen_ndr/messaging.h"
#include "ctdb.h"
#include "ctdb_private.h"
#include "ctdbd_conn.h"
struct messaging_ctdbd_context {
struct ctdbd_connection *conn;

View File

@ -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)));
}
/*******************************************************************
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.
********************************************************************/

View File

@ -41,11 +41,11 @@ static struct db_context *brlock_db;
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,
(unsigned int)pls->context.smbpid,
(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",
(double)pls->start,
@ -263,10 +263,9 @@ void brl_init(bool read_only)
if (brlock_db) {
return;
}
brlock_db = db_open(NULL, lock_path("brlock.tdb"), 0,
TDB_DEFAULT
|TDB_VOLATILE
|(read_only?0x0:TDB_CLEAR_IF_FIRST),
brlock_db = db_open(NULL, lock_path("brlock.tdb"),
lp_open_files_db_hash_size(),
TDB_DEFAULT | TDB_CLEAR_IF_FIRST,
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
if (!brlock_db) {
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++) {
cb->fn(*key,
locks[i].context.pid,
locks[i].lock_type,
locks[i].lock_flav,
locks[i].start,
locks[i].size,
cb->private_data);
if (cb->fn) {
for ( i=0; i<num_locks; i++) {
cb->fn(*key,
locks[i].context.pid,
locks[i].lock_type,
locks[i].lock_flav,
locks[i].start,
locks[i].size,
cb->private_data);
}
}
SAFE_FREE(locks);

View File

@ -117,6 +117,15 @@ int count_current_connections( const char *sharename, bool clear )
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.
****************************************************************************/

View File

@ -93,17 +93,27 @@ static void set_capability(unsigned capability)
return;
}
data.effective |= (1<<capability);
if (0 == (data.effective & (1<<capability))) {
data.effective |= (1<<capability);
if (capset(&header, &data) == -1) {
DEBUG(3,("Unable to set %d capability (%s)\n",
capability, strerror(errno)));
if (capset(&header, &data) == -1) {
DEBUG(3,("Unable to set %d capability (%s)\n",
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)
{
if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {

View File

@ -268,10 +268,20 @@ static void add_child_pid(pid_t pid)
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;
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) {
/* Don't bother with the child list if we don't care anyway */
return;
@ -560,10 +570,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
if (got_sig_cld) {
pid_t pid;
int status;
got_sig_cld = False;
while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
remove_child_pid(pid);
while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
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;
}
/* 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 */
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");
}
/****************************************************************************
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.
****************************************************************************/
@ -1305,6 +1364,8 @@ extern void build_options(bool screen);
/* register our message handlers */
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_FORCE_TDIS, msg_force_tdis);
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_RELEASE_IP, msg_release_ip);
if ((lp_keepalive() != 0)
&& !(event_add_idle(smbd_event_context(), NULL,