notifyd
Volker Lendecke
Volker.Lendecke at SerNet.DE
Fri Jan 9 09:56:44 MST 2015
Hi!
Attached find the notifyd work, rebased on top of current
master. I know it does not have signed-off by tags
everywhere yet, but I think it's in pretty good shape. So
everyone interested in faster clustered change notify with
clustered inotify, please take a look :-)
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 87099e556219061a1a9b47af5a6d435761882d85 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 25 Nov 2014 18:50:25 +0100
Subject: [PATCH 01/15] unix_msg: Fix 80-line formatting
This is pretty fresh code, so hope this change does not fall under the "no
reformatting" rule yet
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/lib/unix_msg/unix_msg.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/source3/lib/unix_msg/unix_msg.c b/source3/lib/unix_msg/unix_msg.c
index 51bb0c6..e4eed1c 100644
--- a/source3/lib/unix_msg/unix_msg.c
+++ b/source3/lib/unix_msg/unix_msg.c
@@ -922,7 +922,8 @@ static void unix_msg_recv(struct unix_dgram_ctx *dgram_ctx,
buflen -= sizeof(cookie);
if (cookie == 0) {
- ctx->recv_callback(ctx, buf, buflen, fds, num_fds, ctx->private_data);
+ ctx->recv_callback(ctx, buf, buflen, fds, num_fds,
+ ctx->private_data);
return;
}
@@ -974,7 +975,8 @@ static void unix_msg_recv(struct unix_dgram_ctx *dgram_ctx,
}
DLIST_REMOVE(ctx->msgs, msg);
- ctx->recv_callback(ctx, msg->buf, msg->msglen, fds, num_fds, ctx->private_data);
+ ctx->recv_callback(ctx, msg->buf, msg->msglen, fds, num_fds,
+ ctx->private_data);
free(msg);
return;
--
1.9.1
From b4b7a4c868b1f5879dd1cf17ff13f126fe82da24 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 21 Dec 2014 14:52:17 +0100
Subject: [PATCH 02/15] lib: Simplify iov_buf
According to
https://www.securecoding.cert.org/confluence/display/seccode/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
we only need to check against one operand.
Signed-off-by: Volker Lendecke <vl at samba.org>
---
source3/lib/iov_buf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/source3/lib/iov_buf.c b/source3/lib/iov_buf.c
index f0e05a6..82a4af5 100644
--- a/source3/lib/iov_buf.c
+++ b/source3/lib/iov_buf.c
@@ -39,8 +39,8 @@ ssize_t iov_buf(const struct iovec *iov, int iovcnt,
tmp = needed + thislen;
- if ((tmp < needed) || (tmp < thislen)) {
- /* overflow */
+ if (tmp < needed) {
+ /* wrap */
return -1;
}
needed = tmp;
--
1.9.1
From 42a873715d01086b464d071177921d269f7f0295 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 03/15] param: Make "change notify" global
---
docs-xml/smbdotconf/misc/changenotify.xml | 3 +--
lib/param/param_table.c | 6 +++---
source3/param/loadparm.c | 3 ++-
source3/smbd/service.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs-xml/smbdotconf/misc/changenotify.xml b/docs-xml/smbdotconf/misc/changenotify.xml
index 3a2debb..91e0c8d 100644
--- a/docs-xml/smbdotconf/misc/changenotify.xml
+++ b/docs-xml/smbdotconf/misc/changenotify.xml
@@ -1,8 +1,7 @@
<samba:parameter name="change notify"
- context="S"
+ context="G"
type="boolean"
advanced="1"
- 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 18b0628..bfb66e7 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -1800,11 +1800,11 @@ 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,
- .flags = FLAG_ADVANCED | FLAG_SHARE,
+ .flags = FLAG_ADVANCED,
},
{
.label = "directory name cache size",
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index da50e3a..3fb7a3f 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -236,7 +236,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,
@@ -719,6 +718,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 3fd0fc8..7f24797 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.9.1
From c93f47144ae3f29cd229cf15390b9deb06aa4a52 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 04/15] make "kernel change notify" global
---
docs-xml/smbdotconf/misc/kernelchangenotify.xml | 3 +--
lib/param/param_table.c | 6 +++---
source3/modules/vfs_default.c | 2 +-
source3/param/loadparm.c | 2 +-
4 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/docs-xml/smbdotconf/misc/kernelchangenotify.xml b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
index e90f845..70ccfd5 100644
--- a/docs-xml/smbdotconf/misc/kernelchangenotify.xml
+++ b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
@@ -1,8 +1,7 @@
<samba:parameter name="kernel change notify"
- context="S"
+ context="G"
type="boolean"
advanced="1"
- 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 bfb66e7..5f7b9ef 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -1818,11 +1818,11 @@ 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,
- .flags = FLAG_ADVANCED | FLAG_SHARE,
+ .flags = FLAG_ADVANCED,
},
{
.label = "lpq cache time",
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 5634cc0..69af305 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -2118,7 +2118,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 3fb7a3f..a5797c4 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -236,7 +236,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,
@@ -719,6 +718,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.9.1
From 5488f260d303a924b45ceade507c82431f7afa8e 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 05/15] 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.
---
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..e3e1b12
--- /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 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 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 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 121682c..16e87f8 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -542,6 +542,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 a6ef584..73a6d57 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -506,6 +506,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
@@ -626,7 +629,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.9.1
From fac3d887979422021d1a0082a6921e63c09796a0 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 06/15] 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.
---
source3/librpc/idl/messaging.idl | 13 +
source3/smbd/notifyd/notifyd.c | 1493 ++++++++++++++++++++++++++++++++++++
source3/smbd/notifyd/notifyd.h | 142 ++++
source3/smbd/notifyd/tests.c | 119 +++
source3/smbd/notifyd/wscript_build | 12 +
source3/wscript_build | 1 +
6 files changed, 1780 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/source3/librpc/idl/messaging.idl b/source3/librpc/idl/messaging.idl
index ce40a7b..cd9c913 100644
--- a/source3/librpc/idl/messaging.idl
+++ b/source3/librpc/idl/messaging.idl
@@ -96,6 +96,13 @@ interface messaging
MSG_SMB_TELL_NUM_CHILDREN = 0x0317,
MSG_SMB_NUM_CHILDREN = 0x0318,
+ /* notifyd messages */
+ MSG_SMB_NOTIFY_REC_CHANGE = 0x0319,
+ MSG_SMB_NOTIFY_TRIGGER = 0x031A,
+ MSG_SMB_NOTIFY_GET_DB = 0x031B,
+ MSG_SMB_NOTIFY_DB = 0x031C,
+ MSG_SMB_NOTIFY_REC_CHANGES = 0x031D,
+
/* winbind messages */
MSG_WINBIND_FINISHED = 0x0401,
MSG_WINBIND_FORGET_STATE = 0x0402,
@@ -133,4 +140,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..8c4a4ae
--- /dev/null
+++ b/source3/smbd/notifyd/notifyd.c
@@ -0,0 +1,1493 @@
+/*
+ * 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"
+
+/*
+ * 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;
+};
+
+/*
+ * Record held per path
+ */
+struct notifyd_entry {
+ struct notifyd_instance instances[1]; /* we allocate more */
+};
+
+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 void notifyd_broadcast_reclog(struct server_id src,
+ struct messaging_reclog *log);
+
+struct notifyd_peer {
+ struct messaging_context *msg_ctx;
+ uint32_t vnn;
+
+ uint64_t rec_index;
+ struct db_context *db;
+};
+
+struct notifyd_peers {
+ uint32_t num_peers;
+ struct notifyd_peer **peers;
+};
+
+static struct tevent_req *notifyd_broadcast_reclog_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct server_id src,
+ struct messaging_reclog *log);
+static int notifyd_broadcast_reclog_recv(struct tevent_req *req);
+
+static struct tevent_req *notifyd_snoop_peers_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx,
+ struct notifyd_peers *peers);
+static int notifyd_snoop_peers_recv(struct tevent_req *req);
+
+struct notifyd_state {
+ struct tevent_context *ev;
+ struct messaging_context *msg_ctx;
+ struct db_context *entries;
+ struct notifyd_peers *peers;
+
+ sys_notify_watch_fn sys_notify_watch;
+ struct sys_notify_context *sys_notify_ctx;
+
+ struct messaging_reclog *log;
+};
+
+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_snoop_peers_finished(struct tevent_req *subreq);
+static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq);
+
+struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ 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;
+ struct ctdbd_connection *ctdbd_conn;
+ 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;
+
+ 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);
+
+ names_db = messaging_names_db(msg_ctx);
+
+ ret = server_id_db_add(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);
+ }
+
+ ctdbd_conn = messaging_ctdbd_connection();
+ if (ctdbd_conn == NULL) {
+ /*
+ * No cluster around, skip the db 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, 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);
+
+ status = register_with_ctdbd(ctdbd_conn,
+ CTDB_SRVID_SAMBA_NOTIFY_PROXY);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_error(req, map_errno_from_nt_status(status));
+ return tevent_req_post(req, ev);
+ }
+
+ state->peers = talloc_zero(state, struct notifyd_peers);
+ if (tevent_req_nomem(state->peers, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = notifyd_snoop_peers_send(
+ state, ev, msg_ctx,
+ state->sys_notify_watch, state->sys_notify_ctx,
+ state->peers);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_snoop_peers_finished, req);
+
+ 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_snoop_peers_finished(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+
+ ret = notifyd_snoop_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_entry **entry,
+ size_t *num_instances)
+{
+ size_t instances_len;
+
+ if (buflen < offsetof(struct notifyd_entry, instances)) {
+ DEBUG(1, ("%s: buffer too short: %u\n",
+ __func__, (unsigned)buflen));
+ return false;
+ }
+
+ instances_len = buflen - offsetof(struct notifyd_entry, instances);
+ if ((instances_len % sizeof(struct notifyd_instance)) != 0) {
+ DEBUG(1, ("%s: invalid buffer size: %u\n",
+ __func__, (unsigned)buflen));
+ return false;
+ }
+
+ if (entry != NULL) {
+ *entry = (struct notifyd_entry *)buf;
+ }
+ if (num_instances != NULL) {
+ *num_instances =
+ instances_len / sizeof(struct notifyd_instance);
+ }
+ return true;
+}
+
+static size_t notifyd_entry_size(size_t num_instances)
+{
+ return offsetof(struct notifyd_entry, instances) +
+ (sizeof(struct notifyd_instance) * num_instances);
+}
+
+static void notifyd_sys_callback(struct sys_notify_context *ctx,
+ void *private_data, struct notify_event *ev);
+
+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_entry *entry;
+ 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
+ */
+ entry = talloc_size(rec, notifyd_entry_size(num_instances+1));
+ if (entry == NULL) {
+ DEBUG(1, ("%s: talloc failed\n", __func__));
+ goto fail;
+ }
+
+ if (value.dsize != 0) {
+ memcpy(entry, value.dptr, value.dsize);
+ }
+
+ for (i=0; i<num_instances; i++) {
+ instance = &entry->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 = &entry->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 = entry->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 *)entry, notifyd_entry_size(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) {
+ 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 >= 1000) {
+ /*
+ * Don't let the log grow too large
+ */
+ notifyd_broadcast_reclog(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, 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->peers->num_peers; i++) {
+ if (state->peers->peers[i]->db == NULL) {
+ /*
+ * Inactive peer, did not get a db yet
+ */
+ continue;
+ }
+ dbwrap_parse_record(state->peers->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;
+ struct iovec iov[2];
+ size_t path_len = key.dsize;
+ struct notifyd_entry *entry = NULL;
+ size_t num_instances = 0;
+ size_t i;
+
+ if (!notifyd_parse_entry(data.dptr, data.dsize, &entry,
+ &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));
+
+ msg = (struct notify_event_msg) {
+ .action = tstate->msg->action
+ };
+
+ 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 = &entry->instances[i];
+ 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);
+
+ 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)));
+ }
+ }
+}
+
+static void notifyd_send_delete(struct messaging_context *msg_ctx,
+ TDB_DATA key,
+ struct notifyd_instance *instance)
+{
+ struct notify_rec_change_msg msg = {};
+ char path[key.dsize+1];
+ struct iovec iov[2];
+ NTSTATUS status;
+
+ msg.instance.private_data = instance->instance.private_data;
+ memcpy(path, key.dptr, key.dsize);
+ path[key.dsize] = 0;
+
+ 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 = sizeof(path);
+
+ 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;
+ size_t dbsize;
+ uint8_t *buf;
+
+ dbsize = dbwrap_marshall(state->entries, NULL, 0);
+
+ buf = talloc_array(rec, uint8_t, dbsize+8);
+ if (buf == NULL) {
+ DEBUG(1, ("%s: talloc_array(%ju) failed\n",
+ __func__, (uintmax_t)dbsize+8));
+ return true;
+ }
+
+ if (state->log != NULL) {
+ rec_index = state->log->rec_index;
+ }
+ SBVAL(buf, 0, rec_index);
+
+ dbsize = dbwrap_marshall(state->entries, buf+8, dbsize);
+
+ if (dbsize != (talloc_get_size(buf)-8)) {
+ DEBUG(1, ("%s: dbsize changed: %ju->%ju\n", __func__,
+ (uintmax_t)(talloc_get_size(buf)-8),
+ (uintmax_t)dbsize));
+ TALLOC_FREE(buf);
+ return true;
+ }
+
+ DEBUG(10, ("%s: Sending %u bytes to %s->%s\n", __func__,
+ (unsigned)talloc_get_size(buf),
+ server_id_str_buf(messaging_server_id(msg_ctx), &id1),
+ server_id_str_buf(rec->src, &id2)));
+
+ status = messaging_send_buf(msg_ctx, rec->src, MSG_SMB_NOTIFY_DB,
+ buf, talloc_get_size(buf));
+ TALLOC_FREE(buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: messaging_send_buf failed: %s\n",
+ __func__, nt_errstr(status)));
+ }
+
+ return true;
+}
+
+static void notifyd_broadcast_reclog(struct server_id src,
+ struct messaging_reclog *log)
+{
+ struct ctdbd_connection *ctdbd_conn;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct messaging_rec msg;
+
+ if (log == NULL) {
+ return;
+ }
+
+ DEBUG(10, ("%s: rec_index=%ju, num_recs=%u\n", __func__,
+ (uintmax_t)log->rec_index, (unsigned)log->num_recs));
+
+ ctdbd_conn = messaging_ctdbd_connection();
+ if (ctdbd_conn == NULL) {
+ goto done;
+ }
+
+ msg = (struct messaging_rec) {
+ .msg_version = MESSAGE_VERSION,
+ .msg_type = MSG_SMB_NOTIFY_REC_CHANGES,
+ .src = src
+ };
+
+ ndr_err = ndr_push_struct_blob(
+ &msg.buf, 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;
+ }
+
+ status = ctdbd_messaging_send(
+ ctdbd_conn, CTDB_BROADCAST_VNNMAP,
+ CTDB_SRVID_SAMBA_NOTIFY_PROXY, &msg);
+ TALLOC_FREE(msg.buf.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_db_pull_state {
+ uint32_t vnn;
+ uint64_t rec_index;
+ struct db_context *db;
+};
+
+static bool notifyd_db_pull_filter(struct messaging_rec *req,
+ void *private_data);
+static void notifyd_db_pull_done(struct tevent_req *subreq);
+
+static struct tevent_req *notifyd_db_pull_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx, uint32_t vnn)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_db_pull_state *state;
+ struct ctdbd_connection *ctdbd_conn;
+ struct messaging_rec msg;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct notifyd_db_pull_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->vnn = vnn;
+
+ state->db = db_open_rbt(state);
+ if (tevent_req_nomem(state->db, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ctdbd_conn = messaging_ctdbd_connection();
+ if (ctdbd_conn == NULL) {
+ tevent_req_error(req, ENOSYS);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = messaging_filtered_read_send(
+ state, ev, msg_ctx, notifyd_db_pull_filter, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_db_pull_done, req);
+
+ msg = (struct messaging_rec) {
+ .msg_version = MESSAGE_VERSION,
+ .msg_type = MSG_SMB_NOTIFY_GET_DB,
+ .src = messaging_server_id(msg_ctx),
+ .buf = data_blob_null
+ };
+
+ status = ctdbd_messaging_send(
+ ctdbd_conn, vnn, CTDB_SRVID_SAMBA_NOTIFY_PROXY, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ int err = map_errno_from_nt_status(status);
+ tevent_req_error(req, err);
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static bool notifyd_db_pull_filter(struct messaging_rec *rec,
+ void *private_data)
+{
+ struct notifyd_db_pull_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_db_pull_state);
+
+ if (rec->num_fds != 0) {
+ return false;
+ }
+ if (rec->msg_type != MSG_SMB_NOTIFY_DB) {
+ return false;
+ }
+ return rec->src.vnn == state->vnn;
+}
+
+static void notifyd_db_pull_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_db_pull_state *state = tevent_req_data(
+ req, struct notifyd_db_pull_state);
+ struct server_id_buf idbuf;
+ struct messaging_rec *rec;
+ NTSTATUS status;
+ int ret;
+
+ ret = messaging_filtered_read_recv(subreq, state, &rec);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ DEBUG(10, ("%s: Got %u bytes from %s\n", __func__,
+ (unsigned)rec->buf.length,
+ server_id_str_buf(rec->src, &idbuf)));
+
+ if (rec->buf.length < 8) {
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ state->rec_index = BVAL(rec->buf.data, 0);
+
+ status = dbwrap_unmarshall(state->db, rec->buf.data + 8,
+ rec->buf.length - 8);
+ if (!NT_STATUS_IS_OK(status)) {
+ int err = map_errno_from_nt_status(status);
+ tevent_req_error(req, err);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int notifyd_db_pull_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint64_t *rec_index, struct db_context **db)
+{
+ struct notifyd_db_pull_state *state = tevent_req_data(
+ req, struct notifyd_db_pull_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+ if (rec_index != NULL) {
+ *rec_index = state->rec_index;
+ }
+ if (db != NULL) {
+ *db = talloc_move(mem_ctx, &state->db);
+ }
+ return 0;
+}
+
+struct notifyd_broadcast_reclog_state {
+ struct tevent_context *ev;
+ 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 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->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->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_peer_recv_state {
+ struct tevent_context *ev;
+ struct messaging_context *msg_ctx;
+ sys_notify_watch_fn sys_notify_watch;
+ struct sys_notify_context *sys_notify_ctx;
+ struct notifyd_peer *peer;
+};
+
+static void notifyd_peer_recv_got_db(struct tevent_req *subreq);
+static int notifyd_add_proxy_syswatches(struct db_record *rec,
+ void *private_data);
+static bool notifyd_peer_recv_filter_changes(struct messaging_rec *rec,
+ void *private_data);
+static void notifyd_peer_recv_got_changes(struct tevent_req *subreq);
+
+static struct tevent_req *notifyd_peer_recv_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx,
+ struct notifyd_peer *peer)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_peer_recv_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct notifyd_peer_recv_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->msg_ctx = msg_ctx;
+ state->sys_notify_watch = sys_notify_watch;
+ state->sys_notify_ctx = sys_notify_ctx;
+ state->peer = peer;
+
+ subreq = notifyd_db_pull_send(state, ev, msg_ctx, peer->vnn);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_peer_recv_got_db, req);
+
+ subreq = messaging_filtered_read_send(state, state->ev, state->msg_ctx,
+ notifyd_peer_recv_filter_changes,
+ peer);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_peer_recv_got_changes, req);
+
+ return req;
+}
+
+static void notifyd_peer_recv_got_db(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_peer_recv_state *state = tevent_req_data(
+ req, struct notifyd_peer_recv_state);
+ struct db_context *db = NULL;
+ uint64_t rec_index = 0;
+ int ret;
+
+ ret = notifyd_db_pull_recv(subreq, state->peer, &rec_index, &db);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ dbwrap_traverse_read(db, notifyd_add_proxy_syswatches, state, NULL);
+
+ TALLOC_FREE(state->peer->db);
+ state->peer->db = db;
+ state->peer->rec_index = rec_index;
+}
+
+static int notifyd_add_proxy_syswatches(struct db_record *rec,
+ void *private_data)
+{
+ struct notifyd_peer_recv_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_peer_recv_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_entry *entry;
+ size_t i, num_instances;
+ 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, &entry,
+ &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 = &entry->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 bool notifyd_peer_recv_filter_changes(struct messaging_rec *rec,
+ void *private_data)
+{
+ struct notifyd_peer *peer = talloc_get_type_abort(
+ private_data, struct notifyd_peer);
+
+ if (rec->num_fds != 0) {
+ return false;
+ }
+ if (rec->msg_type != MSG_SMB_NOTIFY_REC_CHANGES) {
+ return false;
+ }
+ if (rec->src.vnn != peer->vnn) {
+ return false;
+ }
+ if (peer->db == NULL) {
+ /*
+ * No db yet, we can't deal with the changes yet
+ */
+ return false;
+ }
+ return true;
+}
+
+static void notifyd_peer_recv_got_changes(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_peer_recv_state *state = tevent_req_data(
+ req, struct notifyd_peer_recv_state);
+ struct notifyd_peer *peer = state->peer;
+ struct messaging_rec *rec;
+ struct messaging_reclog *log;
+ struct server_id_buf idbuf;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+ int ret;
+
+ ret = messaging_filtered_read_recv(subreq, state, &rec);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ subreq = messaging_filtered_read_send(state, state->ev, state->msg_ctx,
+ notifyd_peer_recv_filter_changes,
+ peer);
+ if (tevent_req_nomem(subreq, req)) {
+ goto done;
+ }
+ tevent_req_set_callback(subreq, notifyd_peer_recv_got_changes, req);
+
+ log = talloc(rec, struct messaging_reclog);
+ if (log == NULL) {
+ DEBUG(10, ("%s: talloc failed\n", __func__));
+ goto done;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &rec->buf, 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 done;
+ }
+
+ 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(rec->src, &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(rec->src, &idbuf),
+ (uintmax_t)peer->rec_index));
+
+ subreq = notifyd_db_pull_send(state, state->ev, state->msg_ctx,
+ peer->vnn);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, notifyd_peer_recv_got_db, req);
+ return;
+ }
+
+ 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) {
+ tevent_req_error(req, EBADMSG);
+ return;
+ }
+
+ 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) {
+ tevent_req_error(req, EBADMSG);
+ return;
+ }
+ }
+
+ peer->rec_index += 1;
+
+done:
+ TALLOC_FREE(rec);
+}
+
+static int notifyd_peer_recv_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+static struct notifyd_peer *notifyd_peer_new(
+ TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx,
+ uint32_t vnn)
+{
+ struct notifyd_peer *peer;
+
+ peer = talloc_zero(mem_ctx, struct notifyd_peer);
+ if (peer == NULL) {
+ return NULL;
+ }
+ peer->msg_ctx = msg_ctx;
+ peer->vnn = vnn;
+
+ return peer;
+}
+
+struct notifyd_snoop_peers_state {
+ struct tevent_context *ev;
+ struct messaging_context *msg_ctx;
+ sys_notify_watch_fn sys_notify_watch;
+ struct sys_notify_context *sys_notify_ctx;
+ struct notifyd_peers *peers;
+};
+
+static bool notifyd_snoop_peers_filter(struct messaging_rec *rec,
+ void *private_data);
+static void notifyd_peer_recv_finished(struct tevent_req *subreq);
+static void notifyd_snoop_peers_done(struct tevent_req *subreq);
+
+static struct tevent_req *notifyd_snoop_peers_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
+ sys_notify_watch_fn sys_notify_watch,
+ struct sys_notify_context *sys_notify_ctx,
+ struct notifyd_peers *peers)
+{
+ struct tevent_req *req, *subreq;
+ struct notifyd_snoop_peers_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct notifyd_snoop_peers_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->msg_ctx = msg_ctx;
+ state->sys_notify_watch = sys_notify_watch;
+ state->sys_notify_ctx = sys_notify_ctx;
+ state->peers = peers;
+
+ subreq = messaging_filtered_read_send(
+ state, ev, msg_ctx, notifyd_snoop_peers_filter, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, notifyd_snoop_peers_done, req);
+ return req;
+}
+
+static bool notifyd_snoop_peers_filter(struct messaging_rec *rec,
+ void *private_data)
+{
+ struct notifyd_snoop_peers_state *state = talloc_get_type_abort(
+ private_data, struct notifyd_snoop_peers_state);
+ struct server_id my_id = messaging_server_id(state->msg_ctx);
+ struct tevent_req *subreq;
+ struct notifyd_peers *peers = state->peers;
+ struct notifyd_peer *p, **tmp;
+ uint32_t i, vnn;
+
+ /*
+ * The only point of this filter is to listen for new vnns
+ * broadcasting MSG_SMB_NOTIFY_REC_CHANGES to us and then create a new
+ * listener req. We are not interested in the changes yet, so always
+ * return false here.
+ */
+
+ if (rec->num_fds != 0) {
+ goto done;
+ }
+ if (rec->msg_type != MSG_SMB_NOTIFY_REC_CHANGES) {
+ goto done;
+ }
+ vnn = rec->src.vnn;
+
+ if (vnn == my_id.vnn) {
+ goto done;
+ }
+
+ for (i=0; i<peers->num_peers; i++) {
+ if (peers->peers[i]->vnn == vnn) {
+ goto done;
+ }
+ }
+
+ DEBUG(10, ("%s: Found unknown peer %u\n", __func__,
+ (unsigned)vnn));
+
+ /*
+ * We got a broadcast from a vnn we've not seen. Create a new peer.
+ */
+
+ tmp = talloc_realloc(peers, peers->peers, struct notifyd_peer *,
+ peers->num_peers+1);
+ if (tmp == NULL) {
+ DEBUG(10, ("%s: talloc_realloc failed\n", __func__));
+ goto done;
+ }
+ peers->peers = tmp;
+
+ p = notifyd_peer_new(peers->peers, state->msg_ctx, vnn);
+ if (p == NULL) {
+ DEBUG(10, ("%s: notifyd_peer_new failed\n", __func__));
+ goto done;
+ }
+
+ subreq = notifyd_peer_recv_send(p, state->ev, state->msg_ctx,
+ state->sys_notify_watch,
+ state->sys_notify_ctx, p);
+ if (subreq == NULL) {
+ DEBUG(10, ("%s: notifyd_peer_recv_send failed\n", __func__));
+ TALLOC_FREE(p);
+ goto done;
+ }
+ tevent_req_set_callback(subreq, notifyd_peer_recv_finished, p);
+
+ peers->peers[peers->num_peers] = p;
+ peers->num_peers += 1;
+
+ /*
+ * "Fall through" to return false, we have all we need: A new peer
+ */
+done:
+ return false;
+}
+
+static void notifyd_snoop_peers_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct messaging_rec *rec;
+ int ret;
+
+ /*
+ * We'll never get here normally, our filter always returns
+ * false. We're not interested in the record, so recv it as a child of
+ * subreq, which we'll free immediately.
+ */
+
+ ret = messaging_filtered_read_recv(subreq, subreq, &rec);
+ TALLOC_FREE(rec);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int notifyd_snoop_peers_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+static void notifyd_peer_recv_finished(struct tevent_req *subreq)
+{
+ struct notifyd_peer *peer = tevent_req_callback_data(
+ subreq, struct notifyd_peer);
+ int ret;
+
+ ret = notifyd_peer_recv_recv(subreq);
+ TALLOC_FREE(subreq);
+ DEBUG(10, ("%s: notifyd_peer_recv for peer %u returned %s\n", __func__,
+ (unsigned)peer->vnn, strerror(ret)));
+}
diff --git a/source3/smbd/notifyd/notifyd.h b/source3/smbd/notifyd/notifyd.h
new file mode 100644
index 0000000..084ddf9
--- /dev/null
+++ b/source3/smbd/notifyd/notifyd.h
@@ -0,0 +1,142 @@
+/*
+ * 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,
+ 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..a7f925a
--- /dev/null
+++ b/source3/smbd/notifyd/tests.c
@@ -0,0 +1,119 @@
+/*
+ * 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);
+ }
+
+ load_case_tables();
+ 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..aa1ba3a
--- /dev/null
+++ b/source3/smbd/notifyd/wscript_build
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_SUBSYSTEM('notifyd',
+ source='notifyd.c',
+ deps='samba3core')
+
+bld.SAMBA3_BINARY('notifyd-tests',
+ source='tests.c',
+ install=False,
+ deps='''
+ param
+ ''')
diff --git a/source3/wscript_build b/source3/wscript_build
index 73a6d57..ae80dbb 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1513,6 +1513,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.9.1
From 7840c995852c832d08067cd14ba4f47de43f18f0 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 07/15] 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
---
source3/smbd/server.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++
source3/wscript_build | 1 +
2 files changed, 95 insertions(+)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 8207bf1..f00df9d 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -48,6 +48,7 @@
#include "lib/smbd_shim.h"
#include "scavenger.h"
#include "locking/leases_db.h"
+#include "smbd/notifyd/notifyd.h"
struct smbd_open_socket;
struct smbd_child_pid;
@@ -381,6 +382,96 @@ 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,
+ 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
@@ -1460,6 +1551,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 ae80dbb..101267b 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -629,6 +629,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.9.1
From 64780ec33ec0f1fde77799d1ad193364404b86cc 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 08/15] smbd: Don't start the notify cleanup anymore
We don't have a database to clean up anymore
---
source3/smbd/server.c | 100 --------------------------------------------------
1 file changed, 100 deletions(-)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index f00df9d..9203f82 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -257,103 +257,6 @@ static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
messaging_send_to_children(ctx, msg_type, msg_data);
}
-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)
{
@@ -1548,9 +1451,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.9.1
From bf3cd686623a33512e22912131f157b694964b7f 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 09/15] smbd: Replace the tdb-based notify_internal with
notify_msg
---
source3/smbd/notify_internal.c | 1272 ----------------------------------------
source3/smbd/notify_msg.c | 268 +++++++++
source3/smbd/proto.h | 5 -
source3/wscript_build | 4 +-
4 files changed, 270 insertions(+), 1279 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 e612f16..0000000
--- a/source3/smbd/notify_internal.c
+++ /dev/null
@@ -1,1272 +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 notify_db_entry *entries;
- size_t i, num_entries;
- time_t now;
-
- DEBUG(10, ("del_entry called for %s %p\n", procid_str_static(pid),
- 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;
- 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;
- }
-
- 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_blob(
- ctdbd_conn, vnn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
- remote_blob, remote_blob_len);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("ctdbd_messaging_send_blob 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)) {
- DEBUG(1, ("internal error: Non-local pid %s in "
- "notify.tdb\n",
- procid_str_static(&e->server)));
- 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 16e87f8..268c3d2 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -581,11 +581,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 101267b..ab10159 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -598,7 +598,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
@@ -1187,7 +1187,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.9.1
From b9cef68623e9be3b6b5e65bb312b1da5e2939c84 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 10/15] smbd: Kernel change notify is done by notifyd
smbd itself does not need to call VFS_NOTIFY_WATCH anymore
---
source3/smbd/notify.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 5ac8c0c..b916ff3 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -235,15 +235,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 filter,
bool recursive)
{
@@ -283,19 +274,6 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 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.9.1
From e04787a87c25afec612aa17fd8dee9a9c3d88f6c 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 11/15] smbd: Remove the notify_fam module
This has been moved to main smbd
---
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 0bc3f54..3db391b 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -67,7 +67,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 54df0e4..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 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 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 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 de4947b..48b4a87 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.9.1
From c0fb1667d8100dd9be4e205dbc26fc249577b034 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 12/15] notifyd: Add notifyd_parse_db()
The database format notifyd is "private" to it. This makes it possible
for smbcontrol and others to inspect the notifyd's database without
having to know exactly what format it uses.
---
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 8c4a4ae..4817ab1 100644
--- a/source3/smbd/notifyd/notifyd.c
+++ b/source3/smbd/notifyd/notifyd.c
@@ -1491,3 +1491,74 @@ static void notifyd_peer_recv_finished(struct tevent_req *subreq)
DEBUG(10, ("%s: notifyd_peer_recv for peer %u returned %s\n", __func__,
(unsigned)peer->vnn, strerror(ret)));
}
+
+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_entry *entry = NULL;
+ size_t i, num_instances;
+ bool ok;
+
+ memcpy(path, key.dptr, key.dsize);
+ path[key.dsize] = 0;
+
+ ok = notifyd_parse_entry(value.dptr, value.dsize, &entry,
+ &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, entry->instances[i].client,
+ &entry->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 084ddf9..707a835 100644
--- a/source3/smbd/notifyd/notifyd.h
+++ b/source3/smbd/notifyd/notifyd.h
@@ -139,4 +139,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.9.1
From 9712bd2ff529b17ee1c371b466f9df2324e831e4 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 13/15] notify: Re-add notify_walk()
This used to be a tdb traverse wrapper. Now we get the notify db from
notifyd via messages.
---
source3/smbd/notify_msg.c | 72 ++++++++++++++++++++++++++++++++++++++++++-----
source3/smbd/proto.h | 14 +++++----
source3/utils/status.c | 45 ++++++++++++++---------------
3 files changed, 96 insertions(+), 35 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 268c3d2..31fab43 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -573,12 +573,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 61efa93..e38f3a8 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 */
@@ -321,28 +322,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];
- char *str;
+ d_printf("%s\\%s\\%x\\%x\n", path, server_id_str_buf(server, &idbuf),
+ (unsigned)instance->filter,
+ (unsigned)instance->subdir_filter);
- str = server_id_str(talloc_tos(), &e->server);
- printf("%s %x %x\n", str, (unsigned)e->filter,
- (unsigned)e->subdir_filter);
- TALLOC_FREE(str);
- }
- printf("\n");
+ return true;
}
int main(int argc, const char *argv[])
@@ -371,7 +361,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;
@@ -582,11 +572,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.9.1
From 754337822452b799d474dcab72fdc7145f3b8f5e 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 14/15] smbd: Remove SMB_VFS_NOTIFY_WATCH
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 b52c381..215c395 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -463,19 +463,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)
{
@@ -888,7 +875,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 925e520..6256654 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -551,21 +551,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)
{
@@ -998,7 +983,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 1843ef4..798fb1d 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -620,16 +620,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);
@@ -1073,15 +1063,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 ef97b49..021b083 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 ec72312..ea5317b 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -1001,23 +1001,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)
{
@@ -1235,7 +1218,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 69af305..47c76b0 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -2099,51 +2099,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)
{
@@ -2607,7 +2562,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 c5a9c0d..956e64a 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -155,7 +155,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,
@@ -280,7 +279,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" },
@@ -1581,27 +1579,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)
{
@@ -2253,7 +2230,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 10c3a22..6ec403e 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -1077,18 +1077,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)
{
@@ -1798,7 +1786,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 a1e825a..6fe109a 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -1416,34 +1416,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)
{
@@ -2437,7 +2409,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 d10e0d6..72aac52 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -2084,22 +2084,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.9.1
From 76be616d2fd1609d52521001c5061c2d278991a3 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 15/15] 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 31fab43..0f348fe 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -568,11 +568,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,
@@ -581,8 +576,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.9.1
More information about the samba-technical
mailing list