[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-1056-g32a36e4

Volker Lendecke vlendec at samba.org
Thu Apr 16 13:07:20 GMT 2009


The branch, master has been updated
       via  32a36e470333abae2745e27074a24ab54777b41e (commit)
       via  ea3a022ca3ed97f0ac3f16536832e8ec43683f8c (commit)
      from  448b434a862da0ca621c3b695dc800e9ec5e8fcf (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 32a36e470333abae2745e27074a24ab54777b41e
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Apr 14 20:39:14 2009 +0200

    Add notify_onelevel.tdb
    
    This optimizes non-recursive notifys. For non-recursive notifies we can use a
    per-directory file-id indexed notify record. This matters for the Windows
    Explorer and IIS cases which do not use recursive notifies. In these cases, we
    do not have to shuffle around the whole notify record on every change.
    
    For the cluster case, this improves correctness of the notifies, ctdb only
    distributes the tdb seqnum once a second, so we can lose notifies.

commit ea3a022ca3ed97f0ac3f16536832e8ec43683f8c
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Apr 14 14:56:35 2009 +0200

    Rename notify_context->db to db_recursive

-----------------------------------------------------------------------

Summary of changes:
 source3/include/proto.h             |    5 +
 source3/librpc/gen_ndr/ndr_notify.c |   63 +++++++
 source3/librpc/gen_ndr/ndr_notify.h |    3 +
 source3/librpc/gen_ndr/notify.h     |    7 +
 source3/librpc/idl/notify.idl       |    5 +
 source3/smbd/files.c                |    4 +
 source3/smbd/notify.c               |   10 ++
 source3/smbd/notify_internal.c      |  307 ++++++++++++++++++++++++++++++++++-
 8 files changed, 395 insertions(+), 9 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 25e81fd..07e04ed 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6554,6 +6554,11 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0,
 		    void (*callback)(void *, const struct notify_event *), 
 		    void *private_data);
 NTSTATUS notify_remove(struct notify_context *notify, void *private_data);
+NTSTATUS notify_remove_onelevel(struct notify_context *notify,
+				const struct file_id *fid,
+				void *private_data);
+void notify_onelevel(struct notify_context *notify, uint32_t action,
+		     uint32_t filter, struct file_id fid, const char *name);
 void notify_trigger(struct notify_context *notify,
 		    uint32_t action, uint32_t filter, const char *path);
 
diff --git a/source3/librpc/gen_ndr/ndr_notify.c b/source3/librpc/gen_ndr/ndr_notify.c
index d4ac42e..844c278 100644
--- a/source3/librpc/gen_ndr/ndr_notify.c
+++ b/source3/librpc/gen_ndr/ndr_notify.c
@@ -68,6 +68,69 @@ _PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, co
 	ndr->depth--;
 }
 
+_PUBLIC_ enum ndr_err_code ndr_push_notify_entry_array(struct ndr_push *ndr, int ndr_flags, const struct notify_entry_array *r)
+{
+	uint32_t cntr_entries_0;
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 8));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_entries));
+		for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+			NDR_CHECK(ndr_push_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0]));
+		}
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+			NDR_CHECK(ndr_push_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0]));
+		}
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_entry_array(struct ndr_pull *ndr, int ndr_flags, struct notify_entry_array *r)
+{
+	uint32_t cntr_entries_0;
+	TALLOC_CTX *_mem_save_entries_0;
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 8));
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_entries));
+		NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries);
+		_mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+		NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+		for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+			NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0]));
+		}
+		NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		_mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+		NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+		for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+			NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0]));
+		}
+		NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_entry_array(struct ndr_print *ndr, const char *name, const struct notify_entry_array *r)
+{
+	uint32_t cntr_entries_0;
+	ndr_print_struct(ndr, name, "notify_entry_array");
+	ndr->depth++;
+	ndr_print_uint32(ndr, "num_entries", r->num_entries);
+	ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->num_entries);
+	ndr->depth++;
+	for (cntr_entries_0=0;cntr_entries_0<r->num_entries;cntr_entries_0++) {
+		char *idx_0=NULL;
+		if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+			ndr_print_notify_entry(ndr, "entries", &r->entries[cntr_entries_0]);
+			free(idx_0);
+		}
+	}
+	ndr->depth--;
+	ndr->depth--;
+}
+
 static enum ndr_err_code ndr_push_notify_depth(struct ndr_push *ndr, int ndr_flags, const struct notify_depth *r)
 {
 	uint32_t cntr_entries_0;
diff --git a/source3/librpc/gen_ndr/ndr_notify.h b/source3/librpc/gen_ndr/ndr_notify.h
index 23d3d3f..fa2972d 100644
--- a/source3/librpc/gen_ndr/ndr_notify.h
+++ b/source3/librpc/gen_ndr/ndr_notify.h
@@ -10,6 +10,9 @@
 enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r);
 enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r);
 void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r);
