notifyd
Jeremy Allison
jra at samba.org
Fri Jan 9 11:46:48 MST 2015
On Fri, Jan 09, 2015 at 05:56:44PM +0100, Volker Lendecke wrote:
> 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 :-)
Wow - this looks some seriously nice code !
The only thing I'd ask for is some more comments
inside smbd_notifyd_init() to point out we're
starting a new daemon here.
I'm assuming I can just push the first two patches...
What do you need to get patches 3-15 in master ?
Jeremy.
> 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
> 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