summaryrefslogtreecommitdiff
path: root/source3/smbd/notify.c
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2007-01-21 11:49:00 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:17:21 -0500
commitd5206610cd67f88e2cc7d5b2b434e320e81c29d5 (patch)
tree5b085416bd4403cea107f73a1e874199fd1284b1 /source3/smbd/notify.c
parent57881f749495825f61f8affce921eee46fc7b728 (diff)
downloadsamba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.tar.gz
samba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.tar.bz2
samba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.zip
r20931: This changes the notify infrastructure from a polling-based to an event-driven
based approach. The only remaining hook into the backend is now void *(*notify_add)(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, files_struct *fsp, uint32 *filter); (Should we put this through the VFS, so that others can more easily plug in?) The trick here is that the backend can pick filter bits that the main smbd should not handle anymore. Thanks to tridge for this idea. The backend can notify the main smbd process via void notify_fsp(files_struct *fsp, uint32 action, char *name); The core patch is not big, what makes this more than 1800 lines are the individual backends that are considerably changed but can be reviewed one by one. Based on this I'll continue with inotify now. Volker (This used to be commit 9cd6a8a82792b7b6967141565d043b6337836a5d)
Diffstat (limited to 'source3/smbd/notify.c')
-rw-r--r--source3/smbd/notify.c226
1 files changed, 48 insertions, 178 deletions
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 2c762bd759..ce7680b49a 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -3,6 +3,7 @@
change notify handling
Copyright (C) Andrew Tridgell 2000
Copyright (C) Jeremy Allison 1994-1998
+ 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
@@ -24,22 +25,6 @@
static struct cnotify_fns *cnotify;
static struct notify_mid_map *notify_changes_by_mid;
-/****************************************************************************
- This is the structure to queue to implement NT change
- notify. It consists of smb_size bytes stored from the
- transact command (to keep the mid, tid etc around).
- Plus the fid to examine and notify private data.
-*****************************************************************************/
-
-struct change_notify {
- struct change_notify *next, *prev;
- files_struct *fsp;
- uint32 flags;
- uint32 max_param_count;
- char request_buf[smb_size];
- void *change_data;
-};
-
/*
* For NTCancel, we need to find the notify_change_request indexed by
* mid. Separate list here.
@@ -51,9 +36,7 @@ struct notify_mid_map {
uint16 mid;
};
-static struct change_notify *change_notify_list;
-
-static BOOL notify_marshall_changes(unsigned num_changes,
+static BOOL notify_marshall_changes(int num_changes,
struct notify_change *changes,
prs_struct *ps)
{
@@ -132,12 +115,17 @@ static void change_notify_reply_packet(const char *request_buf,
}
void change_notify_reply(const char *request_buf, uint32 max_param_count,
- unsigned num_changes, struct notify_change *changes)
+ int num_changes, struct notify_change *changes)
{
char *outbuf = NULL;
prs_struct ps;
size_t buflen = smb_size+38+max_param_count;
+ if (num_changes == -1) {
+ change_notify_reply_packet(request_buf, NT_STATUS_OK);
+ return;
+ }
+
if (!prs_init(&ps, 0, NULL, False)
|| !notify_marshall_changes(num_changes, changes, &ps)) {
change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
@@ -170,19 +158,6 @@ void change_notify_reply(const char *request_buf, uint32 max_param_count,
prs_mem_free(&ps);
}
-/****************************************************************************
- Remove an entry from the list and free it, also closing any
- directory handle if necessary.
-*****************************************************************************/
-
-static void change_notify_remove(struct change_notify *cnbp)
-{
- cnotify->remove_notify(cnbp->change_data);
- DLIST_REMOVE(change_notify_list, cnbp);
- ZERO_STRUCTP(cnbp);
- SAFE_FREE(cnbp);
-}
-
NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
uint32 filter, struct files_struct *fsp)
{
@@ -202,6 +177,10 @@ NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
request->max_param_count = max_param_count;
request->filter = filter;
request->fsp = fsp;
+
+ request->backend_data = cnotify->notify_add(NULL, smbd_event_context(),
+ fsp, &request->filter);
+
DLIST_ADD_END(fsp->notify->requests, request,
struct notify_change_request *);
@@ -240,6 +219,7 @@ static void change_notify_remove_request(struct notify_change_request *remove_re
DLIST_REMOVE(fsp->notify->requests, req);
DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
SAFE_FREE(req->mid_map);
+ TALLOC_FREE(req->backend_data);
SAFE_FREE(req);
}
@@ -283,141 +263,6 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
}
}
-/****************************************************************************
- Delete entries by filename and cnum from the change notify pending queue.
- Always send reply.
-*****************************************************************************/
-
-void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTATUS status)
-{
- struct change_notify *cnbp, *next;
-
- for (cnbp=change_notify_list; cnbp; cnbp=next) {
- next=cnbp->next;
- /*
- * We know it refers to the same directory if the connection number and
- * the filename are identical.
- */
- if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
- change_notify_reply_packet(cnbp->request_buf, status);
- change_notify_remove(cnbp);
- }
- }
-}
-
-/****************************************************************************
- Set the current change notify timeout to the lowest value across all service
- values.
-****************************************************************************/
-
-void set_change_notify_timeout(int val)
-{
- if (val > 0) {
- cnotify->select_time = MIN(cnotify->select_time, val);
- }
-}
-
-/****************************************************************************
- Longest time to sleep for before doing a change notify scan.
-****************************************************************************/
-
-int change_notify_timeout(void)
-{
- return cnotify->select_time;
-}
-
-/****************************************************************************
- Process the change notify queue. Note that this is only called as root.
- Returns True if there are still outstanding change notify requests on the
- queue.
-*****************************************************************************/
-
-BOOL process_pending_change_notify_queue(time_t t)
-{
- struct change_notify *cnbp, *next;
- uint16 vuid;
-
- for (cnbp=change_notify_list; cnbp; cnbp=next) {
- next=cnbp->next;
-
- vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
-
- if (cnbp->fsp->notify->num_changes != 0) {
- DEBUG(10,("process_pending_change_notify_queue: %s "
- "has %d changes!\n", cnbp->fsp->fsp_name,
- cnbp->fsp->notify->num_changes));
- change_notify_reply(cnbp->request_buf,
- cnbp->max_param_count,
- cnbp->fsp->notify->num_changes,
- cnbp->fsp->notify->changes);
- change_notify_remove(cnbp);
- continue;
- }
-
- if (cnotify->check_notify(cnbp->fsp->conn, vuid,
- cnbp->fsp->fsp_name, cnbp->flags,
- cnbp->change_data, t)) {
- DEBUG(10,("process_pending_change_notify_queue: dir "
- "%s changed !\n", cnbp->fsp->fsp_name ));
- change_notify_reply(cnbp->request_buf,
- cnbp->max_param_count,
- cnbp->fsp->notify->num_changes,
- cnbp->fsp->notify->changes);
- change_notify_remove(cnbp);
- }
- }
-
- return (change_notify_list != NULL);
-}
-
-/****************************************************************************
- Now queue an entry on the notify change list.
- We only need to save smb_size bytes from this incoming packet
- as we will always by returning a 'read the directory yourself'
- error.
-****************************************************************************/
-
-BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
- uint32 flags, uint32 max_param_count)
-{
- struct change_notify *cnbp;
-
- if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) {
- DEBUG(0,("change_notify_set: malloc fail !\n" ));
- return False;
- }
-
- ZERO_STRUCTP(cnbp);
-
- memcpy(cnbp->request_buf, inbuf, smb_size);
- cnbp->fsp = fsp;
- cnbp->flags = flags;
- cnbp->max_param_count = max_param_count;
- cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name,
- flags);
-
- if (!cnbp->change_data) {
- SAFE_FREE(cnbp);
- return False;
- }
-
- DLIST_ADD(change_notify_list, cnbp);
-
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(SVAL(inbuf,smb_mid));
-
- return True;
-}
-
-int change_notify_fd(void)
-{
- if (cnotify) {
- return cnotify->notification_fd;
- }
-
- return -1;
-}
-
/* notify message definition
Offset Data length.
@@ -571,7 +416,7 @@ void notify_fname(connection_struct *conn, const char *path,
TALLOC_FREE(parent);
}
-static void notify_fsp(files_struct *fsp, struct notify_message *msg)
+void notify_fsp(files_struct *fsp, uint32 action, char *name)
{
struct notify_change *change, *changes;
@@ -582,8 +427,7 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
return;
}
- if ((fsp->notify->requests != NULL)
- && (fsp->notify->requests->filter & msg->filter)) {
+ if (fsp->notify->requests != NULL) {
/*
* Someone is waiting for the change, trigger the reply
* immediately.
@@ -594,8 +438,18 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
struct notify_change_request *req = fsp->notify->requests;
struct notify_change onechange;
- onechange.action = msg->action;
- onechange.name = msg->name;
+ if (name == NULL) {
+ /*
+ * Catch-all change, possibly from notify_hash.c
+ */
+ change_notify_reply(req->request_buf,
+ req->max_param_count,
+ -1, NULL);
+ return;
+ }
+
+ onechange.action = action;
+ onechange.name = name;
change_notify_reply(req->request_buf, req->max_param_count,
1, &onechange);
@@ -609,6 +463,19 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
* apply here. Do we have to store them?
*/
+ if ((fsp->notify->num_changes > 30) || (name == NULL)) {
+ /*
+ * W2k3 seems to store at most 30 changes.
+ */
+ TALLOC_FREE(fsp->notify->changes);
+ fsp->notify->num_changes = -1;
+ return;
+ }
+
+ if (fsp->notify->num_changes == -1) {
+ return;
+ }
+
if (!(changes = TALLOC_REALLOC_ARRAY(
fsp->notify, fsp->notify->changes,
struct notify_change, fsp->notify->num_changes+1))) {
@@ -620,11 +487,11 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
change = &(fsp->notify->changes[fsp->notify->num_changes]);
- if (!(change->name = talloc_strdup(changes, msg->name))) {
+ if (!(change->name = talloc_strdup(changes, name))) {
DEBUG(0, ("talloc_strdup failed\n"));
return;
}
- change->action = msg->action;
+ change->action = action;
fsp->notify->num_changes += 1;
return;
@@ -645,7 +512,10 @@ static void notify_message_callback(int msgtype, struct process_id pid,
for(fsp = fsp_find_di_first(msg.dev, msg.inode); fsp;
fsp = fsp_find_di_next(fsp)) {
- notify_fsp(fsp, &msg);
+ if ((fsp->notify->requests != NULL)
+ && (fsp->notify->requests->filter & msg.filter)) {
+ notify_fsp(fsp, msg.action, msg.name);
+ }
}
}
@@ -659,11 +529,11 @@ BOOL init_change_notify(void)
#if HAVE_KERNEL_CHANGE_NOTIFY
if (cnotify == NULL && lp_kernel_change_notify())
- cnotify = kernel_notify_init();
+ cnotify = kernel_notify_init(smbd_event_context());
#endif
#if HAVE_FAM_CHANGE_NOTIFY
if (cnotify == NULL && lp_fam_change_notify())
- cnotify = fam_notify_init();
+ cnotify = fam_notify_init(smbd_event_context());
#endif
if (!cnotify) cnotify = hash_notify_init();