[PATCH] notifyd
Volker Lendecke
Volker.Lendecke at SerNet.DE
Fri Jun 19 05:36:23 MDT 2015
Hi!
Attached find the latest incarnation of the notifyd I've
been talking about for a while now. Survived a few private
autobuilds.
Review appreciated!
Thanks,
Volker
--
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From ff8b3fb7bf40a83947c2f41cafaac4fe0232dff5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 9 Jul 2014 12:50:24 +0000
Subject: [PATCH 01/20] lib: Add tevent_req_poll_unix
This makes sync wrappers a bit shorter
Signed-off-by: Volker Lendecke <vl at samba.org>
---
lib/util/tevent_unix.c | 10 ++++++++++
lib/util/tevent_unix.h | 2 ++
2 files changed, 12 insertions(+)
diff --git a/lib/util/tevent_unix.c b/lib/util/tevent_unix.c
index ee7ec8a..63bdaf6 100644
--- a/lib/util/tevent_unix.c
+++ b/lib/util/tevent_unix.c
@@ -61,3 +61,13 @@ int tevent_req_simple_recv_unix(struct tevent_req *req)
tevent_req_received(req);
return err;
}
+
+bool tevent_req_poll_unix(struct tevent_req *req, struct tevent_context *ev,
+ int *err)
+{
+ bool ret = tevent_req_poll(req, ev);
+ if (!ret) {
+ *err = errno;
+ }
+ return ret;
+}
diff --git a/lib/util/tevent_unix.h b/lib/util/tevent_unix.h
index c1b0eb4..39689d6 100644
--- a/lib/util/tevent_unix.h
+++ b/lib/util/tevent_unix.h
@@ -28,5 +28,7 @@
bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno);
int tevent_req_simple_recv_unix(struct tevent_req *req);
+bool tevent_req_poll_unix(struct tevent_req *req, struct tevent_context *ev,
+ int *err);
#endif
--
1.7.9.5
From 2d628ffdfa3bef49872e43d690cea5a40661fc32 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 26 Apr 2015 11:02:27 +0200
Subject: [PATCH 02/20] lib: Add server_id_db_prune_name
With this you can remove a foreign mapping. Required to clean up dead
processes.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
lib/util/server_id_db.c | 31 ++++++++++++++++++++-----------
lib/util/server_id_db.h | 2 ++
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/lib/util/server_id_db.c b/lib/util/server_id_db.c
index 7f5b055..8354752 100644
--- a/lib/util/server_id_db.c
+++ b/lib/util/server_id_db.c
@@ -118,22 +118,18 @@ int server_id_db_add(struct server_id_db *db, const char *name)
return 0;
}
-int server_id_db_remove(struct server_id_db *db, const char *name)
+int server_id_db_prune_name(struct server_id_db *db, const char *name,
+ struct server_id server)
{
struct tdb_context *tdb = db->tdb->tdb;
struct server_id_buf buf;
TDB_DATA key;
uint8_t *data;
- char *ids, *n, *id;
+ char *ids, *id;
int ret;
- n = strv_find(db->names, name);
- if (n == NULL) {
- return ENOENT;
- }
-
key = string_term_tdb_data(name);
- server_id_str_buf(db->pid, &buf);
+ server_id_str_buf(server, &buf);
ret = tdb_chainlock(tdb, key);
if (ret == -1) {
@@ -162,9 +158,22 @@ int server_id_db_remove(struct server_id_db *db, const char *name)
tdb_chainunlock(tdb, key);
- if (ret == -1) {
- enum TDB_ERROR err = tdb_error(tdb);
- return map_unix_error_from_tdb(err);
+ return 0;
+}
+
+int server_id_db_remove(struct server_id_db *db, const char *name)
+{
+ char *n;
+ int ret;
+
+ n = strv_find(db->names, name);
+ if (n == NULL) {
+ return ENOENT;
+ }
+
+ ret = server_id_db_prune_name(db, name, db->pid);
+ if (ret != 0) {
+ return ret;
}
strv_delete(&db->names, n);
diff --git a/lib/util/server_id_db.h b/lib/util/server_id_db.h
index 31b3305..ff86436 100644
--- a/lib/util/server_id_db.h
+++ b/lib/util/server_id_db.h
@@ -32,6 +32,8 @@ struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
void server_id_db_reinit(struct server_id_db *db, struct server_id pid);
int server_id_db_add(struct server_id_db *db, const char *name);
int server_id_db_remove(struct server_id_db *db, const char *name);
+int server_id_db_prune_name(struct server_id_db *db, const char *name,
+ struct server_id server);
int server_id_db_lookup(struct server_id_db *db, const char *name,
TALLOC_CTX *mem_ctx, unsigned *num_servers,
struct server_id **servers);
--
1.7.9.5
From 820b2526cebf3cafd244a6421622e74f82090a54 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 8 Jun 2015 20:46:54 +0000
Subject: [PATCH 03/20] lib: Add server_id_db_pid()
Signed-off-by: Volker Lendecke <vl at samba.org>
---
lib/util/server_id_db.c | 5 +++++
lib/util/server_id_db.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/lib/util/server_id_db.c b/lib/util/server_id_db.c
index 8354752..0874129 100644
--- a/lib/util/server_id_db.c
+++ b/lib/util/server_id_db.c
@@ -74,6 +74,11 @@ void server_id_db_reinit(struct server_id_db *db, struct server_id pid)
TALLOC_FREE(db->names);
}
+struct server_id server_id_db_pid(struct server_id_db *db)
+{
+ return db->pid;
+}
+
static int server_id_db_destructor(struct server_id_db *db)
{
char *name = NULL;
diff --git a/lib/util/server_id_db.h b/lib/util/server_id_db.h
index ff86436..2dcce62 100644
--- a/lib/util/server_id_db.h
+++ b/lib/util/server_id_db.h
@@ -30,6 +30,7 @@ struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
const char *base_path,
int hash_size, int tdb_flags);
void server_id_db_reinit(struct server_id_db *db, struct server_id pid);
+struct server_id server_id_db_pid(struct server_id_db *db);
int server_id_db_add(struct server_id_db *db, const char *name);
int server_id_db_remove(struct server_id_db *db, const char *name);
int server_id_db_prune_name(struct server_id_db *db, const char *name,
--
1.7.9.5
From c56a988c78df88c62da6411f0338ef413517065b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 9 Jun 2015 05:03:25 +0000
Subject: [PATCH 04/20] lib: Add server_id_db_set_exclusive
This is used for server names where only one instance can exist.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/lib/server_id_db_util.c | 104 +++++++++++++++++++++++++++++++++++++++
source3/lib/server_id_db_util.h | 22 +++++++++
source3/wscript_build | 1 +
3 files changed, 127 insertions(+)
create mode 100644 source3/lib/server_id_db_util.c
create mode 100644 source3/lib/server_id_db_util.h
diff --git a/source3/lib/server_id_db_util.c b/source3/lib/server_id_db_util.c
new file mode 100644
index 0000000..ead9ed3
--- /dev/null
+++ b/source3/lib/server_id_db_util.c
@@ -0,0 +1,104 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utils around server_id_db with more dependencies
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "replace.h"
+#include "server_id_db_util.h"
+#include "serverid.h"
+
+static int server_id_db_check_exclusive(
+ struct server_id_db *db, const char *name,
+ unsigned num_servers, struct server_id *servers);
+
+int server_id_db_set_exclusive(struct server_id_db *db, const char *name)
+{
+ int ret;
+ unsigned num_servers;
+ struct server_id *servers;
+
+ ret = server_id_db_add(db, name);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = server_id_db_lookup(db, name, talloc_tos(),
+ &num_servers, &servers);
+ if (ret != 0) {
+ goto done;
+ }
+
+ /*
+ * Remove entries from the server_id_db for processes that have died
+ * and could not clean up. This is racy, as two processes could
+ * simultaneously try to register a name. Both would succeed in the
+ * server_id_db_add call, and both would see their peer active during
+ * the check_exclusive call. Both would get an EEXIST, and nobody
+ * would be able to register itself. But this is okay, as this is
+ * meant to be a cleanup routine, and normally only one daemon should
+ * start up at a time anyway. Getting this "right" would mean we would
+ * have to add locking to server_id_db, or add a dependency on
+ * serverids_exist to server_id_db. Both are too heavy-weight for my
+ * taste.
+ */
+
+ ret = server_id_db_check_exclusive(db, name, num_servers, servers);
+ TALLOC_FREE(servers);
+
+done:
+ if (ret != 0) {
+ server_id_db_remove(db, name);
+ }
+ return ret;
+}
+
+static int server_id_db_check_exclusive(
+ struct server_id_db *db, const char *name,
+ unsigned num_servers, struct server_id *servers)
+{
+ struct server_id me = server_id_db_pid(db);
+ bool exists[num_servers];
+ bool ok;
+ int i;
+
+ ok = serverids_exist(servers, num_servers, exists);
+ if (!ok) {
+ return ENOMEM;
+ }
+
+ for (i=0; i<num_servers; i++) {
+ int ret;
+
+ if (server_id_same_process(&me, &servers[i])) {
+ /*
+ * I am always around ... :-)
+ */
+ continue;
+ }
+
+ if (exists[i]) {
+ return EEXIST;
+ }
+
+ ret = server_id_db_prune_name(db, name, servers[i]);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/source3/lib/server_id_db_util.h b/source3/lib/server_id_db_util.h
new file mode 100644
index 0000000..5fdd078
--- /dev/null
+++ b/source3/lib/server_id_db_util.h
@@ -0,0 +1,22 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utils around server_id_db with more dependencies
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "lib/util/server_id_db.h"
+
+int server_id_db_set_exclusive(struct server_id_db *db, const char *name);
diff --git a/source3/wscript_build b/source3/wscript_build
index 231f1c0..3b44ace 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -320,6 +320,7 @@ bld.SAMBA3_SUBSYSTEM('samba3core',
lib/id_cache.c
lib/talloc_dict.c
lib/serverid.c
+ lib/server_id_db_util.c
lib/addrchange.c
../lib/util/debug_s3.c
lib/dumpcore.c
--
1.7.9.5
From 3951c6e582126527355cf1812c7c1f408bc73e17 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 15:53:53 +0100
Subject: [PATCH 05/20] param: Make "change notify" global
With a central notifyd, we can't do this per share anymore. Notifyd will
only look at absolute paths, not shares.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
docs-xml/smbdotconf/misc/changenotify.xml | 3 +--
lib/param/param_table.c | 4 ++--
source3/param/loadparm.c | 3 ++-
source3/smbd/service.c | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs-xml/smbdotconf/misc/changenotify.xml b/docs-xml/smbdotconf/misc/changenotify.xml
index 1344dce..70793d6 100644
--- a/docs-xml/smbdotconf/misc/changenotify.xml
+++ b/docs-xml/smbdotconf/misc/changenotify.xml
@@ -1,7 +1,6 @@
<samba:parameter name="change notify"
- context="S"
+ context="G"
type="boolean"
- parm="1"
xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
<description>
<para>This parameter specifies whether Samba should reply
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index 287839f..f80dce6 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -1651,8 +1651,8 @@ struct parm_struct parm_table[] = {
{
.label = "change notify",
.type = P_BOOL,
- .p_class = P_LOCAL,
- .offset = LOCAL_VAR(change_notify),
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(change_notify),
.special = NULL,
.enum_list = NULL,
},
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index cedaf1a..bd24844 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -238,7 +238,6 @@ static struct loadparm_service sDefault =
.acl_map_full_control = true,
.acl_group_control = false,
.acl_allow_execute_always = false,
- .change_notify = true,
.kernel_change_notify = true,
.allocation_roundup_size = SMB_ROUNDUP_ALLOCATION_SIZE,
.aio_read_size = 0,
@@ -721,6 +720,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
a large number of sites (tridge) */
Globals.hostname_lookups = false;
+ Globals.change_notify = true,
+
string_set(Globals.ctx, &Globals.passdb_backend, "tdbsam");
string_set(Globals.ctx, &Globals.ldap_suffix, "");
string_set(Globals.ctx, &Globals.szLdapMachineSuffix, "");
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index d1148e1..0544967 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -678,7 +678,7 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
on_err_call_dis_hook = true;
if ((!conn->printer) && (!conn->ipc) &&
- lp_change_notify(conn->params)) {
+ lp_change_notify()) {
if (sconn->notify_ctx == NULL) {
sconn->notify_ctx = notify_init(
sconn, sconn->msg_ctx, sconn->ev_ctx);
--
1.7.9.5
From f28b89a6cce67f3c58979449b81a2519eb1c28c0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 16:02:27 +0100
Subject: [PATCH 06/20] param: Make "kernel change notify" global
With a central notifyd, we can't do this per share anymore. Notifyd will
only look at absolute paths, not shares.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
docs-xml/smbdotconf/misc/kernelchangenotify.xml | 3 +--
lib/param/param_table.c | 4 ++--
source3/modules/vfs_default.c | 2 +-
source3/param/loadparm.c | 2 +-
4 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/docs-xml/smbdotconf/misc/kernelchangenotify.xml b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
index 1e11bb8..6a41dcb 100644
--- a/docs-xml/smbdotconf/misc/kernelchangenotify.xml
+++ b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
@@ -1,7 +1,6 @@
<samba:parameter name="kernel change notify"
- context="S"
+ context="G"
type="boolean"
- parm="1"
xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
<description>
<para>This parameter specifies whether Samba should ask the
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index f80dce6..58f32a0 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -1667,8 +1667,8 @@ struct parm_struct parm_table[] = {
{
.label = "kernel change notify",
.type = P_BOOL,
- .p_class = P_LOCAL,
- .offset = LOCAL_VAR(kernel_change_notify),
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(kernel_change_notify),
.special = NULL,
.enum_list = NULL,
},
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 9b434a0..8e4953e 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -2145,7 +2145,7 @@ static NTSTATUS vfswrap_notify_watch(vfs_handle_struct *vfs_handle,
* Until that is the case, hard-code inotify here.
*/
#ifdef HAVE_INOTIFY
- if (lp_kernel_change_notify(vfs_handle->conn->params)) {
+ if (lp_kernel_change_notify()) {
int ret;
if (!lp_parm_bool(-1, "notify", "inotify", True)) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index bd24844..710e36c 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -238,7 +238,6 @@ static struct loadparm_service sDefault =
.acl_map_full_control = true,
.acl_group_control = false,
.acl_allow_execute_always = false,
- .kernel_change_notify = true,
.allocation_roundup_size = SMB_ROUNDUP_ALLOCATION_SIZE,
.aio_read_size = 0,
.aio_write_size = 0,
@@ -721,6 +720,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.hostname_lookups = false;
Globals.change_notify = true,
+ Globals.kernel_change_notify = true,
string_set(Globals.ctx, &Globals.passdb_backend, "tdbsam");
string_set(Globals.ctx, &Globals.ldap_suffix, "");
--
1.7.9.5
From 9d63149c6ca2f579832212b87ed186adb5d2f406 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 20 Nov 2014 15:30:51 +0000
Subject: [PATCH 07/20] smbd: Add direct notify_fam support
notifyd won't have the VFS around, it is a systemwide daemon without
a connection to specific shares. To continue FAM support, notifyd
needs to be able to link it directly. This adds code to make fam
equivalent to inotify.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notify_fam.c | 305 +++++++++++++++++++++++++++++++++++++++++++++
source3/smbd/proto.h | 12 ++
source3/wscript_build | 7 +-
3 files changed, 323 insertions(+), 1 deletion(-)
create mode 100644 source3/smbd/notify_fam.c
diff --git a/source3/smbd/notify_fam.c b/source3/smbd/notify_fam.c
new file mode 100644
index 0000000..bf9050d
--- /dev/null
+++ b/source3/smbd/notify_fam.c
@@ -0,0 +1,305 @@
+/*
+ * FAM file notification support.
+ *
+ * Copyright (c) James Peach 2005
+ * 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 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 "smbd/smbd.h"
+#include "librpc/gen_ndr/notify.h"
+
+#include <fam.h>
+
+#if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF)
+/* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per
+ * every other FAM implementation. Phooey.
+ */
+typedef enum FAMCodes FAMCodes;
+#endif
+
+/* NOTE: There are multiple versions of FAM floating around the net, each with
+ * slight differences from the original SGI FAM implementation. In this file,
+ * we rely only on the SGI features and do not assume any extensions. For
+ * example, we do not look at FAMErrno, because it is not set by the original
+ * implementation.
+ *
+ * Random FAM links:
+ * http://oss.sgi.com/projects/fam/
+ * http://savannah.nongnu.org/projects/fam/
+ * http://sourceforge.net/projects/bsdfam/
+ */
+
+/* ------------------------------------------------------------------------- */
+
+struct fam_watch_context {
+ struct fam_watch_context *prev, *next;
+ FAMConnection *fam_connection;
+ struct FAMRequest fr;
+ struct sys_notify_context *sys_ctx;
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev);
+ void *private_data;
+ uint32_t mask; /* the inotify mask */
+ uint32_t filter; /* the windows completion filter */
+ const char *path;
+};
+
+
+/*
+ * We want one FAM connection per smbd, not one per tcon.
+ */
+static FAMConnection fam_connection;
+static bool fam_connection_initialized = False;
+
+static struct fam_watch_context *fam_notify_list;
+static void fam_handler(struct tevent_context *event_ctx,
+ struct tevent_fd *fd_event,
+ uint16_t flags,
+ void *private_data);
+
+static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
+ struct tevent_context *event_ctx)
+{
+ int res;
+ char *name;
+
+ ZERO_STRUCTP(fam_conn);
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+
+
+#ifdef HAVE_FAMNOEXISTS
+ /* We should honor outside setting of the GAM_CLIENT_ID. */
+ setenv("GAM_CLIENT_ID","SAMBA",0);
+#endif
+
+ if (asprintf(&name, "smbd (%lu)", (unsigned long)getpid()) == -1) {
+ DEBUG(0, ("No memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ res = FAMOpen2(fam_conn, name);
+
+#ifdef HAVE_FAMNOEXISTS
+ /*
+ * This reduces the chatter between GAMIN and samba making the pair
+ * much more reliable.
+ */
+ FAMNoExists(fam_conn);
+#endif
+
+ SAFE_FREE(name);
+
+ if (res < 0) {
+ DEBUG(10, ("FAM file change notifications not available: %s\n",
+ FamErrlist[-res]));
+ /*
+ * No idea how to get NT_STATUS from a FAM result
+ */
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ if (tevent_add_fd(event_ctx, event_ctx,
+ FAMCONNECTION_GETFD(fam_conn),
+ TEVENT_FD_READ, fam_handler,
+ (void *)fam_conn) == NULL) {
+ DEBUG(0, ("event_add_fd failed\n"));
+ FAMClose(fam_conn);
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void fam_reopen(FAMConnection *fam_conn,
+ struct tevent_context *event_ctx,
+ struct fam_watch_context *notify_list)
+{
+ struct fam_watch_context *ctx;
+
+ DEBUG(5, ("Re-opening FAM connection\n"));
+
+ FAMClose(fam_conn);
+
+ if (!NT_STATUS_IS_OK(fam_open_connection(fam_conn, event_ctx))) {
+ DEBUG(5, ("Re-opening fam connection failed\n"));
+ return;
+ }
+
+ for (ctx = notify_list; ctx; ctx = ctx->next) {
+ FAMMonitorDirectory(fam_conn, ctx->path, &ctx->fr, NULL);
+ }
+}
+
+static void fam_handler(struct tevent_context *event_ctx,
+ struct tevent_fd *fd_event,
+ uint16_t flags,
+ void *private_data)
+{
+ FAMConnection *fam_conn = (FAMConnection *)private_data;
+ FAMEvent fam_event;
+ struct fam_watch_context *ctx;
+ struct notify_event ne;
+
+ if (FAMPending(fam_conn) == 0) {
+ DEBUG(10, ("fam_handler called but nothing pending\n"));
+ return;
+ }
+
+ if (FAMNextEvent(fam_conn, &fam_event) != 1) {
+ DEBUG(5, ("FAMNextEvent returned an error\n"));
+ TALLOC_FREE(fd_event);
+ fam_reopen(fam_conn, event_ctx, fam_notify_list);
+ return;
+ }
+
+ DEBUG(10, ("Got FAMCode %d for %s\n", fam_event.code,
+ fam_event.filename));
+
+ switch (fam_event.code) {
+ case FAMChanged:
+ ne.action = NOTIFY_ACTION_MODIFIED;
+ break;
+ case FAMCreated:
+ ne.action = NOTIFY_ACTION_ADDED;
+ break;
+ case FAMDeleted:
+ ne.action = NOTIFY_ACTION_REMOVED;
+ break;
+ default:
+ DEBUG(10, ("Ignoring code FAMCode %d for file %s\n",
+ (int)fam_event.code, fam_event.filename));
+ return;
+ }
+
+ for (ctx = fam_notify_list; ctx; ctx = ctx->next) {
+ if (memcmp(&fam_event.fr, &ctx->fr, sizeof(FAMRequest)) == 0) {
+ break;
+ }
+ }
+
+ if (ctx == NULL) {
+ DEBUG(5, ("Discarding event for file %s\n",
+ fam_event.filename));
+ return;
+ }
+
+ if ((ne.path = strrchr_m(fam_event.filename, '\\')) == NULL) {
+ ne.path = fam_event.filename;
+ }
+ ne.dir = ctx->path;
+
+ ctx->callback(ctx->sys_ctx, ctx->private_data, &ne);
+}
+
+static int fam_watch_context_destructor(struct fam_watch_context *ctx)
+{
+ if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
+ FAMCancelMonitor(&fam_connection, &ctx->fr);
+ }
+ DLIST_REMOVE(fam_notify_list, ctx);
+ return 0;
+}
+
+/*
+ add a watch. The watch is removed when the caller calls
+ talloc_free() on *handle
+*/
+int _fam_watch(TALLOC_CTX *mem_ctx,
+ struct sys_notify_context *ctx,
+ const char *path,
+ uint32_t *filter,
+ uint32_t *subdir_filter,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p)
+{
+ const uint32_t fam_mask = (FILE_NOTIFY_CHANGE_FILE_NAME|
+ FILE_NOTIFY_CHANGE_DIR_NAME);
+ struct fam_watch_context *watch;
+ void **handle = (void **)handle_p;
+
+ *handle = NULL;
+
+ if ((*filter & fam_mask) == 0) {
+ DEBUG(10, ("filter = %u, ignoring in FAM\n", *filter));
+ return 0;
+ }
+
+ if (!fam_connection_initialized) {
+ if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
+ ctx->ev))) {
+ /*
+ * Just let smbd do all the work itself
+ */
+ return 0;
+ }
+ fam_connection_initialized = True;
+ }
+
+ if (!(watch = talloc(mem_ctx, struct fam_watch_context))) {
+ return ENOMEM;
+ }
+
+ watch->fam_connection = &fam_connection;
+
+ watch->callback = callback;
+ watch->private_data = private_data;
+ watch->sys_ctx = ctx;
+
+ watch->path = talloc_strdup(watch, path);
+ if (watch->path == NULL) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ TALLOC_FREE(watch);
+ return ENOMEM;
+ }
+
+ /*
+ * The FAM module in this early state will only take care of
+ * FAMCreated and FAMDeleted events, Leave the rest to notifyd
+ */
+
+ watch->filter = fam_mask;
+ *filter &= ~fam_mask;
+
+ DLIST_ADD(fam_notify_list, watch);
+ talloc_set_destructor(watch, fam_watch_context_destructor);
+
+ /*
+ * Only directories monitored so far
+ */
+
+ if (FAMCONNECTION_GETFD(watch->fam_connection) != -1) {
+ FAMMonitorDirectory(watch->fam_connection, watch->path,
+ &watch->fr, NULL);
+ }
+ else {
+ /*
+ * If the re-open is successful, this will establish the
+ * FAMMonitor from the list
+ */
+ fam_reopen(watch->fam_connection, ctx->ev, fam_notify_list);
+ }
+
+ *handle = watch;
+
+ return 0;
+}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 531b58d..e91c355 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -543,6 +543,18 @@ int inotify_watch(TALLOC_CTX *mem_ctx,
void *private_data,
void *handle_p);
+int _fam_watch(TALLOC_CTX *mem_ctx,
+ struct sys_notify_context *ctx,
+ const char *path,
+ uint32_t *filter,
+ uint32_t *subdir_filter,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p);
+
+
/* The following definitions come from smbd/notify_internal.c */
struct notify_context *notify_init(TALLOC_CTX *mem_ctx,
diff --git a/source3/wscript_build b/source3/wscript_build
index 3b44ace..60d1ea6 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -516,6 +516,9 @@ NOTIFY_SOURCES=''
if bld.CONFIG_SET("HAVE_INOTIFY"):
NOTIFY_SOURCES += ' smbd/notify_inotify.c'
+if bld.CONFIG_SET('SAMBA_FAM_LIBS'):
+ NOTIFY_SOURCES += ' smbd/notify_fam.c'
+
bld.SAMBA3_LIBRARY('smbd_base',
source='''
smbd/server_reload.c
@@ -635,7 +638,9 @@ bld.SAMBA3_LIBRARY('smbd_base',
NDR_SMB_ACL
netapi
NDR_IOCTL
- ''' + bld.env['dmapi_lib'],
+ ''' + bld.env['dmapi_lib']
+ + (bld.CONFIG_GET('SAMBA_FAM_LIBS')
+ if bld.CONFIG_SET('SAMBA_FAM_LIBS') else ''),
private_library=True)
bld.SAMBA3_SUBSYSTEM('LOCKING',
--
1.7.9.5
From 860f6bec81cca531536d16a446dd737c27620ac9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 16:52:47 +0100
Subject: [PATCH 08/20] smbd: Add the notify daemon
This adds the notify daemon listening on MSG_SMB_NOTIFY_REC_CHANGE
and MSG_SMB_NOTIFY_TRIGGER messages. It relies on ctdbd to distribute
the notify database and events in a cluster.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
librpc/idl/messaging.idl | 13 +
source3/smbd/notifyd/notifyd.c | 1418 ++++++++++++++++++++++++++++++++++++
source3/smbd/notifyd/notifyd.h | 143 ++++
source3/smbd/notifyd/tests.c | 118 +++
source3/smbd/notifyd/wscript_build | 12 +
source3/wscript_build | 1 +
6 files changed, 1705 insertions(+)
create mode 100644 source3/smbd/notifyd/notifyd.c
create mode 100644 source3/smbd/notifyd/notifyd.h
create mode 100644 source3/smbd/notifyd/tests.c
create mode 100644 source3/smbd/notifyd/wscript_build
diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index 2b902ec..ca99f41 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -99,6 +99,13 @@ interface messaging
/* Cancel a notify, directory got deleted */
MSG_SMB_NOTIFY_CANCEL_DELETED = 0x0319,
+ /* notifyd messages */
+ MSG_SMB_NOTIFY_REC_CHANGE = 0x031A,
+ MSG_SMB_NOTIFY_TRIGGER = 0x031B,
+ MSG_SMB_NOTIFY_GET_DB = 0x031C,
+ MSG_SMB_NOTIFY_DB = 0x031D,
+ MSG_SMB_NOTIFY_REC_CHANGES = 0x031E,
+
/* winbind messages */
MSG_WINBIND_FINISHED = 0x0401,
MSG_WINBIND_FORGET_STATE = 0x0402,
@@ -152,4 +159,10 @@ interface messaging
uint8 num_fds;
dlong fds[num_fds];
} messaging_rec;
+
+ typedef [public] struct {
+ hyper rec_index;
+ uint32 num_recs;
+ messaging_rec *recs[num_recs];
+ } messaging_reclog;
}
diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c
new file mode 100644
index 0000000..ea48035
--- /dev/null
+++ b/source3/smbd/notifyd/notifyd.c
@@ -0,0 +1,1418 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "librpc/gen_ndr/notify.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "librpc/gen_ndr/server_id.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "messages.h"
+#include "proto.h"
+#include "tdb.h"
+#include "util_tdb.h"
+#include "notifyd.h"
+#include "lib/util/server_id_db.h"
+#include "lib/util/tevent_unix.h"
+#include "ctdbd_conn.h"
+#include "ctdb_srvids.h"
+#include "source3/smbd/proto.h"
+#include "ctdb/include/ctdb_protocol.h"
+#include "server_id_db_util.h"
+#include "lib/util/iov_buf.h"
+#include "messages_util.h"
+
+struct notifyd_peer;
+
+/*
+ * All of notifyd's state
+ */
+
+struct notifyd_state {
+ struct tevent_context *ev;
+ struct messaging_context *msg_ctx;
+ struct ctdbd_connection *ctdbd_conn;
+
+ /*
+ * Database of everything clients show interest in. Indexed by
+ * absolute path. The database keys are not 0-terminated
+ * because the criticial operation, notifyd_trigger, can walk
+ * the structure from the top without adding intermediate 0s.
+ * The database records contain an array of
+ *
+ * struct notifyd_instance
+ *
+ * to be maintained by parsed by notifyd_entry_parse()
+ */
+ struct db_context *entries;
+
+ /*
+ * In the cluster case, this is the place where we store a log
+ * of all MSG_SMB_NOTIFY_REC_CHANGE messages. We just 1:1
+ * forward them to our peer notifyd's in the cluster once a
+ * second or when the log grows too large.
+ */
+
+ struct messaging_reclog *log;
+
+ /*
+ * Array of companion notifyd's in a cluster. Every notifyd
+ * broadcasts its messaging_reclog to every other notifyd in
+ * the cluster. This is done by making ctdb send a message to
+ * srvid CTDB_SRVID_SAMBA_NOTIFY_PROXY with destination node
+ * number CTDB_BROADCAST_VNNMAP. Everybody in the cluster who
+ * had called register_with_ctdbd this srvid will receive the
+ * broadcasts.
+ *
+ * Database replication happens via these broadcasts. Also,
+ * they serve as liveness indication. If a notifyd receives a
+ * broadcast from an unknown peer, it will create one for this
+ * srvid. Also when we don't hear anything from a peer for a
+ * while, we will discard it.
+ */
+
+ struct notifyd_peer **peers;
+ size_t num_peers;
+
+ sys_notify_watch_fn sys_notify_watch;
+ struct sys_notify_context *sys_notify_ctx;
+};
+
+/*
+ * notifyd's representation of a notify instance
+ */
+struct notifyd_instance {
+ struct server_id client;
+ struct notify_instance instance;
+
+ void *sys_watch; /* inotify/fam/etc handle */
+
+ /*
+ * Filters after sys_watch took responsibility of some bits
+ */
+ uint32_t internal_filter;
+ uint32_t internal_subdir_filter;
+};
+
+struct notifyd_peer {
+ struct notifyd_state *state;
+ struct server_id pid;
+ uint64_t rec_index;
+ struct db_context *db;
+ time_t last_broadcast;
+};
+
+static bool notifyd_rec_change(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data);
+static bool notifyd_trigger(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data);
+static bool notifyd_get_db(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data);
+static bool notifyd_got_db(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data);
+static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn,
+ struct server_id src,
+ struct messaging_reclog *log);
+static void notifyd_sys_callback(struct sys_notify_context *ctx,
+ void *private_data, struct notify_event *ev);
+
+static struct tevent_req *notifyd_broadcast_reclog_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct ctdbd_connection *ctdbd_conn, struct server_id src,
+ struct messaging_reclog *log);
+static int notifyd_broadcast_reclog_recv(struct tevent_req *req);
+
+static struct tevent_req *notifyd_clean_peers_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct notifyd_state *notifyd);
+static int notifyd_clean_peers_recv(struct tevent_req *req);
+
+static int sys_notify_watch_dummy(TALLOC_CTX *mem_ctx,
+ struct sys_notify_context *ctx,
+ const char *path,
+ uint32_t *filter,
+ uint32_t *subdir_filter,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p)
+{
+ void **handle = handle_p;
+ *handle = NULL;
+ return 0;
+}
+
+static void notifyd_handler_done(struct tevent_req *subreq);
+static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq);
+static void notifyd_clean_peers_finished(struct tevent_req *subreq);
+static void notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
+ uint64_t dst_srvid,
+ const uint8_t *msg, size_t msglen,
+ void *private_data);
+
+struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ struct ctdbd_connection *ctdbd_conn,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_state *state;
+ struct server_id_db *names_db;
+ NTSTATUS status;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct notifyd_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->msg_ctx = msg_ctx;
+ state->ctdbd_conn = ctdbd_conn;
+
+ if (sys_notify_watch == NULL) {
+ sys_notify_watch = sys_notify_watch_dummy;
+ }
+
+ state->sys_notify_watch = sys_notify_watch;
+ state->sys_notify_ctx = sys_notify_ctx;
+
+ state->entries = db_open_rbt(state);
+ if (tevent_req_nomem(state->entries, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = messaging_handler_send(state, ev, msg_ctx,
+ MSG_SMB_NOTIFY_REC_CHANGE,
+ notifyd_rec_change, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_handler_done, req);
+
+ subreq = messaging_handler_send(state, ev, msg_ctx,
+ MSG_SMB_NOTIFY_TRIGGER,
+ notifyd_trigger, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_handler_done, req);
+
+ subreq = messaging_handler_send(state, ev, msg_ctx,
+ MSG_SMB_NOTIFY_GET_DB,
+ notifyd_get_db, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_handler_done, req);
+
+ subreq = messaging_handler_send(state, ev, msg_ctx,
+ MSG_SMB_NOTIFY_DB,
+ notifyd_got_db, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_handler_done, req);
+
+ names_db = messaging_names_db(msg_ctx);
+
+ ret = server_id_db_set_exclusive(names_db, "notify-daemon");
+ if (ret != 0) {
+ DEBUG(10, ("%s: server_id_db_add failed: %s\n",
+ __func__, strerror(ret)));
+ tevent_req_error(req, ret);
+ return tevent_req_post(req, ev);
+ }
+
+ if (ctdbd_conn == NULL) {
+ /*
+ * No cluster around, skip the database replication
+ * engine
+ */
+ return req;
+ }
+
+ state->log = talloc_zero(state, struct messaging_reclog);
+ if (tevent_req_nomem(state->log, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = notifyd_broadcast_reclog_send(
+ state->log, ev, ctdbd_conn, messaging_server_id(msg_ctx),
+ state->log);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_broadcast_reclog_finished,
+ req);
+
+ subreq = notifyd_clean_peers_send(state, ev, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_clean_peers_finished,
+ req);
+
+ status = register_with_ctdbd(ctdbd_conn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
+ notifyd_snoop_broadcast, state);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_error(req, map_errno_from_nt_status(status));
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void notifyd_handler_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+
+ ret = messaging_handler_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_error(req, ret);
+}
+
+static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+
+ ret = notifyd_broadcast_reclog_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_error(req, ret);
+}
+
+static void notifyd_clean_peers_finished(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+
+ ret = notifyd_clean_peers_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_error(req, ret);
+}
+
+int notifyd_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+/*
+ * Parse an entry in the notifyd_context->entries database
+ */
+
+static bool notifyd_parse_entry(uint8_t *buf, size_t buflen,
+ struct notifyd_instance **instances,
+ size_t *num_instances)
+{
+ if ((buflen % sizeof(struct notifyd_instance)) != 0) {
+ DEBUG(1, ("%s: invalid buffer size: %u\n",
+ __func__, (unsigned)buflen));
+ return false;
+ }
+
+ if (instances != NULL) {
+ *instances = (struct notifyd_instance *)buf;
+ }
+ if (num_instances != NULL) {
+ *num_instances = buflen / sizeof(struct notifyd_instance);
+ }
+ return true;
+}
+
+static bool notifyd_apply_rec_change(
+ const struct server_id *client,
+ const char *path, size_t pathlen,
+ const struct notify_instance *chg,
+ struct db_context *entries,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx,
+ struct messaging_context *msg_ctx)
+{
+ struct db_record *rec;
+ struct notifyd_instance *instances;
+ size_t num_instances;
+ size_t i;
+ struct notifyd_instance *instance;
+ TDB_DATA value;
+ NTSTATUS status;
+ bool ok = false;
+
+ if (pathlen == 0) {
+ DEBUG(1, ("%s: pathlen==0\n", __func__));
+ return false;
+ }
+ if (path[pathlen-1] != '\0') {
+ DEBUG(1, ("%s: path not 0-terminated\n", __func__));
+ return false;
+ }
+
+ DEBUG(10, ("%s: path=%s, filter=%u, subdir_filter=%u, "
+ "private_data=%p\n", __func__, path,
+ (unsigned)chg->filter, (unsigned)chg->subdir_filter,
+ chg->private_data));
+
+ rec = dbwrap_fetch_locked(
+ entries, entries,
+ make_tdb_data((const uint8_t *)path, pathlen-1));
+
+ if (rec == NULL) {
+ DEBUG(1, ("%s: dbwrap_fetch_locked failed\n", __func__));
+ goto fail;
+ }
+
+ num_instances = 0;
+ value = dbwrap_record_get_value(rec);
+
+ if (value.dsize != 0) {
+ if (!notifyd_parse_entry(value.dptr, value.dsize, NULL,
+ &num_instances)) {
+ goto fail;
+ }
+ }
+
+ /*
+ * Overallocate by one instance to avoid a realloc when adding
+ */
+ instances = talloc_array(rec, struct notifyd_instance,
+ num_instances + 1);
+ if (instances == NULL) {
+ DEBUG(1, ("%s: talloc failed\n", __func__));
+ goto fail;
+ }
+
+ if (value.dsize != 0) {
+ memcpy(instances, value.dptr, value.dsize);
+ }
+
+ for (i=0; i<num_instances; i++) {
+ instance = &instances[i];
+
+ if (server_id_equal(&instance->client, client) &&
+ (instance->instance.private_data == chg->private_data)) {
+ break;
+ }
+ }
+
+ if (i < num_instances) {
+ instance->instance = *chg;
+ } else {
+ /*
+ * We've overallocated for one instance
+ */
+ instance = &instances[num_instances];
+
+ *instance = (struct notifyd_instance) {
+ .client = *client,
+ .instance = *chg,
+ .internal_filter = chg->filter,
+ .internal_subdir_filter = chg->subdir_filter
+ };
+
+ num_instances += 1;
+ }
+
+ if ((instance->instance.filter != 0) ||
+ (instance->instance.subdir_filter != 0)) {
+ int ret;
+
+ TALLOC_FREE(instance->sys_watch);
+
+ ret = sys_notify_watch(entries, sys_notify_ctx, path,
+ &instance->internal_filter,
+ &instance->internal_subdir_filter,
+ notifyd_sys_callback, msg_ctx,
+ &instance->sys_watch);
+ if (ret != 0) {
+ DEBUG(1, ("%s: inotify_watch returned %s\n",
+ __func__, strerror(errno)));
+ }
+ }
+
+ if ((instance->instance.filter == 0) &&
+ (instance->instance.subdir_filter == 0)) {
+ /* This is a delete request */
+ TALLOC_FREE(instance->sys_watch);
+ *instance = instances[num_instances-1];
+ num_instances -= 1;
+ }
+
+ DEBUG(10, ("%s: %s has %u instances\n", __func__,
+ path, (unsigned)num_instances));
+
+ if (num_instances == 0) {
+ status = dbwrap_record_delete(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: dbwrap_record_delete returned %s\n",
+ __func__, nt_errstr(status)));
+ goto fail;
+ }
+ } else {
+ value = make_tdb_data(
+ (uint8_t *)instances,
+ sizeof(struct notifyd_instance) * num_instances);
+
+ status = dbwrap_record_store(rec, value, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: dbwrap_record_store returned %s\n",
+ __func__, nt_errstr(status)));
+ goto fail;
+ }
+ }
+
+ ok = true;
+fail:
+ TALLOC_FREE(rec);
+ return ok;
+}
+
+static void notifyd_sys_callback(struct sys_notify_context *ctx,
+ void *private_data, struct notify_event *ev)
+{
+ struct messaging_context *msg_ctx = talloc_get_type_abort(
+ private_data, struct messaging_context);
+ struct notify_trigger_msg msg;
+ struct iovec iov[4];
+ char slash = '/';
+
+ msg = (struct notify_trigger_msg) {
+ .when = timespec_current(),
+ .action = ev->action,
+ .filter = UINT32_MAX
+ };
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_trigger_msg, path);
+ iov[1].iov_base = discard_const_p(char, ev->dir);
+ iov[1].iov_len = strlen(ev->dir);
+ iov[2].iov_base = &slash;
+ iov[2].iov_len = 1;
+ iov[3].iov_base = discard_const_p(char, ev->path);
+ iov[3].iov_len = strlen(ev->path)+1;
+
+ messaging_send_iov(
+ msg_ctx, messaging_server_id(msg_ctx),
+ MSG_SMB_NOTIFY_TRIGGER, iov, ARRAY_SIZE(iov), NULL, 0);
+}
+
+static bool notifyd_parse_rec_change(uint8_t *buf, size_t bufsize,
+ struct notify_rec_change_msg **pmsg,
+ size_t *pathlen)
+{
+ struct notify_rec_change_msg *msg;
+
+ if (bufsize < offsetof(struct notify_rec_change_msg, path) + 1) {
+ DEBUG(1, ("%s: message too short, ignoring: %u\n", __func__,
+ (unsigned)bufsize));
+ return false;
+ }
+
+ *pmsg = msg = (struct notify_rec_change_msg *)buf;
+ *pathlen = bufsize - offsetof(struct notify_rec_change_msg, path);
+
+ DEBUG(10, ("%s: Got rec_change_msg filter=%u, subdir_filter=%u, "
+ "private_data=%p, path=%.*s\n",
+ __func__, (unsigned)msg->instance.filter,
+ (unsigned)msg->instance.subdir_filter,
+ msg->instance.private_data, (int)(*pathlen), msg->path));
+
+ return true;
+}
+
+static bool notifyd_rec_change(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct server_id_buf idbuf;
+ struct messaging_rec *rec = *prec;
+ struct messaging_rec **tmp;
+ struct messaging_reclog *log;
+ struct notify_rec_change_msg *msg;
+ size_t pathlen;
+ bool ok;
+
+ DEBUG(10, ("%s: Got %d bytes from %s\n", __func__,
+ (unsigned)rec->buf.length,
+ server_id_str_buf(rec->src, &idbuf)));
+
+ ok = notifyd_parse_rec_change(rec->buf.data, rec->buf.length,
+ &msg, &pathlen);
+ if (!ok) {
+ return true;
+ }
+
+ ok = notifyd_apply_rec_change(
+ &rec->src, msg->path, pathlen, &msg->instance,
+ state->entries, state->sys_notify_watch, state->sys_notify_ctx,
+ state->msg_ctx);
+ if (!ok) {
+ DEBUG(1, ("%s: notifyd_apply_rec_change failed, ignoring\n",
+ __func__));
+ return true;
+ }
+
+ if ((state->log == NULL) || (state->ctdbd_conn == NULL)) {
+ return true;
+ }
+ log = state->log;
+
+ tmp = talloc_realloc(log, log->recs, struct messaging_rec *,
+ log->num_recs+1);
+ if (tmp == NULL) {
+ DEBUG(1, ("%s: talloc_realloc failed, ignoring\n", __func__));
+ return true;
+ }
+ log->recs = tmp;
+
+ log->recs[log->num_recs] = talloc_move(log->recs, prec);
+ log->num_recs += 1;
+
+ if (log->num_recs >= 100) {
+ /*
+ * Don't let the log grow too large
+ */
+ notifyd_broadcast_reclog(state->ctdbd_conn,
+ messaging_server_id(msg_ctx), log);
+ }
+
+ return true;
+}
+
+struct notifyd_trigger_state {
+ struct messaging_context *msg_ctx;
+ struct notify_trigger_msg *msg;
+ bool recursive;
+ bool covered_by_sys_notify;
+};
+
+static void notifyd_trigger_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data);
+
+static bool notifyd_trigger(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct server_id my_id = messaging_server_id(msg_ctx);
+ struct messaging_rec *rec = *prec;
+ struct notifyd_trigger_state tstate;
+ const char *path;
+ const char *p, *next_p;
+
+ if (rec->buf.length < offsetof(struct notify_trigger_msg, path) + 1) {
+ DEBUG(1, ("message too short, ignoring: %u\n",
+ (unsigned)rec->buf.length));
+ return true;
+ }
+ if (rec->buf.data[rec->buf.length-1] != 0) {
+ DEBUG(1, ("%s: path not 0-terminated, ignoring\n", __func__));
+ return true;
+ }
+
+ tstate.msg_ctx = msg_ctx;
+
+ tstate.covered_by_sys_notify = (rec->src.vnn == my_id.vnn);
+ tstate.covered_by_sys_notify &= !server_id_equal(&rec->src, &my_id);
+
+ tstate.msg = (struct notify_trigger_msg *)rec->buf.data;
+ path = tstate.msg->path;
+
+ DEBUG(10, ("%s: Got trigger_msg action=%u, filter=%u, path=%s\n",
+ __func__, (unsigned)tstate.msg->action,
+ (unsigned)tstate.msg->filter, path));
+
+ if (path[0] != '/') {
+ DEBUG(1, ("%s: path %s does not start with /, ignoring\n",
+ __func__, path));
+ return true;
+ }
+
+ for (p = strchr(path+1, '/'); p != NULL; p = next_p) {
+ ptrdiff_t path_len = p - path;
+ TDB_DATA key;
+ uint32_t i;
+
+ next_p = strchr(p+1, '/');
+ tstate.recursive = (next_p != NULL);
+
+ DEBUG(10, ("%s: Trying path %.*s\n", __func__,
+ (int)path_len, path));
+
+ key = (TDB_DATA) { .dptr = discard_const_p(uint8_t, path),
+ .dsize = path_len };
+
+ dbwrap_parse_record(state->entries, key,
+ notifyd_trigger_parser, &tstate);
+
+ if (state->peers == NULL) {
+ continue;
+ }
+
+ if (rec->src.vnn != my_id.vnn) {
+ continue;
+ }
+
+ for (i=0; i<state->num_peers; i++) {
+ if (state->peers[i]->db == NULL) {
+ /*
+ * Inactive peer, did not get a db yet
+ */
+ continue;
+ }
+ dbwrap_parse_record(state->peers[i]->db, key,
+ notifyd_trigger_parser, &tstate);
+ }
+ }
+
+ return true;
+}
+
+static void notifyd_send_delete(struct messaging_context *msg_ctx,
+ TDB_DATA key,
+ struct notifyd_instance *instance);
+
+static void notifyd_trigger_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+
+{
+ struct notifyd_trigger_state *tstate = private_data;
+ struct notify_event_msg msg = { .action = tstate->msg->action };
+ struct iovec iov[2];
+ size_t path_len = key.dsize;
+ struct notifyd_instance *instances = NULL;
+ size_t num_instances = 0;
+ size_t i;
+
+ if (!notifyd_parse_entry(data.dptr, data.dsize, &instances,
+ &num_instances)) {
+ DEBUG(1, ("%s: Could not parse notifyd_entry\n", __func__));
+ return;
+ }
+
+ DEBUG(10, ("%s: Found %u instances for %.*s\n", __func__,
+ (unsigned)num_instances, (int)key.dsize,
+ (char *)key.dptr));
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_event_msg, path);
+ iov[1].iov_base = tstate->msg->path + path_len + 1;
+ iov[1].iov_len = strlen((char *)(iov[1].iov_base)) + 1;
+
+ for (i=0; i<num_instances; i++) {
+ struct notifyd_instance *instance = &instances[i];
+ struct server_id_buf idbuf;
+ uint32_t i_filter;
+ NTSTATUS status;
+
+ if (tstate->covered_by_sys_notify) {
+ if (tstate->recursive) {
+ i_filter = instance->internal_subdir_filter;
+ } else {
+ i_filter = instance->internal_filter;
+ }
+ } else {
+ if (tstate->recursive) {
+ i_filter = instance->instance.subdir_filter;
+ } else {
+ i_filter = instance->instance.filter;
+ }
+ }
+
+ if ((i_filter & tstate->msg->filter) == 0) {
+ continue;
+ }
+
+ msg.private_data = instance->instance.private_data;
+
+ status = messaging_send_iov(
+ tstate->msg_ctx, instance->client,
+ MSG_PVFS_NOTIFY, iov, ARRAY_SIZE(iov), NULL, 0);
+
+ DEBUG(10, ("%s: messaging_send_iov to %s returned %s\n",
+ __func__,
+ server_id_str_buf(instance->client, &idbuf),
+ nt_errstr(status)));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+ procid_is_local(&instance->client)) {
+ /*
+ * That process has died
+ */
+ notifyd_send_delete(tstate->msg_ctx, key, instance);
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: messaging_send_iov returned %s\n",
+ __func__, nt_errstr(status)));
+ }
+ }
+}
+
+/*
+ * Send a delete request to ourselves to properly discard a notify
+ * record for an smbd that has died.
+ */
+
+static void notifyd_send_delete(struct messaging_context *msg_ctx,
+ TDB_DATA key,
+ struct notifyd_instance *instance)
+{
+ struct notify_rec_change_msg msg = {
+ .instance.private_data = instance->instance.private_data
+ };
+ uint8_t nul = 0;
+ struct iovec iov[3];
+ NTSTATUS status;
+
+ /*
+ * Send a rec_change to ourselves to delete a dead entry
+ */
+
+ iov[0] = (struct iovec) {
+ .iov_base = &msg,
+ .iov_len = offsetof(struct notify_rec_change_msg, path) };
+ iov[1] = (struct iovec) { .iov_base = key.dptr, .iov_len = key.dsize };
+ iov[2] = (struct iovec) { .iov_base = &nul, .iov_len = sizeof(nul) };
+
+ status = messaging_send_iov_from(
+ msg_ctx, instance->client, messaging_server_id(msg_ctx),
+ MSG_SMB_NOTIFY_REC_CHANGE, iov, ARRAY_SIZE(iov), NULL, 0);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("%s: messaging_send_iov_from returned %s\n",
+ __func__, nt_errstr(status)));
+ }
+}
+
+static bool notifyd_get_db(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct messaging_rec *rec = *prec;
+ struct server_id_buf id1, id2;
+ NTSTATUS status;
+ uint64_t rec_index = UINT64_MAX;
+ uint8_t index_buf[sizeof(uint64_t)];
+ size_t dbsize;
+ uint8_t *buf;
+ struct iovec iov[2];
+
+ dbsize = dbwrap_marshall(state->entries, NULL, 0);
+
+ buf = talloc_array(rec, uint8_t, dbsize);
+ if (buf == NULL) {
+ DEBUG(1, ("%s: talloc_array(%ju) failed\n",
+ __func__, (uintmax_t)dbsize));
+ return true;
+ }
+
+ dbsize = dbwrap_marshall(state->entries, buf, dbsize);
+
+ if (dbsize != talloc_get_size(buf)) {
+ DEBUG(1, ("%s: dbsize changed: %ju->%ju\n", __func__,
+ (uintmax_t)talloc_get_size(buf),
+ (uintmax_t)dbsize));
+ TALLOC_FREE(buf);
+ return true;
+ }
+
+ if (state->log != NULL) {
+ rec_index = state->log->rec_index;
+ }
+ SBVAL(index_buf, 0, rec_index);
+
+ iov[0] = (struct iovec) { .iov_base = index_buf,
+ .iov_len = sizeof(index_buf) };
+ iov[1] = (struct iovec) { .iov_base = buf,
+ .iov_len = dbsize };
+
+ DEBUG(10, ("%s: Sending %ju bytes to %s->%s\n", __func__,
+ (uintmax_t)iov_buflen(iov, ARRAY_SIZE(iov)),
+ server_id_str_buf(messaging_server_id(msg_ctx), &id1),
+ server_id_str_buf(rec->src, &id2)));
+
+ status = messaging_send_iov(msg_ctx, rec->src, MSG_SMB_NOTIFY_DB,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+ TALLOC_FREE(buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: messaging_send_iov failed: %s\n",
+ __func__, nt_errstr(status)));
+ }
+
+ return true;
+}
+
+static int notifyd_add_proxy_syswatches(struct db_record *rec,
+ void *private_data);
+
+static bool notifyd_got_db(struct messaging_context *msg_ctx,
+ struct messaging_rec **prec,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct messaging_rec *rec = *prec;
+ struct notifyd_peer *p = NULL;
+ struct server_id_buf idbuf;
+ NTSTATUS status;
+ int count;
+ size_t i;
+
+ for (i=0; i<state->num_peers; i++) {
+ if (server_id_equal(&rec->src, &state->peers[i]->pid)) {
+ p = state->peers[i];
+ break;
+ }
+ }
+
+ if (p == NULL) {
+ DEBUG(10, ("%s: Did not find peer for db from %s\n",
+ __func__, server_id_str_buf(rec->src, &idbuf)));
+ return true;
+ }
+
+ if (rec->buf.length < 8) {
+ DEBUG(10, ("%s: Got short db length %u from %s\n", __func__,
+ (unsigned)rec->buf.length,
+ server_id_str_buf(rec->src, &idbuf)));
+ TALLOC_FREE(p);
+ return true;
+ }
+
+ p->rec_index = BVAL(rec->buf.data, 0);
+
+ p->db = db_open_rbt(p);
+ if (p->db == NULL) {
+ DEBUG(10, ("%s: db_open_rbt failed\n", __func__));
+ TALLOC_FREE(p);
+ return true;
+ }
+
+ status = dbwrap_unmarshall(p->db, rec->buf.data + 8,
+ rec->buf.length - 8);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("%s: dbwrap_unmarshall returned %s for db %s\n",
+ __func__, nt_errstr(status),
+ server_id_str_buf(rec->src, &idbuf)));
+ TALLOC_FREE(p);
+ return true;
+ }
+
+ dbwrap_traverse_read(p->db, notifyd_add_proxy_syswatches, state,
+ &count);
+
+ DEBUG(10, ("%s: Database from %s contained %d records\n", __func__,
+ server_id_str_buf(rec->src, &idbuf), count));
+
+ return true;
+}
+
+static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn,
+ struct server_id src,
+ struct messaging_reclog *log)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ uint8_t msghdr[MESSAGE_HDR_LENGTH];
+ DATA_BLOB blob;
+ struct iovec iov[2];
+
+ if (log == NULL) {
+ return;
+ }
+
+ DEBUG(10, ("%s: rec_index=%ju, num_recs=%u\n", __func__,
+ (uintmax_t)log->rec_index, (unsigned)log->num_recs));
+
+ message_hdr_put(msghdr, MSG_SMB_NOTIFY_REC_CHANGES, src,
+ (struct server_id) {0 });
+ iov[0] = (struct iovec) { .iov_base = msghdr,
+ .iov_len = sizeof(msghdr) };
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, log, log,
+ (ndr_push_flags_fn_t)ndr_push_messaging_reclog);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(1, ("%s: ndr_push_messaging_recs failed: %s\n",
+ __func__, ndr_errstr(ndr_err)));
+ goto done;
+ }
+ iov[1] = (struct iovec) { .iov_base = blob.data,
+ .iov_len = blob.length };
+
+ status = ctdbd_messaging_send_iov(
+ ctdbd_conn, CTDB_BROADCAST_VNNMAP,
+ CTDB_SRVID_SAMBA_NOTIFY_PROXY, iov, ARRAY_SIZE(iov));
+ TALLOC_FREE(blob.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: ctdbd_messaging_send failed: %s\n",
+ __func__, nt_errstr(status)));
+ goto done;
+ }
+
+ log->rec_index += 1;
+
+done:
+ log->num_recs = 0;
+ TALLOC_FREE(log->recs);
+}
+
+struct notifyd_broadcast_reclog_state {
+ struct tevent_context *ev;
+ struct ctdbd_connection *ctdbd_conn;
+ struct server_id src;
+ struct messaging_reclog *log;
+};
+
+static void notifyd_broadcast_reclog_next(struct tevent_req *subreq);
+
+static struct tevent_req *notifyd_broadcast_reclog_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct ctdbd_connection *ctdbd_conn, struct server_id src,
+ struct messaging_reclog *log)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_broadcast_reclog_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct notifyd_broadcast_reclog_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->ctdbd_conn = ctdbd_conn;
+ state->src = src;
+ state->log = log;
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ timeval_current_ofs_msec(1000));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_broadcast_reclog_next, req);
+ return req;
+}
+
+static void notifyd_broadcast_reclog_next(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_broadcast_reclog_state *state = tevent_req_data(
+ req, struct notifyd_broadcast_reclog_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+
+ notifyd_broadcast_reclog(state->ctdbd_conn, state->src, state->log);
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ timeval_current_ofs_msec(1000));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, notifyd_broadcast_reclog_next, req);
+}
+
+static int notifyd_broadcast_reclog_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+struct notifyd_clean_peers_state {
+ struct tevent_context *ev;
+ struct notifyd_state *notifyd;
+};
+
+static void notifyd_clean_peers_next(struct tevent_req *subreq);
+
+static struct tevent_req *notifyd_clean_peers_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct notifyd_state *notifyd)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_clean_peers_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct notifyd_clean_peers_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->notifyd = notifyd;
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ timeval_current_ofs_msec(30000));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_clean_peers_next, req);
+ return req;
+}
+
+static void notifyd_clean_peers_next(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_clean_peers_state *state = tevent_req_data(
+ req, struct notifyd_clean_peers_state);
+ struct notifyd_state *notifyd = state->notifyd;
+ size_t i;
+ bool ok;
+ time_t now = time(NULL);
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+
+ i = 0;
+ while (i < notifyd->num_peers) {
+ struct notifyd_peer *p = notifyd->peers[i];
+
+ if ((now - p->last_broadcast) > 60) {
+ struct server_id_buf idbuf;
+
+ /*
+ * Haven't heard for more than 60 seconds. Call this peer dead
+ */
+
+ DEBUG(10, ("%s: peer %s died\n", __func__,
+ server_id_str_buf(p->pid, &idbuf)));
+ /*
+ * This implicitly decrements notifyd->num_peers
+ */
+ TALLOC_FREE(p);
+ } else {
+ i += 1;
+ }
+ }
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ timeval_current_ofs_msec(30000));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, notifyd_clean_peers_next, req);
+}
+
+static int notifyd_clean_peers_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+static int notifyd_add_proxy_syswatches(struct db_record *rec,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct db_context *db = dbwrap_record_get_db(rec);
+ TDB_DATA key = dbwrap_record_get_key(rec);
+ TDB_DATA value = dbwrap_record_get_value(rec);
+ struct notifyd_instance *instances = NULL;
+ size_t num_instances = 0;
+ size_t i;
+ char path[key.dsize+1];
+ bool ok;
+
+ memcpy(path, key.dptr, key.dsize);
+ path[key.dsize] = '\0';
+
+ ok = notifyd_parse_entry(value.dptr, value.dsize, &instances,
+ &num_instances);
+ if (!ok) {
+ DEBUG(1, ("%s: Could not parse notifyd entry for %s\n",
+ __func__, path));
+ return 0;
+ }
+
+ for (i=0; i<num_instances; i++) {
+ struct notifyd_instance *instance = &instances[i];
+ uint32_t filter = instance->instance.filter;
+ uint32_t subdir_filter = instance->instance.subdir_filter;
+ int ret;
+
+ ret = state->sys_notify_watch(
+ db, state->sys_notify_ctx, path,
+ &filter, &subdir_filter,
+ notifyd_sys_callback, state->msg_ctx,
+ &instance->sys_watch);
+ if (ret != 0) {
+ DEBUG(1, ("%s: inotify_watch returned %s\n",
+ __func__, strerror(errno)));
+ }
+ }
+
+ return 0;
+}
+
+static int notifyd_db_del_syswatches(struct db_record *rec, void *private_data)
+{
+ TDB_DATA key = dbwrap_record_get_key(rec);
+ TDB_DATA value = dbwrap_record_get_value(rec);
+ struct notifyd_instance *instances = NULL;
+ size_t num_instances = 0;
+ size_t i;
+ bool ok;
+
+ ok = notifyd_parse_entry(value.dptr, value.dsize, &instances,
+ &num_instances);
+ if (!ok) {
+ DEBUG(1, ("%s: Could not parse notifyd entry for %.*s\n",
+ __func__, (int)key.dsize, (char *)key.dptr));
+ return 0;
+ }
+ for (i=0; i<num_instances; i++) {
+ TALLOC_FREE(instances[i].sys_watch);
+ }
+ return 0;
+}
+
+static int notifyd_peer_destructor(struct notifyd_peer *p)
+{
+ struct notifyd_state *state = p->state;
+ size_t i;
+
+ dbwrap_traverse_read(p->db, notifyd_db_del_syswatches, NULL, NULL);
+
+ for (i = 0; i<state->num_peers; i++) {
+ if (p == state->peers[i]) {
+ state->peers[i] = state->peers[state->num_peers-1];
+ state->num_peers -= 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+static struct notifyd_peer *notifyd_peer_new(
+ struct notifyd_state *state, struct server_id pid)
+{
+ struct notifyd_peer *p, **tmp;
+
+ tmp = talloc_realloc(state, state->peers, struct notifyd_peer *,
+ state->num_peers+1);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ state->peers = tmp;
+
+ p = talloc_zero(state->peers, struct notifyd_peer);
+ if (p == NULL) {
+ return NULL;
+ }
+ p->state = state;
+ p->pid = pid;
+
+ state->peers[state->num_peers] = p;
+ state->num_peers += 1;
+
+ talloc_set_destructor(p, notifyd_peer_destructor);
+
+ return p;
+}
+
+static void notifyd_apply_reclog(struct notifyd_peer *peer,
+ const uint8_t *msg, size_t msglen)
+{
+ struct notifyd_state *state = peer->state;
+ DATA_BLOB blob = { .data = discard_const_p(uint8_t, msg),
+ .length = msglen };
+ struct server_id_buf idbuf;
+ struct messaging_reclog *log;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+
+ if (peer->db == NULL) {
+ /*
+ * No db yet
+ */
+ return;
+ }
+
+ log = talloc(peer, struct messaging_reclog);
+ if (log == NULL) {
+ DEBUG(10, ("%s: talloc failed\n", __func__));
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &blob, log, log,
+ (ndr_pull_flags_fn_t)ndr_pull_messaging_reclog);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(10, ("%s: ndr_pull_messaging_reclog failed: %s\n",
+ __func__, ndr_errstr(ndr_err)));
+ goto fail;
+ }
+
+ DEBUG(10, ("%s: Got %u recs index %ju from %s\n", __func__,
+ (unsigned)log->num_recs, (uintmax_t)log->rec_index,
+ server_id_str_buf(peer->pid, &idbuf)));
+
+ if (log->rec_index != peer->rec_index) {
+ DEBUG(3, ("%s: Got rec index %ju from %s, expected %ju\n",
+ __func__, (uintmax_t)log->rec_index,
+ server_id_str_buf(peer->pid, &idbuf),
+ (uintmax_t)peer->rec_index));
+ goto fail;
+ }
+
+ for (i=0; i<log->num_recs; i++) {
+ struct messaging_rec *r = log->recs[i];
+ struct notify_rec_change_msg *chg;
+ size_t pathlen;
+ bool ok;
+
+ ok = notifyd_parse_rec_change(r->buf.data, r->buf.length,
+ &chg, &pathlen);
+ if (!ok) {
+ DEBUG(3, ("%s: notifyd_parse_rec_change failed\n",
+ __func__));
+ goto fail;
+ }
+
+ ok = notifyd_apply_rec_change(&r->src, chg->path, pathlen,
+ &chg->instance, peer->db,
+ state->sys_notify_watch,
+ state->sys_notify_ctx,
+ state->msg_ctx);
+ if (!ok) {
+ DEBUG(3, ("%s: notifyd_apply_rec_change failed\n",
+ __func__));
+ goto fail;
+ }
+ }
+
+ peer->rec_index += 1;
+
+ TALLOC_FREE(log);
+ return;
+
+fail:
+ DEBUG(10, ("%s: Dropping peer %s\n", __func__,
+ server_id_str_buf(peer->pid, &idbuf)));
+ TALLOC_FREE(peer);
+}
+
+/*
+ * Receive messaging_reclog (log of MSG_SMB_NOTIFY_REC_CHANGE
+ * messages) broadcasts by other notifyds. Several cases:
+ *
+ * We don't know the source. This creates a new peer. Creating a peer
+ * involves asking the peer for its full database. We assume ordered
+ * messages, so the new database will arrive before the next broadcast
+ * will.
+ *
+ * We know the source and the log index matches. We will apply the log
+ * locally to our peer's db as if we had received it from a local
+ * client.
+ *
+ * We know the source but the log index does not match. This means we
+ * lost a message. We just drop the whole peer and wait for the next
+ * broadcast, which will then trigger a fresh database pull.
+ */
+
+static void notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
+ uint64_t dst_srvid,
+ const uint8_t *msg, size_t msglen,
+ void *private_data)
+{
+ struct notifyd_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_state);
+ struct server_id my_id = messaging_server_id(state->msg_ctx);
+ struct notifyd_peer *p;
+ uint32_t i;
+ uint32_t msg_type;
+ struct server_id src, dst;
+ struct server_id_buf idbuf;
+ NTSTATUS status;
+
+ if (msglen < MESSAGE_HDR_LENGTH) {
+ DEBUG(10, ("%s: Got short broadcast\n", __func__));
+ return;
+ }
+ message_hdr_get(&msg_type, &src, &dst, msg);
+
+ if (msg_type != MSG_SMB_NOTIFY_REC_CHANGES) {
+ DEBUG(10, ("%s Got message %u, ignoring\n", __func__,
+ (unsigned)msg_type));
+ return;
+ }
+ if (server_id_equal(&src, &my_id)) {
+ DEBUG(10, ("%s: Ignoring my own broadcast\n", __func__));
+ return;
+ }
+
+ DEBUG(10, ("%s: Got MSG_SMB_NOTIFY_REC_CHANGES from %s\n",
+ __func__, server_id_str_buf(src, &idbuf)));
+
+ for (i=0; i<state->num_peers; i++) {
+ if (server_id_equal(&state->peers[i]->pid, &src)) {
+
+ DEBUG(10, ("%s: Applying changes to peer %u\n",
+ __func__, (unsigned)i));
+
+ notifyd_apply_reclog(state->peers[i],
+ msg + MESSAGE_HDR_LENGTH,
+ msglen - MESSAGE_HDR_LENGTH);
+
+ state->peers[i]->last_broadcast = time(NULL);
+ return;
+ }
+ }
+
+ DEBUG(10, ("%s: Creating new peer for %s\n", __func__,
+ server_id_str_buf(src, &idbuf)));
+
+ p = notifyd_peer_new(state, src);
+ if (p == NULL) {
+ DEBUG(10, ("%s: notifyd_peer_new failed\n", __func__));
+ return;
+ }
+
+ status = messaging_send_buf(state->msg_ctx, src, MSG_SMB_NOTIFY_GET_DB,
+ NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("%s: messaging_send_buf failed: %s\n",
+ __func__, nt_errstr(status)));
+ TALLOC_FREE(p);
+ return;
+ }
+}
diff --git a/source3/smbd/notifyd/notifyd.h b/source3/smbd/notifyd/notifyd.h
new file mode 100644
index 0000000..dc0a4e8
--- /dev/null
+++ b/source3/smbd/notifyd/notifyd.h
@@ -0,0 +1,143 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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/>.
+ */
+
+#ifndef __NOTIFYD_NOTIFYD_H__
+#define __NOTIFYD_NOTIFYD_H__
+
+#include "includes.h"
+#include "librpc/gen_ndr/notify.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "messages.h"
+#include "tdb.h"
+#include "util_tdb.h"
+
+/*
+ * Filechangenotify based on asynchronous messages
+ *
+ * smbds talk to local notify daemons to inform them about paths they are
+ * interested in. They also tell local notify daemons about changes they have
+ * done to the file system. There's two message types from smbd to
+ * notifyd. The first is used to inform notifyd about changes in notify
+ * interest. These are only sent from smbd to notifyd if the SMB client issues
+ * FileChangeNotify requests.
+ */
+
+/*
+ * The notifyd implementation is designed to cope with multiple daemons taking
+ * care of just a subset of smbds. The goal is to minimize the traffic between
+ * the notify daemons. The idea behind this is a samba/ctdb cluster, but it
+ * could also be used to spread the load of notifyd instances on a single
+ * node, should this become a bottleneck. The following diagram illustrates
+ * the setup. The numbers in the boxes are node:process ids.
+ *
+ * +-----------+ +-----------+
+ * |notifyd 0:5|------------------|notifyd 1:6|
+ * +-----------+ +-----------+
+ * / | \ / \
+ * / | \ / \
+ * +--------+ | +--------+ +--------+ +--------+
+ * |smbd 0:1| | |smbd 0:4| |smbd 1:7| |smbd 1:2|
+ * +--------+ | +--------+ +--------+ +--------+
+ * |
+ * +---------+
+ * |smbd 0:20|
+ * +---------+
+ *
+ * Suppose 0:1 and 0:4 are interested in changes for /foo and 0:20 creates the
+ * file /foo/bar, if everything fully connected, 0:20 would have to send two
+ * local messages, one to 0:1 and one to 0:4. With the notifyd design, 0:20
+ * only has to send one message, it lets notifyd 0:5 do the hard work to
+ * multicast the change to 0:1 and 0:4.
+ *
+ * Now lets assume 1:7 on the other node creates /foo/baz. It tells its
+ * notifyd 1:6 about this change. All 1:6 will know about is that its peer
+ * notifyd 0:5 is interested in the change. Thus it forwards the event to 0:5,
+ * which sees it as if it came from just another local event creator. 0:5 will
+ * multicast the change to 0:1 and 0:4. To prevent notify loops, the message
+ * from 1:6 to 0:5 will carry a "proxied" flag, so that 0:5 will only forward
+ * the event to local clients.
+ */
+
+/*
+ * Data that notifyd maintains per smbd notify instance
+ */
+struct notify_instance {
+ struct timespec creation_time;
+ uint32_t filter;
+ uint32_t subdir_filter;
+ void *private_data;
+};
+
+/* MSG_SMB_NOTIFY_REC_CHANGE payload */
+struct notify_rec_change_msg {
+ struct notify_instance instance;
+ char path[];
+};
+
+/*
+ * The second message from smbd to notifyd is sent whenever an smbd makes a
+ * file system change. It tells notifyd to inform all interested parties about
+ * that change. This is the message that needs to be really fast in smbd
+ * because it is called a lot.
+ */
+
+/* MSG_SMB_NOTIFY_TRIGGER payload */
+struct notify_trigger_msg {
+ struct timespec when;
+ uint32_t action;
+ uint32_t filter;
+ char path[];
+};
+
+/*
+ * In response to a MSG_SMB_NOTIFY_TRIGGER message notifyd walks its database
+ * and sends out the following message to all interested clients
+ */
+
+/* MSG_PVFS_NOTIFY payload */
+struct notify_event_msg {
+ struct timespec when;
+ void *private_data;
+ uint32_t action;
+ char path[];
+};
+
+struct sys_notify_context;
+
+typedef int (*sys_notify_watch_fn)(TALLOC_CTX *mem_ctx,
+ struct sys_notify_context *ctx,
+ const char *path,
+ uint32_t *filter,
+ uint32_t *subdir_filter,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p);
+
+struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ struct ctdbd_connection *ctdbd_conn,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx);
+int notifyd_recv(struct tevent_req *req);
+
+#endif
diff --git a/source3/smbd/notifyd/tests.c b/source3/smbd/notifyd/tests.c
new file mode 100644
index 0000000..6bcce6a
--- /dev/null
+++ b/source3/smbd/notifyd/tests.c
@@ -0,0 +1,118 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "replace.h"
+#include "notifyd.h"
+#include "messages.h"
+#include "lib/util/server_id_db.h"
+
+int main(int argc, const char *argv[])
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct messaging_context *msg_ctx;
+ struct server_id_db *names;
+ struct server_id notifyd;
+ struct tevent_req *req;
+ unsigned i;
+ bool ok;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <smb.conf-file>\n", argv[0]);
+ exit(1);
+ }
+
+ setup_logging(argv[0], DEBUG_STDOUT);
+ lp_load_global(argv[1]);
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ fprintf(stderr, "tevent_context_init failed\n");
+ exit(1);
+ }
+
+ msg_ctx = messaging_init(ev, ev);
+ if (msg_ctx == NULL) {
+ fprintf(stderr, "messaging_init failed\n");
+ exit(1);
+ }
+
+ names = messaging_names_db(msg_ctx);
+
+ ok = server_id_db_lookup_one(names, "notify-daemon", ¬ifyd);
+ if (!ok) {
+ fprintf(stderr, "no notifyd\n");
+ exit(1);
+ }
+
+ for (i=0; i<50000; i++) {
+ struct notify_rec_change_msg msg = {
+ .instance.filter = UINT32_MAX,
+ .instance.subdir_filter = UINT32_MAX
+ };
+ char path[64];
+ size_t len;
+ struct iovec iov[2];
+ NTSTATUS status;
+
+ len = snprintf(path, sizeof(path), "/tmp%u", i);
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
+ iov[1].iov_base = path;
+ iov[1].iov_len = len+1;
+
+ status = messaging_send_iov(
+ msg_ctx, notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr, "messaging_send_iov returned %s\n",
+ nt_errstr(status));
+ exit(1);
+ }
+
+ msg.instance.filter = 0;
+ msg.instance.subdir_filter = 0;
+
+ status = messaging_send_iov(
+ msg_ctx, notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr, "messaging_send_iov returned %s\n",
+ nt_errstr(status));
+ exit(1);
+ }
+ }
+
+ req = messaging_read_send(ev, ev, msg_ctx, MSG_PONG);
+ if (req == NULL) {
+ fprintf(stderr, "messaging_read_send failed\n");
+ exit(1);
+ }
+ messaging_send_buf(msg_ctx, notifyd, MSG_PING, NULL, 0);
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ fprintf(stderr, "tevent_req_poll failed\n");
+ exit(1);
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/smbd/notifyd/wscript_build b/source3/smbd/notifyd/wscript_build
new file mode 100644
index 0000000..90a9505
--- /dev/null
+++ b/source3/smbd/notifyd/wscript_build
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_SUBSYSTEM('notifyd',
+ source='notifyd.c',
+ deps='util_tdb TDB_LIB messages_util')
+
+bld.SAMBA3_BINARY('notifyd-tests',
+ source='tests.c',
+ install=False,
+ deps='''
+ param
+ ''')
diff --git a/source3/wscript_build b/source3/wscript_build
index 60d1ea6..c02794c 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1526,6 +1526,7 @@ bld.RECURSE('../examples/pdb')
bld.RECURSE('../examples/VFS')
bld.RECURSE('lib/netapi/tests')
bld.RECURSE('lib/netapi/examples')
+bld.RECURSE('smbd/notifyd')
bld.ENFORCE_GROUP_ORDERING()
bld.CHECK_PROJECT_RULES()
--
1.7.9.5
From 45353944ada1882c590bdaab545ca08624c1416d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 16:55:25 +0100
Subject: [PATCH 09/20] smbd: Start the notify daemon
For this we need the kernel change notify stuff to be global: There's only one
notifyd and we have to pass over the kernel change notify watch function
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/server.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
source3/wscript_build | 1 +
2 files changed, 96 insertions(+)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 20aed16..312dde6 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -49,6 +49,7 @@
#include "scavenger.h"
#include "locking/leases_db.h"
#include "../../ctdb/include/ctdb_protocol.h"
+#include "smbd/notifyd/notifyd.h"
struct smbd_open_socket;
struct smbd_child_pid;
@@ -404,6 +405,97 @@ static void smb_tell_num_children(struct messaging_context *ctx, void *data,
}
}
+static void notifyd_stopped(struct tevent_req *req);
+
+static struct tevent_req *notifyd_req(struct messaging_context *msg_ctx,
+ struct tevent_context *ev)
+{
+ struct tevent_req *req;
+ sys_notify_watch_fn sys_notify_watch = NULL;
+ struct sys_notify_context *sys_notify_ctx = NULL;
+
+ if (lp_kernel_change_notify()) {
+
+#ifdef HAVE_INOTIFY
+ if (lp_parm_bool(-1, "notify", "inotify", true)) {
+ sys_notify_watch = inotify_watch;
+ }
+#endif
+
+#ifdef HAVE_FAM
+ if (lp_parm_bool(-1, "notify", "fam",
+ (sys_notify_watch == NULL))) {
+ sys_notify_watch = fam_watch;
+ }
+#endif
+ }
+
+ if (sys_notify_watch != NULL) {
+ sys_notify_ctx = sys_notify_context_create(msg_ctx, ev);
+ if (sys_notify_ctx == NULL) {
+ return NULL;
+ }
+ }
+
+ req = notifyd_send(msg_ctx, ev, msg_ctx,
+ messaging_ctdbd_connection(),
+ sys_notify_watch, sys_notify_ctx);
+ if (req == NULL) {
+ TALLOC_FREE(sys_notify_ctx);
+ return NULL;
+ }
+ tevent_req_set_callback(req, notifyd_stopped, msg_ctx);
+
+ return req;
+}
+
+static void notifyd_stopped(struct tevent_req *req)
+{
+ int ret;
+
+ ret = notifyd_recv(req);
+ TALLOC_FREE(req);
+ DEBUG(1, ("notifyd stopped: %s\n", strerror(ret)));
+}
+
+static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive)
+{
+ struct tevent_context *ev = messaging_tevent_context(msg);
+ struct tevent_req *req;
+ pid_t pid;
+ NTSTATUS status;
+
+ if (interactive) {
+ req = notifyd_req(msg, ev);
+ return (req != NULL);
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ DEBUG(1, ("%s: fork failed: %s\n", __func__,
+ strerror(errno)));
+ return false;
+ }
+
+ if (pid != 0) {
+ return true;
+ }
+
+ status = reinit_after_fork(msg, ev, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: reinit_after_fork failed: %s\n",
+ __func__, nt_errstr(status)));
+ exit(1);
+ }
+
+ req = notifyd_req(msg, ev);
+ if (req == NULL) {
+ exit(1);
+ }
+ tevent_req_set_callback(req, notifyd_stopped, msg);
+ tevent_req_poll(req, ev);
+ return true;
+}
/*
at most every smbd:cleanuptime seconds (default 20), we scan the BRL
@@ -1485,6 +1577,9 @@ extern void build_options(bool screen);
if (!smbd_parent_notify_init(NULL, msg_ctx, ev_ctx)) {
exit_daemon("Samba cannot init notification", EACCES);
}
+ if (!smbd_notifyd_init(msg_ctx, interactive)) {
+ exit_daemon("Samba cannot init notification", EACCES);
+ }
if (!messaging_parent_dgm_cleanup_init(msg_ctx)) {
exit(1);
diff --git a/source3/wscript_build b/source3/wscript_build
index c02794c..a9fe6e4 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -638,6 +638,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
NDR_SMB_ACL
netapi
NDR_IOCTL
+ notifyd
''' + bld.env['dmapi_lib']
+ (bld.CONFIG_GET('SAMBA_FAM_LIBS')
if bld.CONFIG_SET('SAMBA_FAM_LIBS') else ''),
--
1.7.9.5
From ab3b014a3fb40487309500667de37371224cd34e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 16:58:47 +0100
Subject: [PATCH 10/20] smbd: Don't start the notify cleanup anymore
We don't have a database to clean up anymore
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/server.c | 100 -------------------------------------------------
1 file changed, 100 deletions(-)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 312dde6..71ea8eb 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -280,103 +280,6 @@ static void smbd_parent_ctdb_reconfigured(
MSG_SMB_BRL_VALIDATE, NULL, 0);
}
-struct smbd_parent_notify_state {
- struct tevent_context *ev;
- struct messaging_context *msg;
- uint32_t msgtype;
- struct notify_context *notify;
-};
-
-static int smbd_parent_notify_cleanup(void *private_data);
-static void smbd_parent_notify_cleanup_done(struct tevent_req *req);
-static void smbd_parent_notify_proxy_done(struct tevent_req *req);
-
-static bool smbd_parent_notify_init(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg,
- struct tevent_context *ev)
-{
- struct smbd_parent_notify_state *state;
- struct tevent_req *req;
-
- state = talloc(mem_ctx, struct smbd_parent_notify_state);
- if (state == NULL) {
- return false;
- }
- state->msg = msg;
- state->ev = ev;
- state->msgtype = MSG_SMB_NOTIFY_CLEANUP;
-
- state->notify = notify_init(state, msg, ev);
- if (state->notify == NULL) {
- goto fail;
- }
- req = background_job_send(
- state, state->ev, state->msg, &state->msgtype, 1,
- lp_parm_int(-1, "smbd", "notify cleanup interval", 60),
- smbd_parent_notify_cleanup, state->notify);
- if (req == NULL) {
- goto fail;
- }
- tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
-
- if (!lp_clustering()) {
- return true;
- }
-
- req = notify_cluster_proxy_send(state, ev, state->notify);
- if (req == NULL) {
- goto fail;
- }
- tevent_req_set_callback(req, smbd_parent_notify_proxy_done, state);
-
- return true;
-fail:
- TALLOC_FREE(state);
- return false;
-}
-
-static int smbd_parent_notify_cleanup(void *private_data)
-{
- struct notify_context *notify = talloc_get_type_abort(
- private_data, struct notify_context);
- notify_cleanup(notify);
- return lp_parm_int(-1, "smbd", "notify cleanup interval", 60);
-}
-
-static void smbd_parent_notify_cleanup_done(struct tevent_req *req)
-{
- struct smbd_parent_notify_state *state = tevent_req_callback_data(
- req, struct smbd_parent_notify_state);
- NTSTATUS status;
-
- status = background_job_recv(req);
- TALLOC_FREE(req);
- DEBUG(1, ("notify cleanup job ended with %s\n", nt_errstr(status)));
-
- /*
- * Provide self-healing: Whatever the error condition was, it
- * will have printed it into log.smbd. Just retrying and
- * spamming log.smbd once a minute should be fine.
- */
- req = background_job_send(
- state, state->ev, state->msg, &state->msgtype, 1, 60,
- smbd_parent_notify_cleanup, state->notify);
- if (req == NULL) {
- DEBUG(1, ("background_job_send failed\n"));
- return;
- }
- tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
-}
-
-static void smbd_parent_notify_proxy_done(struct tevent_req *req)
-{
- int ret;
-
- ret = notify_cluster_proxy_recv(req);
- TALLOC_FREE(req);
- DEBUG(1, ("notify proxy job ended with %s\n", strerror(ret)));
-}
-
static void add_child_pid(struct smbd_parent_context *parent,
pid_t pid)
{
@@ -1574,9 +1477,6 @@ extern void build_options(bool screen);
exit_daemon("Samba cannot init leases", EACCES);
}
- if (!smbd_parent_notify_init(NULL, msg_ctx, ev_ctx)) {
- exit_daemon("Samba cannot init notification", EACCES);
- }
if (!smbd_notifyd_init(msg_ctx, interactive)) {
exit_daemon("Samba cannot init notification", EACCES);
}
--
1.7.9.5
From 74326492fc65d7f70eb868dfb79d4847ce897a15 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 17:05:16 +0100
Subject: [PATCH 11/20] smbd: Replace the tdb-based notify_internal with
notify_msg
For the moment, this removes smbstatus -N output. It will come back with
the next commits.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notify_internal.c | 1278 ----------------------------------------
source3/smbd/notify_msg.c | 268 +++++++++
source3/smbd/proto.h | 5 -
source3/wscript_build | 4 +-
4 files changed, 270 insertions(+), 1285 deletions(-)
delete mode 100644 source3/smbd/notify_internal.c
create mode 100644 source3/smbd/notify_msg.c
diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c
deleted file mode 100644
index dc50d4f..0000000
--- a/source3/smbd/notify_internal.c
+++ /dev/null
@@ -1,1278 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Copyright (C) Andrew Tridgell 2006
- Copyright (C) Volker Lendecke 2012
-
- 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/>.
-*/
-
-/*
- this is the change notify database. It implements mechanisms for
- storing current change notify waiters in a tdb, and checking if a
- given event matches any of the stored notify waiters.
-*/
-
-#include "includes.h"
-#include "system/filesys.h"
-#include "librpc/gen_ndr/ndr_notify.h"
-#include "dbwrap/dbwrap.h"
-#include "dbwrap/dbwrap_open.h"
-#include "dbwrap/dbwrap_tdb.h"
-#include "smbd/smbd.h"
-#include "messages.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
-#include "util_tdb.h"
-#include "lib/param/param.h"
-#include "lib/dbwrap/dbwrap_cache.h"
-#include "ctdb_srvids.h"
-#include "ctdbd_conn.h"
-#include "ctdb_conn.h"
-#include "lib/util/tevent_unix.h"
-
-struct notify_list {
- struct notify_list *next, *prev;
- const char *path;
- void (*callback)(void *, struct timespec, const struct notify_event *);
- void *private_data;
-};
-
-struct notify_context {
- struct messaging_context *msg;
- struct notify_list *list;
-
- /*
- * The notify database is split up into two databases: One
- * relatively static index db and the real notify db with the
- * volatile entries.
- */
-
- /*
- * "db_notify" is indexed by pathname. Per record it stores an
- * array of notify_db_entry structs. These represent the
- * notify records as requested by the smb client. This
- * database is always held locally, it is never clustered.
- */
- struct db_context *db_notify;
-
- /*
- * "db_index" is indexed by pathname. The records are an array
- * of VNNs which have any interest in notifies for this path
- * name.
- *
- * In the non-clustered case this database is cached in RAM by
- * means of db_cache_open, which maintains a cache per
- * process. Cache consistency is maintained by the tdb
- * sequence number.
- *
- * In the clustered case right now we can not use the tdb
- * sequence number, but by means of read only records we
- * should be able to avoid a lot of full migrations.
- *
- * In both cases, it is important to keep the update
- * operations to db_index to a minimum. This is achieved by
- * delayed deletion. When a db_notify is initially created,
- * the db_index record is also created. When more notifies are
- * added for a path, then only the db_notify record needs to be
- * modified, the db_index record is not touched. When the last
- * entry from the db_notify record is deleted, the db_index
- * record is not immediately deleted. Instead, the db_notify
- * record is replaced with a current timestamp. A regular
- * cleanup process will delete all db_index records that are
- * older than a minute.
- */
- struct db_context *db_index;
-};
-
-static void notify_trigger_local(struct notify_context *notify,
- uint32_t action, uint32_t filter,
- const char *path, size_t path_len,
- bool recursive);
-static NTSTATUS notify_send(struct notify_context *notify,
- struct server_id *pid,
- const char *path, uint32_t action,
- void *private_data);
-static NTSTATUS notify_add_entry(struct db_record *rec,
- const struct notify_db_entry *e,
- bool *p_add_idx);
-static NTSTATUS notify_add_idx(struct db_record *rec, uint32_t vnn);
-
-static NTSTATUS notify_del_entry(struct db_record *rec,
- const struct server_id *pid,
- void *private_data);
-static NTSTATUS notify_del_idx(struct db_record *rec, uint32_t vnn);
-
-static int notify_context_destructor(struct notify_context *notify);
-
-static void notify_handler(struct messaging_context *msg_ctx,
- void *private_data, uint32_t msg_type,
- struct server_id server_id, DATA_BLOB *data);
-
-struct notify_context *notify_init(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg,
- struct tevent_context *ev)
-{
- struct loadparm_context *lp_ctx;
- struct notify_context *notify;
- char *db_path;
-
- notify = talloc(mem_ctx, struct notify_context);
- if (notify == NULL) {
- goto fail;
- }
- notify->msg = msg;
- notify->list = NULL;
-
- lp_ctx = loadparm_init_s3(notify, loadparm_s3_helpers());
-
- db_path = lock_path("notify.tdb");
- if (db_path == NULL) {
- goto fail;
- }
-
- notify->db_notify = db_open_tdb(
- notify, lp_ctx, db_path,
- 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
- O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
- talloc_unlink(notify, lp_ctx);
- TALLOC_FREE(db_path);
- if (notify->db_notify == NULL) {
- goto fail;
- }
-
- db_path = lock_path("notify_index.tdb");
- if (db_path == NULL) {
- goto fail;
- }
-
- notify->db_index = db_open(
- notify, db_path,
- 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
- O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_3, DBWRAP_FLAG_NONE);
- TALLOC_FREE(db_path);
- if (notify->db_index == NULL) {
- goto fail;
- }
- if (!lp_clustering()) {
- notify->db_index = db_open_cache(notify, notify->db_index);
- if (notify->db_index == NULL) {
- goto fail;
- }
- }
-
- if (notify->msg != NULL) {
- NTSTATUS status;
-
- status = messaging_register(notify->msg, notify,
- MSG_PVFS_NOTIFY, notify_handler);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("messaging_register returned %s\n",
- nt_errstr(status)));
- goto fail;
- }
- }
-
- talloc_set_destructor(notify, notify_context_destructor);
-
- return notify;
-fail:
- TALLOC_FREE(notify);
- return NULL;
-}
-
-static int notify_context_destructor(struct notify_context *notify)
-{
- DEBUG(10, ("notify_context_destructor called\n"));
-
- if (notify->msg != NULL) {
- messaging_deregister(notify->msg, MSG_PVFS_NOTIFY, notify);
- }
-
- while (notify->list != NULL) {
- DEBUG(10, ("Removing private_data=%p\n",
- notify->list->private_data));
- notify_remove(notify, notify->list->private_data);
- }
- return 0;
-}
-
-NTSTATUS notify_add(struct notify_context *notify,
- const char *path, uint32_t filter, uint32_t subdir_filter,
- void (*callback)(void *, struct timespec,
- const struct notify_event *),
- void *private_data)
-{
- struct notify_db_entry e;
- struct notify_list *listel;
- struct db_record *notify_rec, *idx_rec;
- bool add_idx;
- NTSTATUS status;
- TDB_DATA key, notify_copy;
-
- if (notify == NULL) {
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
- DEBUG(10, ("notify_add: path=[%s], private_data=%p\n", path,
- private_data));
-
- listel = talloc(notify, struct notify_list);
- if (listel == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- listel->callback = callback;
- listel->private_data = private_data;
- listel->path = talloc_strdup(listel, path);
- if (listel->path == NULL) {
- TALLOC_FREE(listel);
- return NT_STATUS_NO_MEMORY;
- }
- DLIST_ADD(notify->list, listel);
-
- ZERO_STRUCT(e);
- e.filter = filter;
- e.subdir_filter = subdir_filter;
- e.server = messaging_server_id(notify->msg);
- e.private_data = private_data;
-
- key = string_tdb_data(path);
-
- notify_rec = dbwrap_fetch_locked(notify->db_notify,
- talloc_tos(), key);
- if (notify_rec == NULL) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto fail;
- }
-
- /*
- * Make a copy of the notify_rec for easy restore in case
- * updating the index_rec fails;
- */
- notify_copy = dbwrap_record_get_value(notify_rec);
- if (notify_copy.dsize != 0) {
- notify_copy.dptr = (uint8_t *)talloc_memdup(
- notify_rec, notify_copy.dptr,
- notify_copy.dsize);
- if (notify_copy.dptr == NULL) {
- TALLOC_FREE(notify_rec);
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- }
-
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(notify_db_entry, &e);
- }
-
- status = notify_add_entry(notify_rec, &e, &add_idx);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- if (!add_idx) {
- /*
- * Someone else has added the idx entry already
- */
- TALLOC_FREE(notify_rec);
- return NT_STATUS_OK;
- }
-
- idx_rec = dbwrap_fetch_locked(notify->db_index,
- talloc_tos(), key);
- if (idx_rec == NULL) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto restore_notify;
- }
- status = notify_add_idx(idx_rec, get_my_vnn());
- if (!NT_STATUS_IS_OK(status)) {
- goto restore_notify;
- }
-
- TALLOC_FREE(idx_rec);
- TALLOC_FREE(notify_rec);
- return NT_STATUS_OK;
-
-restore_notify:
- if (notify_copy.dsize != 0) {
- dbwrap_record_store(notify_rec, notify_copy, 0);
- } else {
- dbwrap_record_delete(notify_rec);
- }
- TALLOC_FREE(notify_rec);
-fail:
- DLIST_REMOVE(notify->list, listel);
- TALLOC_FREE(listel);
- return status;
-}
-
-static NTSTATUS notify_add_entry(struct db_record *rec,
- const struct notify_db_entry *e,
- bool *p_add_idx)
-{
- TDB_DATA value = dbwrap_record_get_value(rec);
- struct notify_db_entry *entries;
- size_t num_entries;
- bool add_idx = true;
- NTSTATUS status;
-
- if (value.dsize == sizeof(time_t)) {
- DEBUG(10, ("Re-using deleted entry\n"));
- value.dsize = 0;
- add_idx = false;
- }
-
- if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
- DEBUG(1, ("Invalid value.dsize = %u\n",
- (unsigned)value.dsize));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
- num_entries = value.dsize / sizeof(struct notify_db_entry);
-
- if (num_entries != 0) {
- add_idx = false;
- }
-
- entries = talloc_array(rec, struct notify_db_entry, num_entries + 1);
- if (entries == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- memcpy(entries, value.dptr, value.dsize);
-
- entries[num_entries] = *e;
- value = make_tdb_data((uint8_t *)entries, talloc_get_size(entries));
- status = dbwrap_record_store(rec, value, 0);
- TALLOC_FREE(entries);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- *p_add_idx = add_idx;
- return NT_STATUS_OK;
-}
-
-static NTSTATUS notify_add_idx(struct db_record *rec, uint32_t vnn)
-{
- TDB_DATA value = dbwrap_record_get_value(rec);
- uint32_t *vnns;
- size_t i, num_vnns;
- NTSTATUS status;
-
- if ((value.dsize % sizeof(uint32_t)) != 0) {
- DEBUG(1, ("Invalid value.dsize = %u\n",
- (unsigned)value.dsize));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
- num_vnns = value.dsize / sizeof(uint32_t);
- vnns = (uint32_t *)value.dptr;
-
- for (i=0; i<num_vnns; i++) {
- if (vnns[i] == vnn) {
- return NT_STATUS_OK;
- }
- if (vnns[i] > vnn) {
- break;
- }
- }
-
- value.dptr = (uint8_t *)talloc_realloc(
- rec, value.dptr, uint32_t, num_vnns + 1);
- if (value.dptr == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- value.dsize = talloc_get_size(value.dptr);
-
- vnns = (uint32_t *)value.dptr;
-
- memmove(&vnns[i+1], &vnns[i], sizeof(uint32_t) * (num_vnns - i));
- vnns[i] = vnn;
-
- status = dbwrap_record_store(rec, value, 0);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- return NT_STATUS_OK;
-}
-
-NTSTATUS notify_remove(struct notify_context *notify, void *private_data)
-{
- struct server_id pid;
- struct notify_list *listel;
- struct db_record *notify_rec;
- NTSTATUS status;
-
- if ((notify == NULL) || (notify->msg == NULL)) {
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
- DEBUG(10, ("notify_remove: private_data=%p\n", private_data));
-
- pid = messaging_server_id(notify->msg);
-
- for (listel=notify->list;listel;listel=listel->next) {
- if (listel->private_data == private_data) {
- DLIST_REMOVE(notify->list, listel);
- break;
- }
- }
- if (listel == NULL) {
- DEBUG(10, ("%p not found\n", private_data));
- return NT_STATUS_NOT_FOUND;
- }
- notify_rec = dbwrap_fetch_locked(notify->db_notify, talloc_tos(),
- string_tdb_data(listel->path));
- TALLOC_FREE(listel);
- if (notify_rec == NULL) {
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
- status = notify_del_entry(notify_rec, &pid, private_data);
- DEBUG(10, ("del_entry returned %s\n", nt_errstr(status)));
- TALLOC_FREE(notify_rec);
- return status;
-}
-
-static NTSTATUS notify_del_entry(struct db_record *rec,
- const struct server_id *pid,
- void *private_data)
-{
- TDB_DATA value = dbwrap_record_get_value(rec);
- struct server_id_buf tmp;
- struct notify_db_entry *entries;
- size_t i, num_entries;
- time_t now;
-
- DEBUG(10, ("del_entry called for %s %p\n",
- server_id_str_buf(*pid, &tmp), private_data));
-
- if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
- DEBUG(1, ("Invalid value.dsize = %u\n",
- (unsigned)value.dsize));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
- num_entries = value.dsize / sizeof(struct notify_db_entry);
- entries = (struct notify_db_entry *)value.dptr;
-
- for (i=0; i<num_entries; i++) {
- struct notify_db_entry *e = &entries[i];
-
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(notify_db_entry, e);
- }
-
- if (e->private_data != private_data) {
- continue;
- }
- if (serverid_equal(&e->server, pid)) {
- break;
- }
- }
- if (i == num_entries) {
- return NT_STATUS_NOT_FOUND;
- }
- entries[i] = entries[num_entries-1];
- value.dsize -= sizeof(struct notify_db_entry);
-
- if (value.dsize == 0) {
- now = time(NULL);
- value.dptr = (uint8_t *)&now;
- value.dsize = sizeof(now);
- }
- return dbwrap_record_store(rec, value, 0);
-}
-
-struct notify_trigger_index_state {
- TALLOC_CTX *mem_ctx;
- uint32_t *vnns;
- uint32_t my_vnn;
- bool found_my_vnn;
-};
-
-static void notify_trigger_index_parser(TDB_DATA key, TDB_DATA data,
- void *private_data)
-{
- struct notify_trigger_index_state *state =
- (struct notify_trigger_index_state *)private_data;
- uint32_t *new_vnns;
- size_t i, num_vnns, num_new_vnns, num_remote_vnns;
-
- if ((data.dsize % sizeof(uint32_t)) != 0) {
- DEBUG(1, ("Invalid record size in notify index db: %u\n",
- (unsigned)data.dsize));
- return;
- }
- new_vnns = (uint32_t *)data.dptr;
- num_new_vnns = data.dsize / sizeof(uint32_t);
- num_remote_vnns = num_new_vnns;
-
- for (i=0; i<num_new_vnns; i++) {
- if (new_vnns[i] == state->my_vnn) {
- state->found_my_vnn = true;
- num_remote_vnns -= 1;
- }
- }
- if (num_remote_vnns == 0) {
- return;
- }
-
- num_vnns = talloc_array_length(state->vnns);
- state->vnns = talloc_realloc(state->mem_ctx, state->vnns, uint32_t,
- num_vnns + num_remote_vnns);
- if (state->vnns == NULL) {
- DEBUG(1, ("talloc_realloc failed\n"));
- return;
- }
-
- for (i=0; i<num_new_vnns; i++) {
- if (new_vnns[i] != state->my_vnn) {
- state->vnns[num_vnns] = new_vnns[i];
- num_vnns += 1;
- }
- }
-}
-
-static int vnn_cmp(const void *p1, const void *p2)
-{
- const uint32_t *vnn1 = (const uint32_t *)p1;
- const uint32_t *vnn2 = (const uint32_t *)p2;
-
- if (*vnn1 < *vnn2) {
- return -1;
- }
- if (*vnn1 == *vnn2) {
- return 0;
- }
- return 1;
-}
-
-static bool notify_push_remote_blob(TALLOC_CTX *mem_ctx, uint32_t action,
- uint32_t filter, const char *path,
- uint8_t **pblob, size_t *pblob_len)
-{
- struct notify_remote_event ev;
- DATA_BLOB data;
- enum ndr_err_code ndr_err;
-
- ev.action = action;
- ev.filter = filter;
- ev.path = path;
-
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(notify_remote_event, &ev);
- }
-
- ndr_err = ndr_push_struct_blob(
- &data, mem_ctx, &ev,
- (ndr_push_flags_fn_t)ndr_push_notify_remote_event);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return false;
- }
- *pblob = data.data;
- *pblob_len = data.length;
- return true;
-}
-
-static bool notify_pull_remote_blob(TALLOC_CTX *mem_ctx,
- const uint8_t *blob, size_t blob_len,
- uint32_t *paction, uint32_t *pfilter,
- char **path)
-{
- struct notify_remote_event *ev;
- enum ndr_err_code ndr_err;
- DATA_BLOB data;
- char *p;
-
- data.data = discard_const_p(uint8_t, blob);
- data.length = blob_len;
-
- ev = talloc(mem_ctx, struct notify_remote_event);
- if (ev == NULL) {
- return false;
- }
-
- ndr_err = ndr_pull_struct_blob(
- &data, ev, ev,
- (ndr_pull_flags_fn_t)ndr_pull_notify_remote_event);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- TALLOC_FREE(ev);
- return false;
- }
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(notify_remote_event, ev);
- }
- *paction = ev->action;
- *pfilter = ev->filter;
- p = discard_const_p(char, ev->path);
- *path = talloc_move(mem_ctx, &p);
-
- TALLOC_FREE(ev);
- return true;
-}
-
-void notify_trigger(struct notify_context *notify,
- uint32_t action, uint32_t filter,
- const char *dir, const char *name)
-{
- struct ctdbd_connection *ctdbd_conn;
- struct notify_trigger_index_state idx_state;
- const char *p, *next_p;
- size_t i, num_vnns;
- uint32_t last_vnn;
- uint8_t *remote_blob = NULL;
- size_t remote_blob_len = 0;
- struct iovec iov;
- char *path, *to_free;
- char tmpbuf[PATH_MAX];
- ssize_t len;
-
- DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
- "dir=%s, name=%s\n", (unsigned)action, (unsigned)filter,
- dir, name));
-
- /* see if change notify is enabled at all */
- if (notify == NULL) {
- return;
- }
-
- if (dir[0] != '/') {
- /*
- * The rest of this routine assumes an absolute path.
- */
- return;
- }
-
- len = full_path_tos(dir, name, tmpbuf, sizeof(tmpbuf),
- &path, &to_free);
- if (len == -1) {
- DEBUG(1, ("full_path_tos failed\n"));
- return;
- }
-
- idx_state.mem_ctx = talloc_tos();
- idx_state.vnns = NULL;
- idx_state.found_my_vnn = false;
- idx_state.my_vnn = get_my_vnn();
-
- for (p = strchr(path+1, '/'); p != NULL; p = next_p) {
- ptrdiff_t path_len = p - path;
- bool recursive;
-
- next_p = strchr(p+1, '/');
- recursive = (next_p != NULL);
-
- dbwrap_parse_record(
- notify->db_index,
- make_tdb_data(discard_const_p(uint8_t, path), path_len),
- notify_trigger_index_parser, &idx_state);
-
- if (idx_state.found_my_vnn) {
- notify_trigger_local(notify, action, filter,
- path, path_len, recursive);
- idx_state.found_my_vnn = false;
- }
- }
-
- if (idx_state.vnns == NULL) {
- goto done;
- }
-
- ctdbd_conn = messaging_ctdbd_connection();
- if (ctdbd_conn == NULL) {
- goto done;
- }
-
- num_vnns = talloc_array_length(idx_state.vnns);
- qsort(idx_state.vnns, num_vnns, sizeof(uint32_t), vnn_cmp);
-
- last_vnn = 0xffffffff;
-
- if (!notify_push_remote_blob(talloc_tos(), action, filter, path,
- &remote_blob, &remote_blob_len)) {
- DEBUG(1, ("notify_push_remote_blob failed\n"));
- goto done;
- }
-
- iov = (struct iovec) { .iov_base = remote_blob,
- .iov_len = remote_blob_len };
-
- for (i=0; i<num_vnns; i++) {
- uint32_t vnn = idx_state.vnns[i];
- NTSTATUS status;
-
- if (vnn == last_vnn) {
- continue;
- }
-
- status = ctdbd_messaging_send_iov(
- ctdbd_conn, vnn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
- &iov, 1);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("ctdbd_messaging_send_iov to vnn %d "
- "returned %s, ignoring\n", (int)vnn,
- nt_errstr(status)));
- }
-
- last_vnn = vnn;
- }
-
-done:
- TALLOC_FREE(remote_blob);
- TALLOC_FREE(idx_state.vnns);
- TALLOC_FREE(to_free);
-}
-
-static void notify_trigger_local(struct notify_context *notify,
- uint32_t action, uint32_t filter,
- const char *path, size_t path_len,
- bool recursive)
-{
- TDB_DATA data;
- struct notify_db_entry *entries;
- size_t i, num_entries;
- NTSTATUS status;
-
- DEBUG(10, ("notify_trigger_local called for %*s, path_len=%d, "
- "filter=%d\n", (int)path_len, path, (int)path_len,
- (int)filter));
-
- status = dbwrap_fetch(
- notify->db_notify, talloc_tos(),
- make_tdb_data(discard_const_p(uint8_t, path), path_len), &data);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("dbwrap_fetch returned %s\n",
- nt_errstr(status)));
- return;
- }
- if (data.dsize == sizeof(time_t)) {
- DEBUG(10, ("Got deleted record\n"));
- goto done;
- }
- if ((data.dsize % sizeof(struct notify_db_entry)) != 0) {
- DEBUG(1, ("Invalid data.dsize = %u\n",
- (unsigned)data.dsize));
- goto done;
- }
-
- entries = (struct notify_db_entry *)data.dptr;
- num_entries = data.dsize / sizeof(struct notify_db_entry);
-
- DEBUG(10, ("recursive = %s pathlen=%d (%c)\n",
- recursive ? "true" : "false", (int)path_len,
- path[path_len]));
-
- for (i=0; i<num_entries; i++) {
- struct notify_db_entry *e = &entries[i];
- uint32_t e_filter;
-
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(notify_db_entry, e);
- }
-
- e_filter = recursive ? e->subdir_filter : e->filter;
-
- if ((filter & e_filter) == 0) {
- continue;
- }
-
- if (!procid_is_local(&e->server)) {
- struct server_id_buf tmp;
- DEBUG(1, ("internal error: Non-local pid %s in "
- "notify.tdb\n",
- server_id_str_buf(e->server, &tmp)));
- continue;
- }
-
- status = notify_send(notify, &e->server, path + path_len + 1,
- action, e->private_data);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("notify_send returned %s\n",
- nt_errstr(status)));
- }
- }
-
-done:
- TALLOC_FREE(data.dptr);
-}
-
-struct notify_msg {
- struct timespec when;
- void *private_data;
- uint32_t action;
- char path[1];
-};
-
-static NTSTATUS notify_send(struct notify_context *notify,
- struct server_id *pid,
- const char *path, uint32_t action,
- void *private_data)
-{
- struct notify_msg m = {};
- struct iovec iov[2];
-
- m.when = timespec_current();
- m.private_data = private_data;
- m.action = action;
-
- iov[0].iov_base = &m;
- iov[0].iov_len = offsetof(struct notify_msg, path);
- iov[1].iov_base = discard_const_p(char, path);
- iov[1].iov_len = strlen(path)+1;
-
- return messaging_send_iov(notify->msg, *pid, MSG_PVFS_NOTIFY,
- iov, ARRAY_SIZE(iov), NULL, 0);
-}
-
-static void notify_handler(struct messaging_context *msg_ctx,
- void *private_data, uint32_t msg_type,
- struct server_id server_id, DATA_BLOB *data)
-{
- struct notify_context *notify = talloc_get_type_abort(
- private_data, struct notify_context);
- struct notify_msg *m;
- struct notify_event e;
- struct notify_list *listel;
-
- if (data->length == 0) {
- DEBUG(1, ("%s: Got 0-sized MSG_PVFS_NOTIFY msg\n", __func__));
- return;
- }
- if (data->data[data->length-1] != 0) {
- DEBUG(1, ("%s: MSG_PVFS_NOTIFY path not 0-terminated\n",
- __func__));
- return;
- }
-
- m = (struct notify_msg *)data->data;
-
- e = (struct notify_event) {
- .action = m->action,
- .path = m->path,
- .private_data = m->private_data,
- .dir = discard_const_p(char, "")
- };
-
- for (listel=notify->list;listel;listel=listel->next) {
- if (listel->private_data == m->private_data) {
- listel->callback(listel->private_data, m->when, &e);
- break;
- }
- }
-}
-
-struct notify_walk_idx_state {
- void (*fn)(const char *path,
- uint32_t *vnns, size_t num_vnns,
- void *private_data);
- void *private_data;
-};
-
-static int notify_walk_idx_fn(struct db_record *rec, void *private_data)
-{
- struct notify_walk_idx_state *state =
- (struct notify_walk_idx_state *)private_data;
- TDB_DATA key, value;
- char *path;
-
- key = dbwrap_record_get_key(rec);
- value = dbwrap_record_get_value(rec);
-
- if ((value.dsize % sizeof(uint32_t)) != 0) {
- DEBUG(1, ("invalid value size in notify index db: %u\n",
- (unsigned)(value.dsize)));
- return 0;
- }
-
- path = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
- if (path == NULL) {
- DEBUG(1, ("talloc_strndup failed\n"));
- return 0;
- }
- state->fn(path, (uint32_t *)value.dptr, value.dsize/sizeof(uint32_t),
- state->private_data);
- TALLOC_FREE(path);
- return 0;
-}
-
-void notify_walk_idx(struct notify_context *notify,
- void (*fn)(const char *path,
- uint32_t *vnns, size_t num_vnns,
- void *private_data),
- void *private_data)
-{
- struct notify_walk_idx_state state;
- state.fn = fn;
- state.private_data = private_data;
- dbwrap_traverse_read(notify->db_index, notify_walk_idx_fn, &state,
- NULL);
-}
-
-struct notify_walk_state {
- void (*fn)(const char *path,
- struct notify_db_entry *entries, size_t num_entries,
- time_t deleted_time, void *private_data);
- void *private_data;
-};
-
-static int notify_walk_fn(struct db_record *rec, void *private_data)
-{
- struct notify_walk_state *state =
- (struct notify_walk_state *)private_data;
- TDB_DATA key, value;
- struct notify_db_entry *entries;
- size_t num_entries;
- time_t deleted_time;
- char *path;
-
- key = dbwrap_record_get_key(rec);
- value = dbwrap_record_get_value(rec);
-
- if (value.dsize == sizeof(deleted_time)) {
- memcpy(&deleted_time, value.dptr, sizeof(deleted_time));
- entries = NULL;
- num_entries = 0;
- } else {
- if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
- DEBUG(1, ("invalid value size in notify db: %u\n",
- (unsigned)(value.dsize)));
- return 0;
- }
- entries = (struct notify_db_entry *)value.dptr;
- num_entries = value.dsize / sizeof(struct notify_db_entry);
- deleted_time = 0;
- }
-
- path = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
- if (path == NULL) {
- DEBUG(1, ("talloc_strndup failed\n"));
- return 0;
- }
- state->fn(path, entries, num_entries, deleted_time,
- state->private_data);
- TALLOC_FREE(path);
- return 0;
-}
-
-void notify_walk(struct notify_context *notify,
- void (*fn)(const char *path,
- struct notify_db_entry *entries,
- size_t num_entries,
- time_t deleted_time, void *private_data),
- void *private_data)
-{
- struct notify_walk_state state;
- state.fn = fn;
- state.private_data = private_data;
- dbwrap_traverse_read(notify->db_notify, notify_walk_fn, &state,
- NULL);
-}
-
-struct notify_cleanup_state {
- TALLOC_CTX *mem_ctx;
- time_t delete_before;
- ssize_t array_size;
- uint32_t num_paths;
- char **paths;
-};
-
-static void notify_cleanup_collect(
- const char *path, struct notify_db_entry *entries, size_t num_entries,
- time_t deleted_time, void *private_data)
-{
- struct notify_cleanup_state *state =
- (struct notify_cleanup_state *)private_data;
- char *p;
-
- if (num_entries != 0) {
- return;
- }
- if (deleted_time >= state->delete_before) {
- return;
- }
-
- p = talloc_strdup(state->mem_ctx, path);
- if (p == NULL) {
- DEBUG(1, ("talloc_strdup failed\n"));
- return;
- }
- add_to_large_array(state->mem_ctx, sizeof(p), (void *)&p,
- &state->paths, &state->num_paths,
- &state->array_size);
- if (state->array_size == -1) {
- TALLOC_FREE(p);
- }
-}
-
-static bool notify_cleanup_path(struct notify_context *notify,
- const char *path, time_t delete_before);
-
-void notify_cleanup(struct notify_context *notify)
-{
- struct notify_cleanup_state state;
- uint32_t failure_pool;
-
- ZERO_STRUCT(state);
- state.mem_ctx = talloc_stackframe();
-
- state.delete_before = time(NULL)
- - lp_parm_int(-1, "smbd", "notify cleanup interval", 60);
-
- notify_walk(notify, notify_cleanup_collect, &state);
-
- failure_pool = state.num_paths;
-
- while (state.num_paths != 0) {
- size_t idx;
-
- /*
- * This loop is designed to be as kind as possible to
- * ctdb. ctdb does not like it if many smbds hammer on a
- * single record. If on many nodes the cleanup process starts
- * running, it can happen that all of them need to clean up
- * records in the same order. This would generate a ctdb
- * migrate storm on these records. Randomizing the load across
- * multiple records reduces the load on the individual record.
- */
-
- generate_random_buffer((uint8_t *)&idx, sizeof(idx));
- idx = idx % state.num_paths;
-
- if (!notify_cleanup_path(notify, state.paths[idx],
- state.delete_before)) {
- /*
- * notify_cleanup_path failed, the most likely reason
- * is that dbwrap_try_fetch_locked failed due to
- * contention. We allow one failed attempt per deleted
- * path on average before we give up.
- */
- failure_pool -= 1;
- if (failure_pool == 0) {
- /*
- * Too many failures. We will come back here,
- * maybe next time there is less contention.
- */
- break;
- }
- }
-
- TALLOC_FREE(state.paths[idx]);
- state.paths[idx] = state.paths[state.num_paths-1];
- state.num_paths -= 1;
- }
- TALLOC_FREE(state.mem_ctx);
-}
-
-static bool notify_cleanup_path(struct notify_context *notify,
- const char *path, time_t delete_before)
-{
- struct db_record *notify_rec = NULL;
- struct db_record *idx_rec = NULL;
- TDB_DATA key = string_tdb_data(path);
- TDB_DATA value;
- time_t deleted;
- NTSTATUS status;
-
- notify_rec = dbwrap_fetch_locked(notify->db_notify, talloc_tos(), key);
- if (notify_rec == NULL) {
- DEBUG(10, ("Could not fetch notify_rec\n"));
- return false;
- }
- value = dbwrap_record_get_value(notify_rec);
-
- if (value.dsize != sizeof(deleted)) {
- DEBUG(10, ("record %s has been re-used\n", path));
- goto done;
- }
- memcpy(&deleted, value.dptr, sizeof(deleted));
-
- if (deleted >= delete_before) {
- DEBUG(10, ("record %s too young\n", path));
- goto done;
- }
-
- /*
- * Be kind to ctdb and only try one dmaster migration at most.
- */
- idx_rec = dbwrap_try_fetch_locked(notify->db_index, talloc_tos(), key);
- if (idx_rec == NULL) {
- DEBUG(10, ("Could not fetch idx_rec\n"));
- goto done;
- }
-
- status = dbwrap_record_delete(notify_rec);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("Could not delete notify_rec: %s\n",
- nt_errstr(status)));
- }
-
- status = notify_del_idx(idx_rec, get_my_vnn());
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("Could not delete idx_rec: %s\n",
- nt_errstr(status)));
- }
-
-done:
- TALLOC_FREE(idx_rec);
- TALLOC_FREE(notify_rec);
- return true;
-}
-
-static NTSTATUS notify_del_idx(struct db_record *rec, uint32_t vnn)
-{
- TDB_DATA value = dbwrap_record_get_value(rec);
- uint32_t *vnns;
- size_t i, num_vnns;
-
- if ((value.dsize % sizeof(uint32_t)) != 0) {
- DEBUG(1, ("Invalid value.dsize = %u\n",
- (unsigned)value.dsize));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
- num_vnns = value.dsize / sizeof(uint32_t);
- vnns = (uint32_t *)value.dptr;
-
- for (i=0; i<num_vnns; i++) {
- if (vnns[i] == vnn) {
- break;
- }
- }
-
- if (i == num_vnns) {
- /*
- * Not found. Should not happen, but okay...
- */
- return NT_STATUS_OK;
- }
-
- memmove(&vnns[i], &vnns[i+1], sizeof(uint32_t) * (num_vnns - i - 1));
- value.dsize -= sizeof(uint32_t);
-
- if (value.dsize == 0) {
- return dbwrap_record_delete(rec);
- }
- return dbwrap_record_store(rec, value, 0);
-}
-
-struct notify_cluster_proxy_state {
- struct tevent_context *ev;
- struct notify_context *notify;
- struct ctdb_msg_channel *chan;
-};
-
-static void notify_cluster_proxy_got_chan(struct tevent_req *subreq);
-static void notify_cluster_proxy_got_msg(struct tevent_req *subreq);
-static void notify_cluster_proxy_trigger(struct notify_context *notify,
- uint32_t action, uint32_t filter,
- char *path);
-
-struct tevent_req *notify_cluster_proxy_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct notify_context *notify)
-{
- struct tevent_req *req, *subreq;
- struct notify_cluster_proxy_state *state;
-
- req = tevent_req_create(mem_ctx, &state,
- struct notify_cluster_proxy_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->notify = notify;
-
- subreq = ctdb_msg_channel_init_send(
- state, state->ev, lp_ctdbd_socket(),
- CTDB_SRVID_SAMBA_NOTIFY_PROXY);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, notify_cluster_proxy_got_chan, req);
- return req;
-}
-
-static void notify_cluster_proxy_got_chan(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct notify_cluster_proxy_state *state = tevent_req_data(
- req, struct notify_cluster_proxy_state);
- int ret;
-
- ret = ctdb_msg_channel_init_recv(subreq, state, &state->chan);
- TALLOC_FREE(subreq);
- if (ret != 0) {
- tevent_req_error(req, ret);
- return;
- }
- subreq = ctdb_msg_read_send(state, state->ev, state->chan);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, notify_cluster_proxy_got_msg, req);
-}
-
-static void notify_cluster_proxy_got_msg(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct notify_cluster_proxy_state *state = tevent_req_data(
- req, struct notify_cluster_proxy_state);
- uint8_t *msg;
- size_t msg_len;
- uint32_t action, filter;
- char *path;
- int ret;
- bool res;
-
- ret = ctdb_msg_read_recv(subreq, talloc_tos(), &msg, &msg_len);
- TALLOC_FREE(subreq);
- if (ret != 0) {
- tevent_req_error(req, ret);
- return;
- }
-
- res = notify_pull_remote_blob(talloc_tos(), msg, msg_len,
- &action, &filter, &path);
- TALLOC_FREE(msg);
- if (!res) {
- tevent_req_error(req, EIO);
- return;
- }
- notify_cluster_proxy_trigger(state->notify, action, filter, path);
- TALLOC_FREE(path);
-
- subreq = ctdb_msg_read_send(state, state->ev, state->chan);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, notify_cluster_proxy_got_msg, req);
-}
-
-static void notify_cluster_proxy_trigger(struct notify_context *notify,
- uint32_t action, uint32_t filter,
- char *path)
-{
- const char *p, *next_p;
-
- for (p = path; p != NULL; p = next_p) {
- ptrdiff_t path_len = p - path;
- bool recursive;
-
- next_p = strchr(p+1, '/');
- recursive = (next_p != NULL);
-
- notify_trigger_local(notify, action, filter,
- path, path_len, recursive);
- }
-}
-
-int notify_cluster_proxy_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_unix(req);
-}
diff --git a/source3/smbd/notify_msg.c b/source3/smbd/notify_msg.c
new file mode 100644
index 0000000..b31cb57
--- /dev/null
+++ b/source3/smbd/notify_msg.c
@@ -0,0 +1,268 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "librpc/gen_ndr/notify.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "messages.h"
+#include "proto.h"
+#include "globals.h"
+#include "tdb.h"
+#include "util_tdb.h"
+#include "lib/util/server_id_db.h"
+#include "smbd/notifyd/notifyd.h"
+
+struct notify_list {
+ struct notify_list *next, *prev;
+ void (*callback)(void *private_data, struct timespec when,
+ const struct notify_event *ctx);
+ void *private_data;
+ char path[1];
+};
+
+struct notify_context {
+ struct server_id notifyd;
+ struct messaging_context *msg_ctx;
+ struct notify_list *list;
+};
+
+static void notify_handler(struct messaging_context *msg, void *private_data,
+ uint32_t msg_type, struct server_id src,
+ DATA_BLOB *data);
+
+struct notify_context *notify_init(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg,
+ struct tevent_context *ev)
+{
+ struct server_id_db *names_db;
+ struct notify_context *ctx;
+ NTSTATUS status;
+
+ ctx = talloc(mem_ctx, struct notify_context);
+ if (ctx == NULL) {
+ return NULL;
+ }
+ ctx->msg_ctx = msg;
+ ctx->list = NULL;
+
+ names_db = messaging_names_db(msg);
+ if (!server_id_db_lookup_one(names_db, "notify-daemon",
+ &ctx->notifyd)) {
+ DEBUG(1, ("No notify daemon around\n"));
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+
+ status = messaging_register(msg, ctx, MSG_PVFS_NOTIFY, notify_handler);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("messaging_register failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+static void notify_handler(struct messaging_context *msg, void *private_data,
+ uint32_t msg_type, struct server_id src,
+ DATA_BLOB *data)
+{
+ struct notify_context *ctx = talloc_get_type_abort(
+ private_data, struct notify_context);
+ struct notify_event_msg *event_msg;
+ struct notify_event event;
+ struct notify_list *listel;
+
+ if (data->length < offsetof(struct notify_event_msg, path) + 1) {
+ DEBUG(1, ("message too short: %u\n", (unsigned)data->length));
+ return;
+ }
+ if (data->data[data->length-1] != 0) {
+ DEBUG(1, ("%s: path not 0-terminated\n", __func__));
+ return;
+ }
+
+ event_msg = (struct notify_event_msg *)data->data;
+
+ event.action = event_msg->action;
+ event.path = event_msg->path;
+ event.private_data = event_msg->private_data;
+
+ DEBUG(10, ("%s: Got notify_event action=%u, private_data=%p, "
+ "path=%s\n", __func__, (unsigned)event.action,
+ event.private_data, event.path));
+
+ for (listel = ctx->list; listel != NULL; listel = listel->next) {
+ if (listel->private_data == event.private_data) {
+ listel->callback(listel->private_data, event_msg->when,
+ &event);
+ break;
+ }
+ }
+}
+
+NTSTATUS notify_add(struct notify_context *ctx,
+ const char *path, uint32_t filter, uint32_t subdir_filter,
+ void (*callback)(void *, struct timespec,
+ const struct notify_event *),
+ void *private_data)
+{
+ struct notify_list *listel;
+ struct notify_rec_change_msg msg = {};
+ struct iovec iov[2];
+ size_t pathlen;
+ NTSTATUS status;
+
+ if (ctx == NULL) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ DEBUG(10, ("%s: path=[%s], filter=%u, subdir_filter=%u, "
+ "private_data=%p\n", __func__, path, (unsigned)filter,
+ (unsigned)subdir_filter, private_data));
+
+ pathlen = strlen(path)+1;
+
+ listel = (struct notify_list *)talloc_size(
+ ctx, offsetof(struct notify_list, path) + pathlen);
+ if (listel == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ listel->callback = callback;
+ listel->private_data = private_data;
+ memcpy(listel->path, path, pathlen);
+
+ clock_gettime_mono(&msg.instance.creation_time);
+ msg.instance.filter = filter;
+ msg.instance.subdir_filter = subdir_filter;
+ msg.instance.private_data = private_data;
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
+ iov[1].iov_base = discard_const_p(char, path);
+ iov[1].iov_len = pathlen;
+
+ status = messaging_send_iov(
+ ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(listel);
+ DEBUG(10, ("messaging_send_iov returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ DLIST_ADD(ctx->list, listel);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS notify_remove(struct notify_context *ctx, void *private_data)
+{
+ struct notify_list *listel;
+ struct notify_rec_change_msg msg = {};
+ struct iovec iov[2];
+ NTSTATUS status;
+
+ for (listel = ctx->list; listel != NULL; listel = listel->next) {
+ if (listel->private_data == private_data) {
+ DLIST_REMOVE(ctx->list, listel);
+ break;
+ }
+ }
+ if (listel == NULL) {
+ DEBUG(10, ("%p not found\n", private_data));
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ msg.instance.private_data = private_data;
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
+ iov[1].iov_base = discard_const_p(char, listel->path);
+ iov[1].iov_len = strlen(listel->path)+1;
+
+ status = messaging_send_iov(
+ ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+
+ TALLOC_FREE(listel);
+ return status;
+}
+
+void notify_trigger(struct notify_context *ctx,
+ uint32_t action, uint32_t filter,
+ const char *dir, const char *name)
+{
+ struct notify_trigger_msg msg;
+ struct iovec iov[4];
+ char slash = '/';
+
+ DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
+ "dir=%s, name=%s\n", (unsigned)action, (unsigned)filter,
+ dir, name));
+
+ if (ctx == NULL) {
+ return;
+ }
+
+ msg.when = timespec_current();
+ msg.action = action;
+ msg.filter = filter;
+
+ iov[0].iov_base = &msg;
+ iov[0].iov_len = offsetof(struct notify_trigger_msg, path);
+ iov[1].iov_base = discard_const_p(char, dir);
+ iov[1].iov_len = strlen(dir);
+ iov[2].iov_base = &slash;
+ iov[2].iov_len = 1;
+ iov[3].iov_base = discard_const_p(char, name);
+ iov[3].iov_len = strlen(name)+1;
+
+ messaging_send_iov(
+ ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_TRIGGER,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+}
+
+void notify_walk_idx(struct notify_context *notify,
+ void (*fn)(const char *path,
+ uint32_t *vnns, size_t num_vnns,
+ void *private_data),
+ void *private_data)
+{
+ return;
+}
+
+void notify_walk(struct notify_context *notify,
+ void (*fn)(const char *path,
+ struct notify_db_entry *entries,
+ size_t num_entries,
+ time_t deleted_time, void *private_data),
+ void *private_data)
+{
+ return;
+}
+
+void notify_cleanup(struct notify_context *notify)
+{
+ return;
+}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index e91c355..e4a434a 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -582,11 +582,6 @@ void notify_walk(struct notify_context *notify,
void *private_data);
void notify_cleanup(struct notify_context *notify);
-struct tevent_req *notify_cluster_proxy_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct notify_context *notify);
-int notify_cluster_proxy_recv(struct tevent_req *req);
-
/* The following definitions come from smbd/ntquotas.c */
int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, struct dom_sid *psid, SMB_NTQUOTA_STRUCT *qt);
diff --git a/source3/wscript_build b/source3/wscript_build
index a9fe6e4..80cdb9f 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -608,7 +608,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
smbd/oplock_irix.c
smbd/oplock_linux.c
smbd/notify.c
- smbd/notify_internal.c
+ smbd/notify_msg.c
smbd/build_options.c''' + NOTIFY_SOURCES,
deps='''
talloc
@@ -1198,7 +1198,7 @@ bld.SAMBA3_BINARY('smbta-util',
secrets3
param''')
-smbstatus_source = 'utils/status.c smbd/notify_internal.c'
+smbstatus_source = 'utils/status.c smbd/notify_msg.c'
if bld.CONFIG_GET("WITH_PROFILE"):
smbstatus_source += ' utils/status_profile.c'
--
1.7.9.5
From 77240ccc033a46fe75b9ea698cc9e0c38ce4068b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 17:23:18 +0100
Subject: [PATCH 12/20] smbd: Kernel change notify is done by notifyd
smbd itself does not need to call VFS_NOTIFY_WATCH anymore
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notify.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index b3079d2..e776749 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -236,15 +236,6 @@ static void notify_callback(void *private_data, struct timespec when,
notify_fsp(fsp, when, e->action, e->path);
}
-static void sys_notify_callback(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *e)
-{
- files_struct *fsp = (files_struct *)private_data;
- DEBUG(10, ("sys_notify_callback called for %s\n", fsp_str_dbg(fsp)));
- notify_fsp(fsp, timespec_current(), e->action, e->path);
-}
-
NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter,
bool recursive)
{
@@ -284,19 +275,6 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter,
subdir_filter = recursive ? filter : 0;
- if (fsp->conn->sconn->sys_notify_ctx != NULL) {
- void *sys_notify_handle = NULL;
-
- status = SMB_VFS_NOTIFY_WATCH(
- fsp->conn, fsp->conn->sconn->sys_notify_ctx,
- fullpath, &filter, &subdir_filter,
- sys_notify_callback, fsp, &sys_notify_handle);
-
- if (NT_STATUS_IS_OK(status)) {
- talloc_steal(fsp->notify, sys_notify_handle);
- }
- }
-
if ((filter != 0) || (subdir_filter != 0)) {
status = notify_add(fsp->conn->sconn->notify_ctx,
fullpath, filter, subdir_filter,
--
1.7.9.5
From e76c67fc85842020abba0f306dd0d8755d7bd1b7 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 21 Nov 2014 17:28:02 +0100
Subject: [PATCH 13/20] smbd: Remove the notify_fam module
This has been moved to main smbd
Signed-off-by: Volker Lendecke <vl at samba.org>
---
docs-xml/Samba3-HOWTO/manpages.xml | 1 -
docs-xml/manpages/vfs_notify_fam.8.xml | 70 -------
docs-xml/wscript_build | 1 -
source3/modules/vfs_notify_fam.c | 316 --------------------------------
source3/modules/wscript_build | 7 -
5 files changed, 395 deletions(-)
delete mode 100644 docs-xml/manpages/vfs_notify_fam.8.xml
delete mode 100644 source3/modules/vfs_notify_fam.c
diff --git a/docs-xml/Samba3-HOWTO/manpages.xml b/docs-xml/Samba3-HOWTO/manpages.xml
index 577ac8b..ad23f49 100644
--- a/docs-xml/Samba3-HOWTO/manpages.xml
+++ b/docs-xml/Samba3-HOWTO/manpages.xml
@@ -58,7 +58,6 @@
<xi:include href="../manpages/vfs_full_audit.8.xml"/>
<xi:include href="../manpages/vfs_gpfs.8.xml"/>
<xi:include href="../manpages/vfs_netatalk.8.xml"/>
- <xi:include href="../manpages/vfs_notify_fam.8.xml"/>
<xi:include href="../manpages/vfs_prealloc.8.xml"/>
<xi:include href="../manpages/vfs_readahead.8.xml"/>
<xi:include href="../manpages/vfs_readonly.8.xml"/>
diff --git a/docs-xml/manpages/vfs_notify_fam.8.xml b/docs-xml/manpages/vfs_notify_fam.8.xml
deleted file mode 100644
index 954aa37..0000000
--- a/docs-xml/manpages/vfs_notify_fam.8.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
-<refentry id="vfs_notify_fam.8">
-
-<refmeta>
- <refentrytitle>vfs_notify_fam</refentrytitle>
- <manvolnum>8</manvolnum>
- <refmiscinfo class="source">Samba</refmiscinfo>
- <refmiscinfo class="manual">System Administration tools</refmiscinfo>
- <refmiscinfo class="version">4.2</refmiscinfo>
-</refmeta>
-
-
-<refnamediv>
- <refname>vfs_notify_fam</refname>
- <refpurpose>FAM support for file change notifications</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
- <cmdsynopsis>
- <command>vfs objects = notify_fam</command>
- </cmdsynopsis>
-</refsynopsisdiv>
-
-<refsect1>
- <title>DESCRIPTION</title>
-
- <para>This VFS module is part of the
- <citerefentry><refentrytitle>samba</refentrytitle>
- <manvolnum>7</manvolnum></citerefentry> suite.</para>
-
- <para>The <command>vfs_notify_fam</command> module makes use of
- the system FAM (File Alteration Monitor) daemon to implement
- file change notifications for Windows clients. FAM is generally
- present only on IRIX and some BSD systems.</para>
-
- <para>This module is not stackable.</para>
-
-</refsect1>
-
-<refsect1>
- <title>EXAMPLES</title>
-
- <para>Support FAM notifications globally:</para>
-
-<programlisting>
- <smbconfsection name="[global]"/>
- <smbconfoption name="vfs objects">notify_fam</smbconfoption>
-</programlisting>
-
-</refsect1>
-
-<refsect1>
- <title>VERSION</title>
-
- <para>This man page is correct for version 3.0.25 of the Samba suite.
- </para>
-</refsect1>
-
-<refsect1>
- <title>AUTHOR</title>
-
- <para>The original Samba software and related utilities
- were created by Andrew Tridgell. Samba is now developed
- by the Samba Team as an Open Source project similar
- to the way the Linux kernel is developed.</para>
-
-</refsect1>
-
-</refentry>
diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
index f54ae15..5c42a31 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -68,7 +68,6 @@ manpages='''
manpages/vfs_linux_xfs_sgid.8
manpages/vfs_media_harmony.8
manpages/vfs_netatalk.8
- manpages/vfs_notify_fam.8
manpages/vfs_prealloc.8
manpages/vfs_preopen.8
manpages/vfs_readahead.8
diff --git a/source3/modules/vfs_notify_fam.c b/source3/modules/vfs_notify_fam.c
deleted file mode 100644
index 51ada11..0000000
--- a/source3/modules/vfs_notify_fam.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * FAM file notification support.
- *
- * Copyright (c) James Peach 2005
- * 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 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 "smbd/smbd.h"
-#include "librpc/gen_ndr/notify.h"
-
-#include <fam.h>
-
-#if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF)
-/* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per
- * every other FAM implementation. Phooey.
- */
-typedef enum FAMCodes FAMCodes;
-#endif
-
-/* NOTE: There are multiple versions of FAM floating around the net, each with
- * slight differences from the original SGI FAM implementation. In this file,
- * we rely only on the SGI features and do not assume any extensions. For
- * example, we do not look at FAMErrno, because it is not set by the original
- * implementation.
- *
- * Random FAM links:
- * http://oss.sgi.com/projects/fam/
- * http://savannah.nongnu.org/projects/fam/
- * http://sourceforge.net/projects/bsdfam/
- */
-
-/* ------------------------------------------------------------------------- */
-
-struct fam_watch_context {
- struct fam_watch_context *prev, *next;
- FAMConnection *fam_connection;
- struct FAMRequest fr;
- struct sys_notify_context *sys_ctx;
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev);
- void *private_data;
- uint32_t mask; /* the inotify mask */
- uint32_t filter; /* the windows completion filter */
- const char *path;
-};
-
-
-/*
- * We want one FAM connection per smbd, not one per tcon.
- */
-static FAMConnection fam_connection;
-static bool fam_connection_initialized = False;
-
-static struct fam_watch_context *fam_notify_list;
-static void fam_handler(struct tevent_context *event_ctx,
- struct tevent_fd *fd_event,
- uint16_t flags,
- void *private_data);
-
-static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
- struct tevent_context *event_ctx)
-{
- int res;
- char *name;
-
- ZERO_STRUCTP(fam_conn);
- FAMCONNECTION_GETFD(fam_conn) = -1;
-
-
-#ifdef HAVE_FAMNOEXISTS
- /* We should honor outside setting of the GAM_CLIENT_ID. */
- setenv("GAM_CLIENT_ID","SAMBA",0);
-#endif
-
- if (asprintf(&name, "smbd (%lu)", (unsigned long)getpid()) == -1) {
- DEBUG(0, ("No memory\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- res = FAMOpen2(fam_conn, name);
-
-#ifdef HAVE_FAMNOEXISTS
- /*
- * This reduces the chatter between GAMIN and samba making the pair
- * much more reliable.
- */
- FAMNoExists(fam_conn);
-#endif
-
- SAFE_FREE(name);
-
- if (res < 0) {
- DEBUG(10, ("FAM file change notifications not available\n"));
- /*
- * No idea how to get NT_STATUS from a FAM result
- */
- FAMCONNECTION_GETFD(fam_conn) = -1;
- return NT_STATUS_UNEXPECTED_IO_ERROR;
- }
-
- if (tevent_add_fd(event_ctx, event_ctx,
- FAMCONNECTION_GETFD(fam_conn),
- TEVENT_FD_READ, fam_handler,
- (void *)fam_conn) == NULL) {
- DEBUG(0, ("event_add_fd failed\n"));
- FAMClose(fam_conn);
- FAMCONNECTION_GETFD(fam_conn) = -1;
- return NT_STATUS_NO_MEMORY;
- }
-
- return NT_STATUS_OK;
-}
-
-static void fam_reopen(FAMConnection *fam_conn,
- struct tevent_context *event_ctx,
- struct fam_watch_context *notify_list)
-{
- struct fam_watch_context *ctx;
-
- DEBUG(5, ("Re-opening FAM connection\n"));
-
- FAMClose(fam_conn);
-
- if (!NT_STATUS_IS_OK(fam_open_connection(fam_conn, event_ctx))) {
- DEBUG(5, ("Re-opening fam connection failed\n"));
- return;
- }
-
- for (ctx = notify_list; ctx; ctx = ctx->next) {
- FAMMonitorDirectory(fam_conn, ctx->path, &ctx->fr, NULL);
- }
-}
-
-static void fam_handler(struct tevent_context *event_ctx,
- struct tevent_fd *fd_event,
- uint16_t flags,
- void *private_data)
-{
- FAMConnection *fam_conn = (FAMConnection *)private_data;
- FAMEvent fam_event;
- struct fam_watch_context *ctx;
- struct notify_event ne;
-
- if (FAMPending(fam_conn) == 0) {
- DEBUG(10, ("fam_handler called but nothing pending\n"));
- return;
- }
-
- if (FAMNextEvent(fam_conn, &fam_event) != 1) {
- DEBUG(5, ("FAMNextEvent returned an error\n"));
- TALLOC_FREE(fd_event);
- fam_reopen(fam_conn, event_ctx, fam_notify_list);
- return;
- }
-
- DEBUG(10, ("Got FAMCode %d for %s\n", fam_event.code,
- fam_event.filename));
-
- switch (fam_event.code) {
- case FAMChanged:
- ne.action = NOTIFY_ACTION_MODIFIED;
- break;
- case FAMCreated:
- ne.action = NOTIFY_ACTION_ADDED;
- break;
- case FAMDeleted:
- ne.action = NOTIFY_ACTION_REMOVED;
- break;
- default:
- DEBUG(10, ("Ignoring code FAMCode %d for file %s\n",
- (int)fam_event.code, fam_event.filename));
- return;
- }
-
- for (ctx = fam_notify_list; ctx; ctx = ctx->next) {
- if (memcmp(&fam_event.fr, &ctx->fr, sizeof(FAMRequest)) == 0) {
- break;
- }
- }
-
- if (ctx == NULL) {
- DEBUG(5, ("Discarding event for file %s\n",
- fam_event.filename));
- return;
- }
-
- if ((ne.path = strrchr_m(fam_event.filename, '\\')) == NULL) {
- ne.path = fam_event.filename;
- }
-
- ctx->callback(ctx->sys_ctx, ctx->private_data, &ne);
-}
-
-static int fam_watch_context_destructor(struct fam_watch_context *ctx)
-{
- if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
- FAMCancelMonitor(&fam_connection, &ctx->fr);
- }
- DLIST_REMOVE(fam_notify_list, ctx);
- return 0;
-}
-
-/*
- add a watch. The watch is removed when the caller calls
- talloc_free() on *handle
-*/
-static NTSTATUS fam_watch(vfs_handle_struct *vfs_handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data,
- void *handle_p)
-{
- const uint32_t fam_mask = (FILE_NOTIFY_CHANGE_FILE_NAME|
- FILE_NOTIFY_CHANGE_DIR_NAME);
- struct fam_watch_context *watch;
- void **handle = (void **)handle_p;
-
- if ((*filter & fam_mask) == 0) {
- DEBUG(10, ("filter = %u, ignoring in FAM\n", *filter));
- return NT_STATUS_OK;
- }
-
- if (!fam_connection_initialized) {
- if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
- ctx->ev))) {
- /*
- * Just let smbd do all the work itself
- */
- return NT_STATUS_OK;
- }
- fam_connection_initialized = True;
- }
-
- if (!(watch = talloc(ctx, struct fam_watch_context))) {
- return NT_STATUS_NO_MEMORY;
- }
-
- watch->fam_connection = &fam_connection;
-
- watch->callback = callback;
- watch->private_data = private_data;
- watch->sys_ctx = ctx;
-
- watch->path = talloc_strdup(watch, path);
- if (watch->path == NULL) {
- DEBUG(0, ("talloc_asprintf failed\n"));
- TALLOC_FREE(watch);
- return NT_STATUS_NO_MEMORY;
- }
-
- /*
- * The FAM module in this early state will only take care of
- * FAMCreated and FAMDeleted events, Leave the rest to
- * notify_internal.c
- */
-
- watch->filter = fam_mask;
- *filter &= ~fam_mask;
-
- DLIST_ADD(fam_notify_list, watch);
- talloc_set_destructor(watch, fam_watch_context_destructor);
-
- /*
- * Only directories monitored so far
- */
-
- if (FAMCONNECTION_GETFD(watch->fam_connection) != -1) {
- FAMMonitorDirectory(watch->fam_connection, watch->path,
- &watch->fr, NULL);
- }
- else {
- /*
- * If the re-open is successful, this will establish the
- * FAMMonitor from the list
- */
- fam_reopen(watch->fam_connection, ctx->ev, fam_notify_list);
- }
-
- *handle = (void *)watch;
-
- return NT_STATUS_OK;
-}
-
-/* VFS operations structure */
-
-static struct vfs_fn_pointers notify_fam_fns = {
- .notify_watch_fn = fam_watch,
-};
-
-
-NTSTATUS vfs_notify_fam_init(void);
-NTSTATUS vfs_notify_fam_init(void)
-{
- return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "notify_fam",
- ¬ify_fam_fns);
-}
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index 30f3bdd..d05e58b 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -284,13 +284,6 @@ bld.SAMBA3_MODULE('vfs_gpfs',
vfs_notify_fam_deps='samba-util '
if bld.CONFIG_SET('SAMBA_FAM_LIBS'):
vfs_notify_fam_deps += bld.CONFIG_GET('SAMBA_FAM_LIBS')
-bld.SAMBA3_MODULE('vfs_notify_fam',
- subsystem='vfs',
- source='vfs_notify_fam.c',
- deps=vfs_notify_fam_deps,
- init_function='',
- internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_notify_fam'),
- enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_notify_fam'))
bld.SAMBA3_MODULE('vfs_readahead',
subsystem='vfs',
--
1.7.9.5
From 769c9eba552f1e1fb10a4fb1348af9aebe9fb7f9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 9 Jan 2015 12:24:58 +0000
Subject: [PATCH 14/20] notifyd: Add notifyd_parse_db()
The database format notifyd is "private" to it. This makes it
possible for smbcontrol and others to query notifyd's database with
MSG_SMB_NOTIFY_GET_DB and inspect it without having to know exactly what
format it uses.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notifyd/notifyd.c | 71 ++++++++++++++++++++++++++++++++++++++++
source3/smbd/notifyd/notifyd.h | 13 ++++++++
2 files changed, 84 insertions(+)
diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c
index ea48035..b34b526 100644
--- a/source3/smbd/notifyd/notifyd.c
+++ b/source3/smbd/notifyd/notifyd.c
@@ -1416,3 +1416,74 @@ static void notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
return;
}
}
+
+struct notifyd_parse_db_state {
+ bool (*fn)(const char *path,
+ struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data);
+ void *private_data;
+};
+
+static bool notifyd_parse_db_parser(TDB_DATA key, TDB_DATA value,
+ void *private_data)
+{
+ struct notifyd_parse_db_state *state = private_data;
+ char path[key.dsize+1];
+ struct notifyd_instance *instances = NULL;
+ size_t num_instances = 0;
+ size_t i;
+ bool ok;
+
+ memcpy(path, key.dptr, key.dsize);
+ path[key.dsize] = 0;
+
+ ok = notifyd_parse_entry(value.dptr, value.dsize, &instances,
+ &num_instances);
+ if (!ok) {
+ DEBUG(10, ("%s: Could not parse entry for path %s\n",
+ __func__, path));
+ return true;
+ }
+
+ for (i=0; i<num_instances; i++) {
+ ok = state->fn(path, instances[i].client,
+ &instances[i].instance,
+ state->private_data);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int notifyd_parse_db(const uint8_t *buf, size_t buflen,
+ uint64_t *log_index,
+ bool (*fn)(const char *path,
+ struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data),
+ void *private_data)
+{
+ struct notifyd_parse_db_state state = {
+ .fn = fn, .private_data = private_data
+ };
+ NTSTATUS status;
+
+ if (buflen < 8) {
+ return EINVAL;
+ }
+ *log_index = BVAL(buf, 0);
+
+ buf += 8;
+ buflen -= 8;
+
+ status = dbwrap_parse_marshall_buf(
+ buf, buflen, notifyd_parse_db_parser, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return map_errno_from_nt_status(status);
+ }
+
+ return 0;
+}
diff --git a/source3/smbd/notifyd/notifyd.h b/source3/smbd/notifyd/notifyd.h
index dc0a4e8..672ffba 100644
--- a/source3/smbd/notifyd/notifyd.h
+++ b/source3/smbd/notifyd/notifyd.h
@@ -140,4 +140,17 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct sys_notify_context *sys_notify_ctx);
int notifyd_recv(struct tevent_req *req);
+/*
+ * Parse a database received via the MSG_SMB_NOTIFY_[GET_]DB messages to the
+ * notify daemon
+ */
+int notifyd_parse_db(const uint8_t *buf, size_t buflen,
+ uint64_t *log_index,
+ bool (*fn)(const char *path,
+ struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data),
+ void *private_data);
+
+
#endif
--
1.7.9.5
From 86f3e3e3b84d15cdfa199422d26bf761d860ad46 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 9 Jan 2015 12:48:56 +0000
Subject: [PATCH 15/20] notify: Re-add notify_walk()
This used to be a tdb traverse wrapper. Now we get the notify db from
notifyd via messages.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notify_msg.c | 72 ++++++++++++++++++++++++++++++++++++++++-----
source3/smbd/proto.h | 14 +++++----
source3/utils/status.c | 44 ++++++++++++++-------------
3 files changed, 96 insertions(+), 34 deletions(-)
diff --git a/source3/smbd/notify_msg.c b/source3/smbd/notify_msg.c
index b31cb57..2fe4472 100644
--- a/source3/smbd/notify_msg.c
+++ b/source3/smbd/notify_msg.c
@@ -252,14 +252,72 @@ void notify_walk_idx(struct notify_context *notify,
return;
}
-void notify_walk(struct notify_context *notify,
- void (*fn)(const char *path,
- struct notify_db_entry *entries,
- size_t num_entries,
- time_t deleted_time, void *private_data),
- void *private_data)
+NTSTATUS notify_walk(struct notify_context *notify,
+ bool (*fn)(const char *path, struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data),
+ void *private_data)
{
- return;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ struct messaging_rec *rec;
+ uint64_t log_idx;
+ NTSTATUS status;
+ int ret;
+ bool ok;
+
+ ev = samba_tevent_context_init(notify);
+ if (ev == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ req = messaging_read_send(ev, ev, notify->msg_ctx, MSG_SMB_NOTIFY_DB);
+ if (req == NULL) {
+ TALLOC_FREE(ev);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(10, 0));
+ if (!ok) {
+ TALLOC_FREE(ev);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = messaging_send_buf(notify->msg_ctx, notify->notifyd,
+ MSG_SMB_NOTIFY_GET_DB, NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("%s: messaging_send_buf failed\n",
+ nt_errstr(status)));
+ TALLOC_FREE(ev);
+ return status;
+ }
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ DEBUG(10, ("%s: tevent_req_poll failed\n", __func__));
+ TALLOC_FREE(ev);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ret = messaging_read_recv(req, ev, &rec);
+ if (ret != 0) {
+ DEBUG(10, ("%s: messaging_read_recv failed: %s\n",
+ __func__, strerror(ret)));
+ TALLOC_FREE(ev);
+ return map_nt_error_from_unix(ret);
+ }
+
+ ret = notifyd_parse_db(rec->buf.data, rec->buf.length, &log_idx,
+ fn, private_data);
+ if (ret != 0) {
+ DEBUG(10, ("%s: notifyd_parse_db failed: %s\n",
+ __func__, strerror(ret)));
+ TALLOC_FREE(ev);
+ return map_nt_error_from_unix(ret);
+ }
+
+ TALLOC_FREE(ev);
+ return NT_STATUS_OK;
}
void notify_cleanup(struct notify_context *notify)
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index e4a434a..79be349 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -574,12 +574,14 @@ void notify_walk_idx(struct notify_context *notify,
uint32_t *vnns, size_t num_vnns,
void *private_data),
void *private_data);
-void notify_walk(struct notify_context *notify,
- void (*fn)(const char *path,
- struct notify_db_entry *entries,
- size_t num_entries,
- time_t deleted_time, void *private_data),
- void *private_data);
+
+struct notify_instance;
+NTSTATUS notify_walk(struct notify_context *notify,
+ bool (*fn)(const char *path, struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data),
+ void *private_data);
+
void notify_cleanup(struct notify_context *notify);
/* The following definitions come from smbd/ntquotas.c */
diff --git a/source3/utils/status.c b/source3/utils/status.c
index afbba69..c11b4ee 100644
--- a/source3/utils/status.c
+++ b/source3/utils/status.c
@@ -45,6 +45,7 @@
#include "lib/conn_tdb.h"
#include "serverid.h"
#include "status_profile.h"
+#include "smbd/notifyd/notifyd.h"
#define SMB_MAXPIDS 2048
static uid_t Ucrit_uid = 0; /* added by OH */
@@ -326,27 +327,17 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
}
-static void print_notify_recs(const char *path,
- struct notify_db_entry *entries,
- size_t num_entries,
- time_t deleted_time, void *private_data)
+static bool print_notify_rec(const char *path, struct server_id server,
+ const struct notify_instance *instance,
+ void *private_data)
{
- size_t i;
- d_printf("%s\n", path);
+ struct server_id_buf idbuf;
- if (num_entries == 0) {
- d_printf("deleted %s\n", time_to_asc(deleted_time));
- }
-
- for (i=0; i<num_entries; i++) {
- struct notify_db_entry *e = &entries[i];
- struct server_id_buf idbuf;
+ d_printf("%s\\%s\\%x\\%x\n", path, server_id_str_buf(server, &idbuf),
+ (unsigned)instance->filter,
+ (unsigned)instance->subdir_filter);
- printf("%s %x %x\n", server_id_str_buf(e->server, &idbuf),
- (unsigned)e->filter,
- (unsigned)e->subdir_filter);
- }
- printf("\n");
+ return true;
}
int main(int argc, const char *argv[])
@@ -375,7 +366,7 @@ int main(int argc, const char *argv[])
};
TALLOC_CTX *frame = talloc_stackframe();
int ret = 0;
- struct messaging_context *msg_ctx;
+ struct messaging_context *msg_ctx = NULL;
char *db_path;
bool ok;
@@ -586,11 +577,22 @@ int main(int argc, const char *argv[])
if (show_notify) {
struct notify_context *n;
- n = notify_init(talloc_tos(), NULL, NULL);
+ if (msg_ctx == NULL) {
+ msg_ctx = messaging_init(
+ NULL, samba_tevent_context_init(NULL));
+ if (msg_ctx == NULL) {
+ fprintf(stderr, "messaging_init failed\n");
+ ret = -1;
+ goto done;
+ }
+ }
+
+ n = notify_init(talloc_tos(), msg_ctx,
+ messaging_tevent_context(msg_ctx));
if (n == NULL) {
goto done;
}
- notify_walk(n, print_notify_recs, NULL);
+ notify_walk(n, print_notify_rec, NULL);
TALLOC_FREE(n);
}
--
1.7.9.5
From 3d94a482991827fc05690b4a1eaec1bac1fa2470 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 12 Dec 2014 15:37:30 +0100
Subject: [PATCH 16/20] smbd: Remove SMB_VFS_NOTIFY_WATCH
No longer needed
Signed-off-by: Volker Lendecke <vl at samba.org>
---
examples/VFS/skel_opaque.c | 14 ------------
examples/VFS/skel_transparent.c | 16 -------------
source3/include/vfs.h | 19 ----------------
source3/include/vfs_macros.h | 5 -----
source3/modules/vfs_ceph.c | 18 ---------------
source3/modules/vfs_default.c | 46 --------------------------------------
source3/modules/vfs_full_audit.c | 24 --------------------
source3/modules/vfs_glusterfs.c | 13 -----------
source3/modules/vfs_time_audit.c | 29 ------------------------
source3/smbd/vfs.c | 16 -------------
10 files changed, 200 deletions(-)
diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
index 296a855..7021998 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -490,19 +490,6 @@ static char *skel_realpath(vfs_handle_struct *handle, const char *path)
return NULL;
}
-static NTSTATUS skel_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback) (struct sys_notify_context *
- ctx, void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
static int skel_chflags(vfs_handle_struct *handle, const char *path,
uint flags)
{
@@ -918,7 +905,6 @@ struct vfs_fn_pointers skel_opaque_fns = {
.link_fn = skel_link,
.mknod_fn = skel_mknod,
.realpath_fn = skel_realpath,
- .notify_watch_fn = skel_notify_watch,
.chflags_fn = skel_chflags,
.file_id_create_fn = skel_file_id_create,
.copy_chunk_send_fn = skel_copy_chunk_send,
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
index 10f5ac5..6c6adea 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -579,21 +579,6 @@ static char *skel_realpath(vfs_handle_struct *handle, const char *path)
return SMB_VFS_NEXT_REALPATH(handle, path);
}
-static NTSTATUS skel_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback) (struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- return SMB_VFS_NEXT_NOTIFY_WATCH(handle, ctx, path,
- filter, subdir_filter, callback,
- private_data, handle_p);
-}
-
static int skel_chflags(vfs_handle_struct *handle, const char *path,
uint flags)
{
@@ -1029,7 +1014,6 @@ struct vfs_fn_pointers skel_transparent_fns = {
.link_fn = skel_link,
.mknod_fn = skel_mknod,
.realpath_fn = skel_realpath,
- .notify_watch_fn = skel_notify_watch,
.chflags_fn = skel_chflags,
.file_id_create_fn = skel_file_id_create,
.copy_chunk_send_fn = skel_copy_chunk_send,
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index aa1a880..15e87ff 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -624,16 +624,6 @@ struct vfs_fn_pointers {
int (*link_fn)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath);
int (*mknod_fn)(struct vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev);
char *(*realpath_fn)(struct vfs_handle_struct *handle, const char *path);
- NTSTATUS (*notify_watch_fn)(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data,
- void *handle_p);
int (*chflags_fn)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
struct file_id (*file_id_create_fn)(struct vfs_handle_struct *handle,
const SMB_STRUCT_STAT *sbuf);
@@ -1091,15 +1081,6 @@ int smb_vfs_call_link(struct vfs_handle_struct *handle, const char *oldpath,
int smb_vfs_call_mknod(struct vfs_handle_struct *handle, const char *path,
mode_t mode, SMB_DEV_T dev);
char *smb_vfs_call_realpath(struct vfs_handle_struct *handle, const char *path);
-NTSTATUS smb_vfs_call_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *name,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p);
int smb_vfs_call_chflags(struct vfs_handle_struct *handle, const char *path,
unsigned int flags);
struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle,
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index 9a686c9..eaf0c19 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -336,11 +336,6 @@
#define SMB_VFS_NEXT_REALPATH(handle, path) \
smb_vfs_call_realpath((handle)->next, (path))
-#define SMB_VFS_NOTIFY_WATCH(conn, ctx, path, filter, subdir_filter, callback, private_data, handle_p) \
- smb_vfs_call_notify_watch((conn)->vfs_handles, (ctx), (path), (filter), (subdir_filter), (callback), (private_data), (handle_p))
-#define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, path, filter, subdir_filter, callback, private_data, handle_p) \
- smb_vfs_call_notify_watch((conn)->next, (ctx), (path), (filter), (subdir_filter), (callback), (private_data), (handle_p))
-
#define SMB_VFS_CHFLAGS(conn, path, flags) \
smb_vfs_call_chflags((conn)->vfs_handles, (path), (flags))
#define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) \
diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
index ff642fe..0113faa 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -1011,23 +1011,6 @@ static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *pa
return result;
}
-static NTSTATUS cephwrap_notify_watch(struct vfs_handle_struct *vfs_handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data,
- void *handle_p)
-{
- /*
- * We cannot call inotify on files the kernel does not know about
- */
- return NT_STATUS_OK;
-}
-
static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
unsigned int flags)
{
@@ -1303,7 +1286,6 @@ static struct vfs_fn_pointers ceph_fns = {
.link_fn = cephwrap_link,
.mknod_fn = cephwrap_mknod,
.realpath_fn = cephwrap_realpath,
- .notify_watch_fn = cephwrap_notify_watch,
.chflags_fn = cephwrap_chflags,
.get_real_filename_fn = cephwrap_get_real_filename,
.connectpath_fn = cephwrap_connectpath,
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 8e4953e..6cd1dbc 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -2126,51 +2126,6 @@ static char *vfswrap_realpath(vfs_handle_struct *handle, const char *path)
return result;
}
-static NTSTATUS vfswrap_notify_watch(vfs_handle_struct *vfs_handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle)
-{
- /*
- * So far inotify is the only supported default notify mechanism. If
- * another platform like the the BSD's or a proprietary Unix comes
- * along and wants another default, we can play the same trick we
- * played with Posix ACLs.
- *
- * Until that is the case, hard-code inotify here.
- */
-#ifdef HAVE_INOTIFY
- if (lp_kernel_change_notify()) {
- int ret;
- if (!lp_parm_bool(-1, "notify", "inotify", True)) {
- return NT_STATUS_INVALID_SYSTEM_SERVICE;
- }
- /*
- * "ctx->private_data" is not obvious as a talloc context
- * here. Without modifying the VFS we don't have a mem_ctx
- * available here, and ctx->private_data was used by
- * inotify_watch before it got a real talloc parent.
- */
- ret = inotify_watch(ctx->private_data, ctx,
- path, filter, subdir_filter,
- callback, private_data, handle);
- if (ret != 0) {
- return map_nt_error_from_unix(ret);
- }
- return NT_STATUS_OK;
- }
-#endif
- /*
- * Do nothing, leave everything to notify_internal.c
- */
- return NT_STATUS_OK;
-}
-
static int vfswrap_chflags(vfs_handle_struct *handle, const char *path,
unsigned int flags)
{
@@ -2637,7 +2592,6 @@ static struct vfs_fn_pointers vfs_default_fns = {
.link_fn = vfswrap_link,
.mknod_fn = vfswrap_mknod,
.realpath_fn = vfswrap_realpath,
- .notify_watch_fn = vfswrap_notify_watch,
.chflags_fn = vfswrap_chflags,
.file_id_create_fn = vfswrap_file_id_create,
.streaminfo_fn = vfswrap_streaminfo,
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index c6648d1..6de22b1 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -158,7 +158,6 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_LINK,
SMB_VFS_OP_MKNOD,
SMB_VFS_OP_REALPATH,
- SMB_VFS_OP_NOTIFY_WATCH,
SMB_VFS_OP_CHFLAGS,
SMB_VFS_OP_FILE_ID_CREATE,
SMB_VFS_OP_STREAMINFO,
@@ -286,7 +285,6 @@ static struct {
{ SMB_VFS_OP_LINK, "link" },
{ SMB_VFS_OP_MKNOD, "mknod" },
{ SMB_VFS_OP_REALPATH, "realpath" },
- { SMB_VFS_OP_NOTIFY_WATCH, "notify_watch" },
{ SMB_VFS_OP_CHFLAGS, "chflags" },
{ SMB_VFS_OP_FILE_ID_CREATE, "file_id_create" },
{ SMB_VFS_OP_STREAMINFO, "streaminfo" },
@@ -1630,27 +1628,6 @@ static char *smb_full_audit_realpath(vfs_handle_struct *handle,
return result;
}
-static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- NTSTATUS result;
-
- result = SMB_VFS_NEXT_NOTIFY_WATCH(handle, ctx, path,
- filter, subdir_filter, callback,
- private_data, handle_p);
-
- do_log(SMB_VFS_OP_NOTIFY_WATCH, NT_STATUS_IS_OK(result), handle, "");
-
- return result;
-}
-
static int smb_full_audit_chflags(vfs_handle_struct *handle,
const char *path, unsigned int flags)
{
@@ -2305,7 +2282,6 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
.link_fn = smb_full_audit_link,
.mknod_fn = smb_full_audit_mknod,
.realpath_fn = smb_full_audit_realpath,
- .notify_watch_fn = smb_full_audit_notify_watch,
.chflags_fn = smb_full_audit_chflags,
.file_id_create_fn = smb_full_audit_file_id_create,
.streaminfo_fn = smb_full_audit_streaminfo,
diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
index cd58080..a66887d 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -1039,18 +1039,6 @@ static int vfs_gluster_mknod(struct vfs_handle_struct *handle, const char *path,
return glfs_mknod(handle->data, path, mode, dev);
}
-static NTSTATUS vfs_gluster_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path, uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback) (struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
const char *path, unsigned int flags)
{
@@ -1760,7 +1748,6 @@ static struct vfs_fn_pointers glusterfs_fns = {
.link_fn = vfs_gluster_link,
.mknod_fn = vfs_gluster_mknod,
.realpath_fn = vfs_gluster_realpath,
- .notify_watch_fn = vfs_gluster_notify_watch,
.chflags_fn = vfs_gluster_chflags,
.file_id_create_fn = NULL,
.copy_chunk_send_fn = NULL,
diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
index 5c43d7c..7efad1e 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -1483,34 +1483,6 @@ static char *smb_time_audit_realpath(vfs_handle_struct *handle,
return result;
}
-static NTSTATUS smb_time_audit_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- NTSTATUS result;
- struct timespec ts1,ts2;
- double timediff;
-
- clock_gettime_mono(&ts1);
- result = SMB_VFS_NEXT_NOTIFY_WATCH(handle, ctx, path,
- filter, subdir_filter, callback,
- private_data, handle_p);
- clock_gettime_mono(&ts2);
- timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
-
- if (timediff > audit_timeout) {
- smb_time_audit_log_fname("notify_watch", timediff, path);
- }
-
- return result;
-}
-
static int smb_time_audit_chflags(vfs_handle_struct *handle,
const char *path, unsigned int flags)
{
@@ -2507,7 +2479,6 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
.link_fn = smb_time_audit_link,
.mknod_fn = smb_time_audit_mknod,
.realpath_fn = smb_time_audit_realpath,
- .notify_watch_fn = smb_time_audit_notify_watch,
.chflags_fn = smb_time_audit_chflags,
.file_id_create_fn = smb_time_audit_file_id_create,
.streaminfo_fn = smb_time_audit_streaminfo,
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 4ab7723..37e67f5 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -2053,22 +2053,6 @@ char *smb_vfs_call_realpath(struct vfs_handle_struct *handle, const char *path)
return handle->fns->realpath_fn(handle, path);
}
-NTSTATUS smb_vfs_call_notify_watch(struct vfs_handle_struct *handle,
- struct sys_notify_context *ctx,
- const char *path,
- uint32_t *filter,
- uint32_t *subdir_filter,
- void (*callback)(struct sys_notify_context *ctx,
- void *private_data,
- struct notify_event *ev),
- void *private_data, void *handle_p)
-{
- VFS_FIND(notify_watch);
- return handle->fns->notify_watch_fn(handle, ctx, path,
- filter, subdir_filter, callback,
- private_data, handle_p);
-}
-
int smb_vfs_call_chflags(struct vfs_handle_struct *handle, const char *path,
unsigned int flags)
{
--
1.7.9.5
From 0c5ef152a1f973cae5589f2e5073c17ecdb6ad40 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 9 Jan 2015 12:59:46 +0000
Subject: [PATCH 17/20] notify: Remove two now unused stubs
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notify_msg.c | 14 --------------
source3/smbd/proto.h | 7 -------
2 files changed, 21 deletions(-)
diff --git a/source3/smbd/notify_msg.c b/source3/smbd/notify_msg.c
index 2fe4472..8641983 100644
--- a/source3/smbd/notify_msg.c
+++ b/source3/smbd/notify_msg.c
@@ -243,15 +243,6 @@ void notify_trigger(struct notify_context *ctx,
iov, ARRAY_SIZE(iov), NULL, 0);
}
-void notify_walk_idx(struct notify_context *notify,
- void (*fn)(const char *path,
- uint32_t *vnns, size_t num_vnns,
- void *private_data),
- void *private_data)
-{
- return;
-}
-
NTSTATUS notify_walk(struct notify_context *notify,
bool (*fn)(const char *path, struct server_id server,
const struct notify_instance *instance,
@@ -319,8 +310,3 @@ NTSTATUS notify_walk(struct notify_context *notify,
TALLOC_FREE(ev);
return NT_STATUS_OK;
}
-
-void notify_cleanup(struct notify_context *notify)
-{
- return;
-}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 79be349..2eac3ec 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -569,11 +569,6 @@ NTSTATUS notify_remove(struct notify_context *notify, void *private_data);
void notify_trigger(struct notify_context *notify,
uint32_t action, uint32_t filter,
const char *dir, const char *path);
-void notify_walk_idx(struct notify_context *notify,
- void (*fn)(const char *path,
- uint32_t *vnns, size_t num_vnns,
- void *private_data),
- void *private_data);
struct notify_instance;
NTSTATUS notify_walk(struct notify_context *notify,
@@ -582,8 +577,6 @@ NTSTATUS notify_walk(struct notify_context *notify,
void *private_data),
void *private_data);
-void notify_cleanup(struct notify_context *notify);
-
/* The following definitions come from smbd/ntquotas.c */
int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, struct dom_sid *psid, SMB_NTQUOTA_STRUCT *qt);
--
1.7.9.5
From e66d50d85b335a870925ac8a8c21c608774c2571 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 15 Jun 2015 12:14:03 +0000
Subject: [PATCH 18/20] utils: add net notify
A little tool to play with the notify daemon
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/utils/net.c | 8 ++
source3/utils/net_notify.c | 198 ++++++++++++++++++++++++++++++++++++++++++++
source3/utils/net_proto.h | 1 +
source3/wscript_build | 1 +
4 files changed, 208 insertions(+)
create mode 100644 source3/utils/net_notify.c
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 4a8fad1..8182323 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -743,6 +743,14 @@ static struct functable net_func[] = {
"'net serverid' commands.")
},
+ { "notify",
+ net_notify,
+ NET_TRANSPORT_LOCAL,
+ N_("notifyd client code"),
+ N_(" Use 'net help notify' to get more information about "
+ "'net notify' commands.")
+ },
+
#ifdef WITH_FAKE_KASERVER
{ "afs",
net_afs,
diff --git a/source3/utils/net_notify.c b/source3/utils/net_notify.c
new file mode 100644
index 0000000..7138bcb
--- /dev/null
+++ b/source3/utils/net_notify.c
@@ -0,0 +1,198 @@
+/*
+ * Samba Unix/Linux notifyd client code
+ * Copyright (C) 2015 Volker Lendecke <vl at samba.org>
+ *
+ * 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 "utils/net.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/server_id_db.h"
+#include "messages.h"
+#include "source3/smbd/notifyd/notifyd.h"
+
+static void net_notify_got_event(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct notify_event_msg *event_msg;
+
+ if (data->length < offsetof(struct notify_event_msg, path) + 1) {
+ d_fprintf(stderr, "message too short\n");
+ return;
+ }
+ if (data->data[data->length-1] != 0) {
+ d_fprintf(stderr, "path not 0-terminated\n");
+ return;
+ }
+
+ event_msg = (struct notify_event_msg *)data->data;
+
+ d_printf("%u %s\n", (unsigned)event_msg->action,
+ event_msg->path);
+}
+
+static int net_notify_listen(struct net_context *c, int argc,
+ const char **argv)
+{
+ struct messaging_context *msg_ctx = c->msg_ctx;
+ struct tevent_context *ev = messaging_tevent_context(msg_ctx);
+ struct server_id_db *names_db = messaging_names_db(msg_ctx);
+ struct server_id notifyd;
+ struct server_id_buf idbuf;
+ struct notify_rec_change_msg msg;
+ struct iovec iov[2];
+ NTSTATUS status;
+ bool ok;
+
+ if (argc != 3) {
+ d_printf("Usage: net notify listen <path> <filter> "
+ "<subdir-filter>\n");
+ return -1;
+ }
+
+ ok = server_id_db_lookup_one(names_db, "notify-daemon", ¬ifyd);
+ if (!ok) {
+ fprintf(stderr, "no notify daemon found\n");
+ return -1;
+ }
+
+ printf("notify daemon: %s\n", server_id_str_buf(notifyd, &idbuf));
+
+ msg = (struct notify_rec_change_msg) {
+ .instance.filter = atoi(argv[1]),
+ .instance.subdir_filter = atoi(argv[2])
+ };
+ iov[0] = (struct iovec) {
+ .iov_base = &msg,
+ .iov_len = offsetof(struct notify_rec_change_msg, path)
+ };
+ iov[1] = (struct iovec) {
+ .iov_base = discard_const_p(char, argv[0]),
+ .iov_len = strlen(argv[0])+1
+ };
+
+ status = messaging_register(c->msg_ctx, NULL, MSG_PVFS_NOTIFY,
+ net_notify_got_event);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "messaging_register failed: %s\n",
+ nt_errstr(status));
+ return -1;
+ }
+
+ status = messaging_send_iov(
+ c->msg_ctx, notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Sending rec_change to %s returned %s\n",
+ server_id_str_buf(notifyd, &idbuf),
+ nt_errstr(status));
+ return -1;
+ }
+
+ while (true) {
+ int ret;
+
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ d_fprintf(stderr, "tevent_loop_once failed: %s\n",
+ strerror(errno));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int net_notify_trigger(struct net_context *c, int argc,
+ const char **argv)
+{
+ struct messaging_context *msg_ctx = c->msg_ctx;
+ struct server_id_db *names_db = messaging_names_db(msg_ctx);
+ struct server_id notifyd;
+ struct server_id_buf idbuf;
+ struct notify_trigger_msg msg;
+ struct iovec iov[2];
+ NTSTATUS status;
+ bool ok;
+
+ if (argc != 3) {
+ d_printf("Usage: net notify trigger <path> <action> "
+ "<filter>\n");
+ return -1;
+ }
+
+ ok = server_id_db_lookup_one(names_db, "notify-daemon", ¬ifyd);
+ if (!ok) {
+ fprintf(stderr, "no notify daemon found\n");
+ return -1;
+ }
+
+ printf("notify daemon: %s\n", server_id_str_buf(notifyd, &idbuf));
+
+ msg = (struct notify_trigger_msg) {
+ .action = atoi(argv[1]), .filter = atoi(argv[2])
+ };
+
+ iov[0] = (struct iovec) {
+ .iov_base = &msg,
+ .iov_len = offsetof(struct notify_trigger_msg, path)
+ };
+ iov[1] = (struct iovec) {
+ .iov_base = discard_const_p(char, argv[0]),
+ .iov_len = strlen(argv[0])+1
+ };
+
+ status = messaging_send_iov(
+ c->msg_ctx, notifyd, MSG_SMB_NOTIFY_TRIGGER,
+ iov, ARRAY_SIZE(iov), NULL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Sending rec_change to %s returned %s\n",
+ server_id_str_buf(notifyd, &idbuf),
+ nt_errstr(status));
+ return -1;
+ }
+
+ return 0;
+}
+
+int net_notify(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ { "listen",
+ net_notify_listen,
+ NET_TRANSPORT_LOCAL,
+ N_("Register for a path and listen for changes"),
+ N_("net notify listen <path>")
+ },
+ { "trigger",
+ net_notify_trigger,
+ NET_TRANSPORT_LOCAL,
+ N_("Simulate a trigger action"),
+ N_("net notify trigger <path> <action> <filter>")
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (c->msg_ctx == NULL) {
+ d_fprintf(stderr, "No connection to messaging, need to run "
+ "as root\n");
+ return -1;
+ }
+
+ return net_run_function(c, argc, argv, "net notify", func);
+}
diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h
index 27cdb8d..093aa4b 100644
--- a/source3/utils/net_proto.h
+++ b/source3/utils/net_proto.h
@@ -461,4 +461,5 @@ int net_rpc_trust(struct net_context *c, int argc, const char **argv);
/* The following definitions come from utils/net_rpc_conf.c */
int net_rpc_conf(struct net_context *c, int argc, const char **argv);
+int net_notify(struct net_context *c, int argc, const char **argv);
#endif /* _NET_PROTO_H_ */
diff --git a/source3/wscript_build b/source3/wscript_build
index 80cdb9f..f58d0c5 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1123,6 +1123,7 @@ bld.SAMBA3_BINARY('net',
utils/net_rpc_trust.c
utils/net_rpc_conf.c
utils/net_afs.c
+ utils/net_notify.c
registry/reg_parse.c
registry/reg_format.c
registry/reg_import.c
--
1.7.9.5
From fd94413e624efc42729602421e9c199184740c55 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Jun 2015 14:57:14 +0000
Subject: [PATCH 19/20] notifyd: Add notiyfdd
A little standalone notify daemon to play around with.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/smbd/notifyd/notifydd.c | 83 ++++++++++++++++++++++++++++++++++++
source3/smbd/notifyd/wscript_build | 7 +++
2 files changed, 90 insertions(+)
create mode 100644 source3/smbd/notifyd/notifydd.c
diff --git a/source3/smbd/notifyd/notifydd.c b/source3/smbd/notifyd/notifydd.c
new file mode 100644
index 0000000..6856b3e
--- /dev/null
+++ b/source3/smbd/notifyd/notifydd.c
@@ -0,0 +1,83 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * 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 "replace.h"
+#include "notifyd.h"
+#include <tevent.h>
+#include "lib/util/tevent_unix.h"
+
+int main(int argc, const char *argv[])
+{
+ TALLOC_CTX *frame;
+ struct tevent_context *ev;
+ struct messaging_context *msg;
+ struct tevent_req *req;
+ int err, ret;
+ bool ok;
+
+ talloc_enable_leak_report_full();
+
+ frame = talloc_stackframe();
+
+ setup_logging("notifyd", DEBUG_DEFAULT_STDOUT);
+ lp_set_cmdline("log level", "10");
+
+ lp_load_initial_only(get_dyn_CONFIGFILE());
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ fprintf(stderr, "samba_tevent_context_init failed\n");
+ return 1;
+ }
+
+ msg = messaging_init(ev, ev);
+ if (msg == NULL) {
+ fprintf(stderr, "messaging_init failed\n");
+ return 1;
+ }
+
+ if (!lp_load_global(get_dyn_CONFIGFILE())) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ get_dyn_CONFIGFILE());
+ return 1;
+ }
+
+ req = notifyd_send(ev, ev, msg, messaging_ctdbd_connection(),
+ NULL, NULL);
+ if (req == NULL) {
+ fprintf(stderr, "notifyd_send failed\n");
+ return 1;
+ }
+
+ ok = tevent_req_poll_unix(req, ev, &err);
+ if (!ok) {
+ fprintf(stderr, "tevent_req_poll_unix failed: %s\n",
+ strerror(err));
+ return 1;
+ }
+
+ ret = notifyd_recv(req);
+
+ printf("notifyd_recv returned %d (%s)\n", ret,
+ ret ? strerror(ret) : "ok");
+
+ TALLOC_FREE(frame);
+
+ return 0;
+}
diff --git a/source3/smbd/notifyd/wscript_build b/source3/smbd/notifyd/wscript_build
index 90a9505..d9976bd 100644
--- a/source3/smbd/notifyd/wscript_build
+++ b/source3/smbd/notifyd/wscript_build
@@ -10,3 +10,10 @@ bld.SAMBA3_BINARY('notifyd-tests',
deps='''
param
''')
+
+bld.SAMBA3_BINARY('notifydd',
+ source='notifydd.c',
+ install=False,
+ deps='''notifyd
+ param
+ ''')
--
1.7.9.5
From 933c85ef7f8d7f78fdbcd9d2a669f8c9bf6465ab Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 3 May 2015 16:30:45 +0000
Subject: [PATCH 20/20] Remove ctdb_conn.[ch]
This was only used in notify_internal.c
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/lib/ctdb_conn.c | 547 ---------------------------------------
source3/lib/ctdb_conn.h | 65 -----
source3/lib/ctdb_dummy.c | 71 -----
source3/torture/proto.h | 1 -
source3/torture/test_ctdbconn.c | 239 -----------------
source3/torture/torture.c | 1 -
source3/wscript_build | 2 -
7 files changed, 926 deletions(-)
delete mode 100644 source3/lib/ctdb_conn.c
delete mode 100644 source3/lib/ctdb_conn.h
delete mode 100644 source3/torture/test_ctdbconn.c
diff --git a/source3/lib/ctdb_conn.c b/source3/lib/ctdb_conn.c
deleted file mode 100644
index 4e1b3e5..0000000
--- a/source3/lib/ctdb_conn.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Samba3 ctdb connection handling
- Copyright (C) Volker Lendecke 2012
-
- 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/util/tevent_unix.h"
-#include "ctdb_conn.h"
-
-#include <tdb.h>
-
-#include <ctdb_protocol.h>
-
-#include "lib/async_req/async_sock.h"
-
-struct ctdb_conn {
- int fd;
- struct tevent_queue *outqueue;
-};
-
-struct ctdb_conn_init_state {
- struct sockaddr_un addr;
- struct ctdb_conn *conn;
-};
-
-/*
- * use the callbacks of async_connect_send to make sure
- * we are connecting to CTDB as root
- */
-static void before_connect_cb(void *private_data) {
- become_root();
-}
-
-static void after_connect_cb(void *private_data) {
- unbecome_root();
-}
-
-static void ctdb_conn_init_done(struct tevent_req *subreq);
-static int ctdb_conn_destructor(struct ctdb_conn *conn);
-
-struct tevent_req *ctdb_conn_init_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- const char *sock)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_conn_init_state *state;
- size_t len;
-
- req = tevent_req_create(mem_ctx, &state, struct ctdb_conn_init_state);
- if (req == NULL) {
- return NULL;
- }
-
- if (!lp_clustering()) {
- tevent_req_error(req, ENOSYS);
- return tevent_req_post(req, ev);
- }
-
- state->conn = talloc(state, struct ctdb_conn);
- if (tevent_req_nomem(state->conn, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->conn->outqueue = tevent_queue_create(
- state->conn, "ctdb outqueue");
- if (tevent_req_nomem(state->conn->outqueue, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->conn->fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (state->conn->fd == -1) {
- tevent_req_error(req, errno);
- return tevent_req_post(req, ev);
- }
- talloc_set_destructor(state->conn, ctdb_conn_destructor);
-
- state->addr.sun_family = AF_UNIX;
-
- len = strlcpy(state->addr.sun_path, sock,
- sizeof(state->addr.sun_path));
- if (len >= sizeof(state->addr.sun_path)) {
- tevent_req_error(req, ENAMETOOLONG);
- return tevent_req_post(req, ev);
- }
-
- subreq = async_connect_send(state, ev, state->conn->fd,
- (struct sockaddr *)&state->addr,
- sizeof(state->addr), before_connect_cb,
- after_connect_cb, NULL);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_conn_init_done, req);
- return req;
-}
-
-static int ctdb_conn_destructor(struct ctdb_conn *c)
-{
- if (c->fd != -1) {
- close(c->fd);
- c->fd = -1;
- }
- return 0;
-}
-
-static void ctdb_conn_init_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- int ret, err;
-
- ret = async_connect_recv(subreq, &err);
- TALLOC_FREE(subreq);
- if (ret == -1) {
- tevent_req_error(req, err);
- return;
- }
- tevent_req_done(req);
-}
-
-int ctdb_conn_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_conn **pconn)
-{
- struct ctdb_conn_init_state *state = tevent_req_data(
- req, struct ctdb_conn_init_state);
- int err;
-
- if (tevent_req_is_unix_error(req, &err)) {
- return err;
- }
- *pconn = talloc_move(mem_ctx, &state->conn);
-
- return 0;
-}
-
-struct ctdb_conn_control_state {
- struct tevent_context *ev;
- struct ctdb_conn *conn;
- struct ctdb_req_control req;
- struct iovec iov[2];
- struct ctdb_reply_control *reply;
-};
-
-static void ctdb_conn_control_written(struct tevent_req *subreq);
-static void ctdb_conn_control_done(struct tevent_req *subreq);
-static ssize_t ctdb_packet_more(uint8_t *buf, size_t buflen, void *p);
-
-struct tevent_req *ctdb_conn_control_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_conn *conn,
- uint32_t vnn, uint32_t opcode,
- uint64_t srvid, uint32_t flags,
- uint8_t *data, size_t datalen)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_conn_control_state *state;
- struct ctdb_req_header *hdr;
-
- req = tevent_req_create(mem_ctx, &state,
- struct ctdb_conn_control_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->conn = conn;
-
- hdr = &state->req.hdr;
- hdr->length = offsetof(struct ctdb_req_control, data) + datalen;
- hdr->ctdb_magic = CTDB_MAGIC;
- hdr->ctdb_version = CTDB_PROTOCOL;
- hdr->operation = CTDB_REQ_CONTROL;
- hdr->reqid = 1; /* FIXME */
- hdr->destnode = vnn;
- state->req.opcode = opcode;
- state->req.srvid = srvid;
- state->req.datalen = datalen;
- state->req.flags = flags;
-
- state->iov[0].iov_base = &state->req;
- state->iov[0].iov_len = offsetof(struct ctdb_req_control, data);
- state->iov[1].iov_base = data;
- state->iov[1].iov_len = datalen;
-
- subreq = writev_send(state, ev, conn->outqueue, conn->fd, false,
- state->iov, 2);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_conn_control_written, req);
- return req;
-}
-
-static void ctdb_conn_control_written(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_control_state *state = tevent_req_data(
- req, struct ctdb_conn_control_state);
- ssize_t written;
- int err;
-
- written = writev_recv(subreq, &err);
- TALLOC_FREE(subreq);
- if (written == -1) {
- tevent_req_error(req, err);
- return;
- }
- subreq = read_packet_send(
- state, state->ev, state->conn->fd, sizeof(uint32_t),
- ctdb_packet_more, NULL);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_control_done, req);
-}
-
-static ssize_t ctdb_packet_more(uint8_t *buf, size_t buflen, void *p)
-{
- uint32_t len;
-
- if (buflen > sizeof(uint32_t)) {
- /* Been here, done */
- return 0;
- }
- memcpy(&len, buf, sizeof(len));
-
- if (len < sizeof(uint32_t)) {
- return -1;
- }
-
- return (len - sizeof(uint32_t));
-}
-
-static void ctdb_conn_control_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_control_state *state = tevent_req_data(
- req, struct ctdb_conn_control_state);
- ssize_t nread;
- uint8_t *buf;
- int err;
-
- nread = read_packet_recv(subreq, state, &buf, &err);
- TALLOC_FREE(subreq);
- if (nread == -1) {
- tevent_req_error(req, err);
- return;
- }
- state->reply = (struct ctdb_reply_control *)buf;
- tevent_req_done(req);
-}
-
-int ctdb_conn_control_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_reply_control **preply)
-{
- struct ctdb_conn_control_state *state = tevent_req_data(
- req, struct ctdb_conn_control_state);
- int err;
-
- if (tevent_req_is_unix_error(req, &err)) {
- return err;
- }
- if (preply != NULL) {
- *preply = talloc_move(mem_ctx, &state->reply);
- }
- return 0;
-}
-
-struct ctdb_conn_msg_write_state {
- struct ctdb_req_message ctdb_msg;
- struct iovec iov[2];
-};
-
-static void ctdb_conn_msg_write_done(struct tevent_req *subreq);
-
-struct tevent_req *ctdb_conn_msg_write_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_conn *conn,
- uint32_t vnn, uint64_t srvid,
- uint8_t *msg, size_t msg_len)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_conn_msg_write_state *state;
- struct ctdb_req_header *h;
-
- req = tevent_req_create(mem_ctx, &state,
- struct ctdb_conn_msg_write_state);
- if (req == NULL) {
- return NULL;
- }
-
- h = &state->ctdb_msg.hdr;
-
- h->length = offsetof(struct ctdb_req_message, data) + msg_len;
- h->ctdb_magic = CTDB_MAGIC;
- h->ctdb_version = CTDB_PROTOCOL;
- h->generation = 1;
- h->operation = CTDB_REQ_MESSAGE;
- h->destnode = vnn;
- h->srcnode = CTDB_CURRENT_NODE;
- h->reqid = 0;
- state->ctdb_msg.srvid = srvid;
- state->ctdb_msg.datalen = msg_len;
-
- state->iov[0].iov_base = &state->ctdb_msg;
- state->iov[0].iov_len = offsetof(struct ctdb_req_message, data);
- state->iov[1].iov_base = msg;
- state->iov[1].iov_len = msg_len;
-
- subreq = writev_send(state, ev, conn->outqueue, conn->fd, false,
- state->iov, 2);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_conn_msg_write_done, req);
- return req;
-}
-
-static void ctdb_conn_msg_write_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- ssize_t written;
- int err;
-
- written = writev_recv(subreq, &err);
- TALLOC_FREE(subreq);
- if (written == -1) {
- tevent_req_error(req, err);
- return;
- }
- tevent_req_done(req);
-}
-
-int ctdb_conn_msg_write_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_unix(req);
-}
-
-struct ctdb_msg_channel {
- struct ctdb_conn *conn;
-};
-
-struct ctdb_msg_channel_init_state {
- struct tevent_context *ev;
- struct ctdb_conn *conn;
- uint64_t srvid;
- struct ctdb_msg_channel *channel;
-};
-
-static void ctdb_msg_channel_init_connected(struct tevent_req *subreq);
-static void ctdb_msg_channel_init_registered_srvid(struct tevent_req *subreq);
-
-struct tevent_req *ctdb_msg_channel_init_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- const char *sock, uint64_t srvid)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_msg_channel_init_state *state;
-
- req = tevent_req_create(mem_ctx, &state,
- struct ctdb_msg_channel_init_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->srvid = srvid;
-
- subreq = ctdb_conn_init_send(state, ev, sock);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_msg_channel_init_connected, req);
- return req;
-}
-
-static void ctdb_msg_channel_init_connected(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_msg_channel_init_state *state = tevent_req_data(
- req, struct ctdb_msg_channel_init_state);
- int ret;
-
- ret = ctdb_conn_init_recv(subreq, state, &state->conn);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- subreq = ctdb_conn_control_send(state, state->ev, state->conn,
- CTDB_CURRENT_NODE,
- CTDB_CONTROL_REGISTER_SRVID,
- state->srvid, 0, NULL, 0);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(
- subreq, ctdb_msg_channel_init_registered_srvid, req);
-}
-
-static void ctdb_msg_channel_init_registered_srvid(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_msg_channel_init_state *state = tevent_req_data(
- req, struct ctdb_msg_channel_init_state);
- struct ctdb_reply_control *reply;
- int ret;
-
- ret = ctdb_conn_control_recv(subreq, talloc_tos(), &reply);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- if (reply->status != 0) {
- tevent_req_error(req, EIO);
- return;
- }
- state->channel = talloc(state, struct ctdb_msg_channel);
- if (tevent_req_nomem(state->channel, req)) {
- return;
- }
- state->channel->conn = talloc_move(state->channel, &state->conn);
- tevent_req_done(req);
-}
-
-int ctdb_msg_channel_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_msg_channel **pchannel)
-{
- struct ctdb_msg_channel_init_state *state = tevent_req_data(
- req, struct ctdb_msg_channel_init_state);
- int err;
-
- if (tevent_req_is_unix_error(req, &err)) {
- return err;
- }
- *pchannel = talloc_move(mem_ctx, &state->channel);
- return 0;
-}
-
-struct ctdb_msg_read_state {
- size_t buflen;
- uint8_t *buf;
-};
-
-static void ctdb_msg_channel_got_msg(struct tevent_req *subreq);
-
-struct tevent_req *ctdb_msg_read_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_msg_channel *channel)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_msg_read_state *state;
-
- req = tevent_req_create(mem_ctx, &state,
- struct ctdb_msg_read_state);
- if (req == NULL) {
- return NULL;
- }
- subreq = read_packet_send(state, ev, channel->conn->fd,
- sizeof(uint32_t), ctdb_packet_more, NULL);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_msg_channel_got_msg, req);
- return req;
-}
-
-static void ctdb_msg_channel_got_msg(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_msg_read_state *state = tevent_req_data(
- req, struct ctdb_msg_read_state);
- ssize_t nread;
- uint8_t *buf;
- int err;
-
- nread = read_packet_recv(subreq, state, &buf, &err);
- if (nread == -1) {
- tevent_req_error(req, err);
- return;
- }
- state->buflen = nread;
- state->buf = buf;
- tevent_req_done(req);
-}
-
-int ctdb_msg_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- uint8_t **pmsg, size_t *pmsg_len)
-{
- struct ctdb_msg_read_state *state = tevent_req_data(
- req, struct ctdb_msg_read_state);
- struct ctdb_req_header *hdr;
- struct ctdb_req_message *msg;
- uint8_t *buf;
- int err;
-
- if (tevent_req_is_unix_error(req, &err)) {
- return err;
- }
-
- hdr = (struct ctdb_req_header *)state->buf;
- if (hdr->length != state->buflen) {
- DEBUG(10, ("Got invalid header length\n"));
- return EIO;
- }
- if (hdr->operation != CTDB_REQ_MESSAGE) {
- DEBUG(10, ("Expected %d (CTDB_REQ_MESSAGE), got %d\n",
- CTDB_REQ_MESSAGE, (int)hdr->operation));
- return EIO;
- }
- if (hdr->length < offsetof(struct ctdb_req_message, data)) {
- DEBUG(10, ("Got short msg, len=%d\n", (int)hdr->length));
- return EIO;
- }
-
- msg = (struct ctdb_req_message *)hdr;
- if (msg->datalen >
- hdr->length - offsetof(struct ctdb_req_message, data)) {
- DEBUG(10, ("Got invalid datalen %d\n", (int)msg->datalen));
- return EIO;
- }
-
- buf = (uint8_t *)talloc_memdup(mem_ctx, msg->data, msg->datalen);
- if (buf == NULL) {
- return ENOMEM;
- }
- *pmsg = buf;
- *pmsg_len = msg->datalen;
- return 0;
-}
diff --git a/source3/lib/ctdb_conn.h b/source3/lib/ctdb_conn.h
deleted file mode 100644
index 21a69c7..0000000
--- a/source3/lib/ctdb_conn.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Samba3 ctdb connection handling
- Copyright (C) Volker Lendecke 2012
-
- 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/>.
-*/
-
-#ifndef _CTDB_CONN_H
-#define _CTDB_CONN_H
-
-#include "tevent.h"
-#include "librpc/gen_ndr/messaging.h"
-
-struct ctdb_conn;
-struct ctdb_reply_control;
-
-struct tevent_req *ctdb_conn_control_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_conn *conn,
- uint32_t vnn, uint32_t opcode,
- uint64_t srvid, uint32_t flags,
- uint8_t *data, size_t datalen);
-int ctdb_conn_control_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_reply_control **preply);
-
-struct tevent_req *ctdb_conn_init_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- const char *sock);
-int ctdb_conn_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_conn **pconn);
-
-struct tevent_req *ctdb_conn_msg_write_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_conn *conn,
- uint32_t vnn, uint64_t srvid,
- uint8_t *msg, size_t msg_len);
-int ctdb_conn_msg_write_recv(struct tevent_req *req);
-
-struct ctdb_msg_channel;
-
-struct tevent_req *ctdb_msg_channel_init_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- const char *sock, uint64_t srvid);
-int ctdb_msg_channel_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_msg_channel **pchannel);
-
-struct tevent_req *ctdb_msg_read_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_msg_channel *channel);
-int ctdb_msg_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- uint8_t **pmsg, size_t *pmsg_len);
-
-#endif /* _CTDB_CONN_H */
diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 2df6c28..abefa00 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -19,7 +19,6 @@
#include "includes.h"
#include "messages.h"
-#include "ctdb_conn.h"
#include "ctdbd_conn.h"
#include "lib/dbwrap/dbwrap.h"
#include "lib/dbwrap/dbwrap_ctdb.h"
@@ -81,76 +80,6 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
return false;
}
-struct dummy_state {
- uint8_t dummy;
-};
-
-static struct tevent_req *dummy_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev)
-{
- struct tevent_req *req;
- struct dummy_state *state;
- req = tevent_req_create(mem_ctx, &state, struct dummy_state);
- if (req == NULL) {
- return NULL;
- }
- tevent_req_done(req);
- return tevent_req_post(req, ev);
-}
-
-struct tevent_req *ctdb_conn_init_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- const char *sock)
-{
- return dummy_send(mem_ctx, ev);
-}
-
-int ctdb_conn_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_conn **pconn)
-{
- return ENOSYS;
-}
-
-struct tevent_req *ctdb_conn_msg_write_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_conn *conn,
- uint32_t vnn, uint64_t srvid,
- uint8_t *msg, size_t msg_len)
-{
- return dummy_send(mem_ctx, ev);
-}
-
-int ctdb_conn_msg_write_recv(struct tevent_req *req)
-{
- return ENOSYS;
-}
-
-struct tevent_req *ctdb_msg_channel_init_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- const char *sock, uint64_t srvid)
-{
- return dummy_send(mem_ctx, ev);
-}
-
-int ctdb_msg_channel_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct ctdb_msg_channel **pchannel)
-{
- return ENOSYS;
-}
-
-struct tevent_req *ctdb_msg_read_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct ctdb_msg_channel *channel)
-{
- return dummy_send(mem_ctx, ev);
-}
-
-int ctdb_msg_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- uint8_t **pmsg, size_t *pmsg_len)
-{
- return ENOSYS;
-}
-
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
const char *name,
int hash_size, int tdb_flags,
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index ab422d5..fc7c33f 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -105,7 +105,6 @@ bool run_cleanup1(int dummy);
bool run_cleanup2(int dummy);
bool run_cleanup3(int dummy);
bool run_cleanup4(int dummy);
-bool run_ctdb_conn(int dummy);
bool run_notify_bench2(int dummy);
bool run_notify_bench3(int dummy);
bool run_dbwrap_watch1(int dummy);
diff --git a/source3/torture/test_ctdbconn.c b/source3/torture/test_ctdbconn.c
deleted file mode 100644
index 1f80cff..0000000
--- a/source3/torture/test_ctdbconn.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Test new ctdb API
- Copyright (C) Volker Lendecke 2012
-
- 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 "torture/proto.h"
-
-#include "ctdb_conn.h"
-#include "ctdbd_conn.h"
-#include "lib/util/tevent_unix.h"
-#include "tdb.h"
-
-#include "ctdb_protocol.h"
-
-#include "messages.h"
-
-struct ctdb_conn_test_state {
- struct tevent_context *ev;
- struct ctdb_conn *conn;
- struct ctdb_msg_channel *channel;
- int msgno;
-};
-
-static void ctdb_conn_test_got_conn(struct tevent_req *subreq);
-static void ctdb_conn_test_got_pnn(struct tevent_req *subreq);
-static void ctdb_conn_test_got_channel(struct tevent_req *subreq);
-static void ctdb_conn_test_got_msg(struct tevent_req *subreq);
-static void ctdb_conn_test_msg_sent(struct tevent_req *subreq);
-
-static struct tevent_req *ctdb_conn_test_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev)
-{
- struct tevent_req *req, *subreq;
- struct ctdb_conn_test_state *state;
-
- req = tevent_req_create(mem_ctx, &state, struct ctdb_conn_test_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
-
- subreq = ctdb_conn_init_send(mem_ctx, ev, lp_ctdbd_socket());
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_got_conn, req);
- return req;
-}
-
-static void ctdb_conn_test_got_conn(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_test_state *state = tevent_req_data(
- req, struct ctdb_conn_test_state);
- uint64_t ret;
-
- ret = ctdb_conn_init_recv(subreq, state, &state->conn);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- subreq = ctdb_conn_control_send(state, state->ev, state->conn,
- CTDB_CURRENT_NODE,
- CTDB_CONTROL_GET_PNN, 0, 0, NULL, 0);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_got_pnn, req);
-}
-
-static void ctdb_conn_test_got_pnn(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_test_state *state = tevent_req_data(
- req, struct ctdb_conn_test_state);
- int ret;
- struct ctdb_reply_control *reply;
-
- ret = ctdb_conn_control_recv(subreq, talloc_tos(), &reply);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- printf("vnn=%d\n", (int)reply->status);
-
- subreq = ctdb_msg_channel_init_send(
- state, state->ev, lp_ctdbd_socket(), 999999);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_got_channel, req);
-}
-
-static void ctdb_conn_test_got_channel(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_test_state *state = tevent_req_data(
- req, struct ctdb_conn_test_state);
- int ret;
-
- ret = ctdb_msg_channel_init_recv(subreq, state, &state->channel);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
-
- subreq = ctdb_msg_read_send(state, state->ev, state->channel);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_got_msg, req);
-
- state->msgno += 1;
-
- subreq = ctdb_conn_msg_write_send(
- state, state->ev, state->conn, CTDB_CURRENT_NODE, 999999,
- (uint8_t *)&state->msgno, sizeof(state->msgno));
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_msg_sent, req);
-}
-
-static void ctdb_conn_test_got_msg(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_test_state *state = tevent_req_data(
- req, struct ctdb_conn_test_state);
- uint8_t *buf;
- size_t buf_len;
- int ret;
-
- ret = ctdb_msg_read_recv(subreq, talloc_tos(), &buf, &buf_len);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- if (buf_len != sizeof(int)) {
- printf("got invalid msg\n");
- tevent_req_error(req, EINVAL);
- return;
- }
- memcpy(&ret, buf, buf_len);
- printf("got msg %d\n", ret);
- if (ret == 5) {
- tevent_req_done(req);
- return;
- }
-
- subreq = ctdb_msg_read_send(state, state->ev, state->channel);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_got_msg, req);
-}
-
-static void ctdb_conn_test_msg_sent(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct ctdb_conn_test_state *state = tevent_req_data(
- req, struct ctdb_conn_test_state);
- int ret;
-
- ret = ctdb_conn_msg_write_recv(subreq);
- TALLOC_FREE(subreq);
- if (tevent_req_error(req, ret)) {
- return;
- }
- state->msgno += 1;
-
- if (state->msgno >= 10) {
- return;
- }
-
- subreq = ctdb_conn_msg_write_send(
- state, state->ev, state->conn, CTDB_CURRENT_NODE, 999999,
- (uint8_t *)&state->msgno, sizeof(state->msgno));
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, ctdb_conn_test_msg_sent, req);
-}
-
-static int ctdb_conn_test_recv(struct tevent_req *req)
-{
- int err;
- if (tevent_req_is_unix_error(req, &err)) {
- return err;
- }
- return 0;
-}
-
-bool run_ctdb_conn(int dummy)
-{
- struct tevent_context *ev;
- struct tevent_req *req;
- int ret;
-
- ev = samba_tevent_context_init(talloc_tos());
- if (ev == NULL) {
- fprintf(stderr, "tevent_context_init failed\n");
- return false;
- }
- req = ctdb_conn_test_send(ev, ev);
- if (req == NULL) {
- fprintf(stderr, "ctdb_conn_test_send failed\n");
- return false;
- }
- if (!tevent_req_poll(req, ev)) {
- fprintf(stderr, "tevent_req_poll failed\n");
- return false;
- }
- ret = ctdb_conn_test_recv(req);
- TALLOC_FREE(req);
- printf("ctdb_conn_test returned %s\n",
- ret ? strerror(ret) : "success");
- TALLOC_FREE(ev);
- return (ret == 0);
-}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index d5ec4c6..bfd04f4 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -9597,7 +9597,6 @@ static struct {
{ "LOCAL-SUBSTITUTE", run_local_substitute, 0},
{ "LOCAL-GENCACHE", run_local_gencache, 0},
{ "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0},
- { "LOCAL-CTDB-CONN", run_ctdb_conn, 0},
{ "LOCAL-DBWRAP-WATCH1", run_dbwrap_watch1, 0 },
{ "LOCAL-MESSAGING-READ1", run_messaging_read1, 0 },
{ "LOCAL-MESSAGING-READ2", run_messaging_read2, 0 },
diff --git a/source3/wscript_build b/source3/wscript_build
index f58d0c5..df894d5 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -272,8 +272,6 @@ if bld.CONFIG_GET("CTDB_CFLAGS") and bld.CONFIG_GET("CTDB_INCLUDE"):
lib/dbwrap/dbwrap_ctdb.c
lib/messages_ctdbd.c
lib/ctdbd_conn.c
- lib/ctdb_conn.c
- torture/test_ctdbconn.c
'''
SAMBA_CLUSTER_SUPPORT_DEPS='''
talloc
--
1.7.9.5
More information about the samba-technical
mailing list