+enum ndr_err_code ndr_push_notify_entry_array(struct ndr_push *ndr, int ndr_flags, const struct notify_entry_array *r);
+enum ndr_err_code ndr_pull_notify_entry_array(struct ndr_pull *ndr, int ndr_flags, struct notify_entry_array *r);
+void ndr_print_notify_entry_array(struct ndr_print *ndr, const char *name, const struct notify_entry_array *r);
 void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r);
 enum ndr_err_code ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r);
 enum ndr_err_code ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r);
diff --git a/source3/librpc/gen_ndr/notify.h b/source3/librpc/gen_ndr/notify.h
index a5ec4a4..a390fa8 100644
--- a/source3/librpc/gen_ndr/notify.h
+++ b/source3/librpc/gen_ndr/notify.h
@@ -2,6 +2,8 @@
 
 #include <stdint.h>
 
+#include "libcli/util/ntstatus.h"
+
 #ifndef _HEADER_notify
 #define _HEADER_notify
 
@@ -16,6 +18,11 @@ struct notify_entry {
 	void* private_data;
 }/* [public] */;
 
+struct notify_entry_array {
+	uint32_t num_entries;
+	struct notify_entry *entries;
+}/* [public] */;
+
 struct notify_depth {
 	uint32_t max_mask;
 	uint32_t max_mask_subdir;
diff --git a/source3/librpc/idl/notify.idl b/source3/librpc/idl/notify.idl
index 550783b..0e80679 100644
--- a/source3/librpc/idl/notify.idl
+++ b/source3/librpc/idl/notify.idl
@@ -25,6 +25,11 @@ interface notify
 		pointer private_data;
 	} notify_entry;
 
+	typedef [public] struct {
+		uint32 num_entries;
+		notify_entry entries[num_entries];
+	} notify_entry_array;
+
 	/*
 	  to allow for efficient search for matching entries, we
 	  divide them by the directory depth, with a separate array
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 36e80a0..d2ea520 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -433,6 +433,10 @@ void file_free(struct smb_request *req, files_struct *fsp)
 	}
 
 	if (fsp->notify) {
+		if (fsp->is_directory) {
+			notify_remove_onelevel(fsp->conn->notify_ctx,
+					       &fsp->file_id, fsp);
+		}
 		notify_remove(fsp->conn->notify_ctx, fsp);
 		TALLOC_FREE(fsp->notify);
 	}
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index d141fb2..12a75cc 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -339,6 +339,9 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
 		  const char *path)
 {
 	char *fullpath;
+	char *parent;
+	const char *name;
+	SMB_STRUCT_STAT sbuf;
 
 	if (path[0] == '.' && path[1] == '/') {
 		path += 2;
@@ -348,6 +351,13 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
 		return;
 	}
 
+	if (parent_dirname(talloc_tos(), path, &parent, &name)
+	    && (SMB_VFS_STAT(conn, parent, &sbuf) != -1)) {
+		notify_onelevel(conn->notify_ctx, action, filter,
+				SMB_VFS_FILE_ID_CREATE(conn, &sbuf),
+				name);
+	}
+
 	notify_trigger(conn->notify_ctx, action, filter, fullpath);
 	SAFE_FREE(fullpath);
 }
diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c
index 1e45c54..a42404d 100644
--- a/source3/smbd/notify_internal.c
+++ b/source3/smbd/notify_internal.c
@@ -27,7 +27,8 @@
 #include "librpc/gen_ndr/ndr_notify.h"
 
 struct notify_context {
-	struct db_context *db;
+	struct db_context *db_recursive;
+	struct db_context *db_onelevel;
 	struct server_id server;
 	struct messaging_context *messaging_ctx;
 	struct notify_list *list;
@@ -91,10 +92,18 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
 		return NULL;
 	}
 
-	notify->db = db_open(notify, lock_path("notify.tdb"),
-				  0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
-				  O_RDWR|O_CREAT, 0644);
-	if (notify->db == NULL) {
+	notify->db_recursive = db_open(notify, lock_path("notify.tdb"),
+				       0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+				       O_RDWR|O_CREAT, 0644);
+	if (notify->db_recursive == NULL) {
+		talloc_free(notify);
+		return NULL;
+	}
+
+	notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"),
+				      0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+				      O_RDWR|O_CREAT, 0644);
+	if (notify->db_onelevel == NULL) {
 		talloc_free(notify);
 		return NULL;
 	}
@@ -103,7 +112,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
 	notify->messaging_ctx = messaging_ctx;
 	notify->list = NULL;
 	notify->array = NULL;
-	notify->seqnum = notify->db->get_seqnum(notify->db);
+	notify->seqnum = notify->db_recursive->get_seqnum(
+		notify->db_recursive);
 	notify->key = string_term_tdb_data(NOTIFY_KEY);
 
 	talloc_set_destructor(notify, notify_destructor);
@@ -123,7 +133,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
 */
 static NTSTATUS notify_fetch_locked(struct notify_context *notify, struct db_record **rec)
 {
-	*rec = notify->db->fetch_locked(notify->db, notify, notify->key);
+	*rec = notify->db_recursive->fetch_locked(notify->db_recursive,
+						  notify, notify->key);
 	if (*rec == NULL) {
 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
 	}
@@ -140,7 +151,7 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec
 	NTSTATUS status;
 	int seqnum;
 
-	seqnum = notify->db->get_seqnum(notify->db);
+	seqnum = notify->db_recursive->get_seqnum(notify->db_recursive);
 
 	if (seqnum == notify->seqnum && notify->array != NULL) {
 		return NT_STATUS_OK;
@@ -153,7 +164,8 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec
 	NT_STATUS_HAVE_NO_MEMORY(notify->array);
 
 	if (!rec) {
-		if (notify->db->fetch(notify->db, notify, notify->key, &dbuf) != 0) {
+		if (notify->db_recursive->fetch(notify->db_recursive, notify,
+						notify->key, &dbuf) != 0) {
 			return NT_STATUS_INTERNAL_DB_CORRUPTION;
 		}
 	} else {
@@ -344,6 +356,96 @@ static NTSTATUS notify_add_array(struct notify_context *notify, struct db_record
 }
 
 /*
+  Add a non-recursive watch
+*/
+
+static void notify_add_onelevel(struct notify_context *notify,
+				struct notify_entry *e, void *private_data)
+{
+	struct notify_entry_array *array;
+	struct db_record *rec;
+	DATA_BLOB blob;
+	TDB_DATA dbuf;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+
+	array = talloc_zero(talloc_tos(), struct notify_entry_array);
+	if (array == NULL) {
+		return;
+	}
+
+	rec = notify->db_onelevel->fetch_locked(
+		notify->db_onelevel, talloc_tos(),
+		make_tdb_data((uint8_t *)&e->dir_id, sizeof(e->dir_id)));
+	if (rec == NULL) {
+		DEBUG(10, ("notify_add_onelevel: fetch_locked for %s failed"
+			   "\n", file_id_string_tos(&e->dir_id)));
+		TALLOC_FREE(array);
+		return;
+	}
+
+	blob.data = (uint8_t *)rec->value.dptr;
+	blob.length = rec->value.dsize;
+
+	if (blob.length > 0) {
+		ndr_err = ndr_pull_struct_blob(
+			&blob, array, NULL, array,
+			(ndr_pull_flags_fn_t)ndr_pull_notify_entry_array);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n",
+				   ndr_errstr(ndr_err)));
+			TALLOC_FREE(array);
+			return;
+		}
+		if (DEBUGLEVEL >= 10) {
+			DEBUG(10, ("notify_add_onelevel:\n"));
+			NDR_PRINT_DEBUG(notify_entry_array, array);
+		}
+	}
+
+	array->entries = talloc_realloc(array, array->entries,
+					struct notify_entry,
+					array->num_entries+1);
+	if (array->entries == NULL) {
+		TALLOC_FREE(array);
+		return;
+	}
+	array->entries[array->num_entries] = *e;
+	array->entries[array->num_entries].private_data = private_data;
+	array->entries[array->num_entries].server = notify->server;
+	array->num_entries += 1;
+
+	ndr_err = ndr_push_struct_blob(
+		&blob, rec, NULL, array,
+		(ndr_push_flags_fn_t)ndr_push_notify_entry_array);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n",
+			   ndr_errstr(ndr_err)));
+		TALLOC_FREE(array);
+		return;
+	}
+
+	if (DEBUGLEVEL >= 10) {
+		DEBUG(10, ("notify_add_onelevel:\n"));
+		NDR_PRINT_DEBUG(notify_entry_array, array);
+	}
+
+	dbuf.dptr = blob.data;
+	dbuf.dsize = blob.length;
+
+	status = rec->store(rec, dbuf, TDB_REPLACE);
+	TALLOC_FREE(array);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("notify_add_onelevel: store failed: %s\n",
+			   nt_errstr(status)));
+		return;
+	}
+	e->filter = 0;
+	return;
+}
+
+
+/*
   add a notify watch. This is called when a notify is first setup on a open
   directory handle.
 */
@@ -411,6 +513,11 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0,
 		}
 	}
 
+	if (e.filter != 0) {
+		notify_add_onelevel(notify, &e, private_data);
+		status = NT_STATUS_OK;
+	}
+
 	/* if the system notify handler couldn't handle some of the
 	   filter bits, or couldn't handle a request for recursion
 	   then we need to install it in the array used for the
@@ -426,6 +533,102 @@ done:
 	return status;
 }
 
+NTSTATUS notify_remove_onelevel(struct notify_context *notify,
+				const struct file_id *fid,
+				void *private_data)
+{
+	struct notify_entry_array *array;
+	struct db_record *rec;
+	DATA_BLOB blob;
+	TDB_DATA dbuf;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+	int i;
+
+	array = talloc_zero(talloc_tos(), struct notify_entry_array);
+	if (array == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	rec = notify->db_onelevel->fetch_locked(
+		notify->db_onelevel, talloc_tos(),
+		make_tdb_data((uint8_t *)fid, sizeof(*fid)));
+	if (rec == NULL) {
+		DEBUG(10, ("notify_remove_onelevel: fetch_locked for %s failed"
+			   "\n", file_id_string_tos(fid)));
+		TALLOC_FREE(array);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	blob.data = (uint8_t *)rec->value.dptr;
+	blob.length = rec->value.dsize;
+
+	if (blob.length > 0) {
+		ndr_err = ndr_pull_struct_blob(
+			&blob, array, NULL, array,
+			(ndr_pull_flags_fn_t)ndr_pull_notify_entry_array);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n",
+				   ndr_errstr(ndr_err)));
+			TALLOC_FREE(array);
+			return ndr_map_error2ntstatus(ndr_err);
+		}
+		if (DEBUGLEVEL >= 10) {
+			DEBUG(10, ("notify_remove_onelevel:\n"));
+			NDR_PRINT_DEBUG(notify_entry_array, array);
+		}
+	}
+
+	for (i=0; i<array->num_entries; i++) {
+		if ((private_data == array->entries[i].private_data) &&
+		    cluster_id_equal(&notify->server,
+				     &array->entries[i].server)) {
+			break;
+		}
+	}
+
+	if (i == array->num_entries) {
+		TALLOC_FREE(array);
+		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+	}
+
+	array->entries[i] = array->entries[array->num_entries-1];
+	array->num_entries -= 1;
+
+	if (array->num_entries == 0) {
+		rec->delete_rec(rec);
+		TALLOC_FREE(array);
+		return NT_STATUS_OK;
+	}
+
+	ndr_err = ndr_push_struct_blob(
+		&blob, rec, NULL, array,
+		(ndr_push_flags_fn_t)ndr_push_notify_entry_array);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n",
+			   ndr_errstr(ndr_err)));
+		TALLOC_FREE(array);
+		return ndr_map_error2ntstatus(ndr_err);
+	}
+
+	if (DEBUGLEVEL >= 10) {
+		DEBUG(10, ("notify_add_onelevel:\n"));
+		NDR_PRINT_DEBUG(notify_entry_array, array);
+	}
+
+	dbuf.dptr = blob.data;
+	dbuf.dsize = blob.length;
+
+	status = rec->store(rec, dbuf, TDB_REPLACE);
+	TALLOC_FREE(array);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("notify_add_onelevel: store failed: %s\n",
+			   nt_errstr(status)));
+		return status;
+	}
+	return NT_STATUS_OK;
+}
+
 /*
   remove a notify watch. Called when the directory handle is closed
 */
@@ -574,6 +777,92 @@ static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry *
 	return status;
 }
 
+void notify_onelevel(struct notify_context *notify, uint32_t action,
+		     uint32_t filter, struct file_id fid, const char *name)
+{
+	struct notify_entry_array *array;
+	TDB_DATA dbuf;
+	DATA_BLOB blob;
+	bool have_dead_entries = false;
+	int i;
+
+	array = talloc_zero(talloc_tos(), struct notify_entry_array);
+	if (array == NULL) {
+		return;
+	}
+
+	if (notify->db_onelevel->fetch(
+		    notify->db_onelevel, array,
+		    make_tdb_data((uint8_t *)&fid, sizeof(fid)),
+		    &dbuf) == -1) {
+		TALLOC_FREE(array);
+		return;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list