[SCM] Samba Shared Repository - branch v3-2-test updated - initial-v3-2-test-2661-gb0e52ce

Volker Lendecke vl at samba.org
Fri Feb 29 08:43:58 GMT 2008


The branch, v3-2-test has been updated
       via  b0e52cecf2009d4c7f29412dadf17910e54e4327 (commit)
      from  7cf645cdae8ce17705036951538991b0a9dbefaf (commit)

http://gitweb.samba.org/?samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit b0e52cecf2009d4c7f29412dadf17910e54e4327
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Feb 21 16:14:08 2008 +0100

    Add vfs_aio_fork
    
    This is used for two purposes:
    
    First, I'm using it to test the async I/O code. In the forked process it is
    pretty easy to delay a reply for a random amount of time. See the
    BUILD_FARM_HACKS snippet.
    
    Second, there are systems around that claim to have Posix AIO but which is
    broken. This might be some help for those systems.
    
    Also add tests how to pass file descriptors

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

Summary of changes:
 WHATSNEW.txt                  |    2 +
 source/Makefile.in            |    5 +
 source/configure.in           |   51 +++
 source/modules/vfs_aio_fork.c |  728 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 786 insertions(+), 0 deletions(-)
 create mode 100644 source/modules/vfs_aio_fork.c


Changeset truncated at 500 lines:

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 8c32d9a..76a66b3 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -205,6 +205,8 @@ o  Volker Lendecke <vl at samba.org>
     * Support for storing alternate data streams in xattrs.
     * Implement a generic in-memory cache based on rb-trees.
     * Add implicit temporary talloc contexts via talloc_stack().
+    * Speed up the smbclient "get" command
+    * Add the aio_fork module
 
 
 o   Stefan Metzmacher <metze at samba.org>
diff --git a/source/Makefile.in b/source/Makefile.in
index 7ab0c4f..2f963e2 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -601,6 +601,7 @@ VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o
 VFS_READAHEAD_OBJ = modules/vfs_readahead.o
 VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
 VFS_FILEID_OBJ = modules/vfs_fileid.o
+VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
 VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
@@ -1854,6 +1855,10 @@ bin/fileid. at SHLIBEXT@: $(BINARY_PREREQS) $(VFS_FILEID_OBJ)
 	@echo "Building plugin $@"
 	@$(SHLD_MODULE) $(VFS_FILEID_OBJ)
 
+bin/aio_fork. at SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ)
+	@echo "Building plugin $@"
+	@$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ)
+
 #########################################################
 ## IdMap NSS plugins
 
diff --git a/source/configure.in b/source/configure.in
index 5de8a28..495da90 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -809,6 +809,56 @@ if test x"$samba_cv_unixsocket" = x"yes"; then
    AC_DEFINE(HAVE_UNIXSOCKET,1,[If we need to build with unixsocket support])
 fi
 
+#############################################
+# check for fd passing struct via msg_control
+AC_CACHE_CHECK([for fd passing via msg_control],samba_cv_msghdr_msg_control, [
+    AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>],
+[
+	struct msghdr msg;
+	union {
+	      struct cmsghdr cm;
+	      char control[CMSG_SPACE(sizeof(int))];
+	} control_un;
+	msg.msg_control = control_un.control;
+	msg.msg_controllen = sizeof(control_un.control);
+],
+	samba_cv_msghdr_msg_control=yes,samba_cv_msghdr_msg_control=no)])
+if test x"$samba_cv_msghdr_msg_control" = x"yes"; then
+   AC_DEFINE(HAVE_MSGHDR_MSG_CONTROL,1,
+	     [If we can use msg_control for passing file descriptors])
+fi
+
+#############################################
+# check for fd passing struct via msg_acctrights
+AC_CACHE_CHECK([for fd passing via msg_acctrights],
+		samba_cv_msghdr_msg_acctrights, [
+    AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>],
+[
+	struct msghdr msg;
+	int fd;
+	msg.msg_acctrights = (caddr_t) &fd;
+	msg.msg_acctrightslen = sizeof(fd);
+],
+	samba_cv_msghdr_msg_acctrights=yes,samba_cv_msghdr_msg_acctrights=no)])
+if test x"$samba_cv_msghdr_msg_acctrights" = x"yes"; then
+   AC_DEFINE(HAVE_MSGHDR_MSG_ACCTRIGHTS,1,
+	     [If we can use msg_acctrights for passing file descriptors])
+fi
+
+if test x"$samba_cv_msghdr_msg_control" = x"yes" -o \
+	x"$samba_cv_msghdr_msg_acctright" = x"yes"; then
+	default_shared_modules="$default_shared_modules vfs_aio_fork"
+fi
 
 AC_CACHE_CHECK([for sig_atomic_t type],samba_cv_sig_atomic_t, [
     AC_TRY_COMPILE([
@@ -6038,6 +6088,7 @@ SMB_MODULE(vfs_gpfs, \$(VFS_GPFS_OBJ), "bin/gpfs.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_aio_fork, \$(VFS_AIO_FORK_OBJ), "bin/aio_fork.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS)
diff --git a/source/modules/vfs_aio_fork.c b/source/modules/vfs_aio_fork.c
new file mode 100644
index 0000000..21f63d0
--- /dev/null
+++ b/source/modules/vfs_aio_fork.c
@@ -0,0 +1,728 @@
+/*
+ * Simulate the Posix AIO using mmap/fork
+ *
+ * Copyright (C) Volker Lendecke 2008
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+struct mmap_area {
+	size_t size;
+	volatile void *ptr;
+};
+
+static int mmap_area_destructor(struct mmap_area *area)
+{
+	munmap((void *)area->ptr, area->size);
+	return 0;
+}
+
+static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
+{
+	struct mmap_area *result;
+	int fd;
+
+	result = talloc(mem_ctx, struct mmap_area);
+	if (result == NULL) {
+		DEBUG(0, ("talloc failed\n"));
+		goto fail;
+	}
+
+	fd = open("/dev/zero", O_RDWR);
+	if (fd == -1) {
+		DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
+			  strerror(errno)));
+		goto fail;
+	}
+
+	result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
+			   MAP_SHARED|MAP_FILE, fd, 0);
+	if (result->ptr == MAP_FAILED) {
+		DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
+		goto fail;
+	}
+
+	result->size = size;
+	talloc_set_destructor(result, mmap_area_destructor);
+
+	return result;
+
+fail:
+	TALLOC_FREE(result);
+	return NULL;
+}
+
+struct rw_cmd {
+	size_t n;
+	SMB_OFF_T offset;
+	bool read_cmd;
+};
+
+struct rw_ret {
+	ssize_t size;
+	int ret_errno;
+};
+
+struct aio_child_list;
+
+struct aio_child {
+	struct aio_child *prev, *next;
+	struct aio_child_list *list;
+	SMB_STRUCT_AIOCB *aiocb;
+	pid_t pid;
+	int sockfd;
+	struct fd_event *sock_event;
+	struct rw_ret retval;
+	struct mmap_area *map;	/* ==NULL means write request */
+	bool dont_delete;	/* Marked as in use since last cleanup */
+	bool cancelled;
+	bool read_cmd;
+};
+
+struct aio_child_list {
+	struct aio_child *children;
+	struct timed_event *cleanup_event;
+};
+
+static void free_aio_children(void **p)
+{
+	TALLOC_FREE(*p);
+}
+
+static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
+{
+	struct msghdr msg;
+	struct iovec iov[1];
+	ssize_t n;
+#ifndef HAVE_MSGHDR_MSG_CONTROL
+	int newfd;
+#endif
+
+#ifdef	HAVE_MSGHDR_MSG_CONTROL
+	union {
+	  struct cmsghdr	cm;
+	  char				control[CMSG_SPACE(sizeof(int))];
+	} control_un;
+	struct cmsghdr	*cmptr;
+
+	msg.msg_control = control_un.control;
+	msg.msg_controllen = sizeof(control_un.control);
+#else
+#if HAVE_MSGHDR_MSG_ACCTRIGHTS
+	msg.msg_accrights = (caddr_t) &newfd;
+	msg.msg_accrightslen = sizeof(int);
+#else
+#error Can not pass file descriptors
+#endif
+#endif
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+
+	iov[0].iov_base = ptr;
+	iov[0].iov_len = nbytes;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+
+	if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
+		return(n);
+	}
+
+#ifdef	HAVE_MSGHDR_MSG_CONTROL
+	if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
+	    && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
+		if (cmptr->cmsg_level != SOL_SOCKET) {
+			DEBUG(10, ("control level != SOL_SOCKET"));
+			errno = EINVAL;
+			return -1;
+		}
+		if (cmptr->cmsg_type != SCM_RIGHTS) {
+			DEBUG(10, ("control type != SCM_RIGHTS"));
+			errno = EINVAL;
+			return -1;
+		}
+		*recvfd = *((int *) CMSG_DATA(cmptr));
+	} else {
+		*recvfd = -1;		/* descriptor was not passed */
+	}
+#else
+	if (msg.msg_accrightslen == sizeof(int)) {
+		*recvfd = newfd;
+	}
+	else {
+		*recvfd = -1;		/* descriptor was not passed */
+	}
+#endif
+
+	return(n);
+}
+
+static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
+{
+	struct msghdr	msg;
+	struct iovec	iov[1];
+
+#ifdef	HAVE_MSGHDR_MSG_CONTROL
+	union {
+		struct cmsghdr	cm;
+		char control[CMSG_SPACE(sizeof(int))];
+	} control_un;
+	struct cmsghdr	*cmptr;
+
+	ZERO_STRUCT(msg);
+	ZERO_STRUCT(control_un);
+
+	msg.msg_control = control_un.control;
+	msg.msg_controllen = sizeof(control_un.control);
+
+	cmptr = CMSG_FIRSTHDR(&msg);
+	cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+	cmptr->cmsg_level = SOL_SOCKET;
+	cmptr->cmsg_type = SCM_RIGHTS;
+	*((int *) CMSG_DATA(cmptr)) = sendfd;
+#else
+	ZERO_STRUCT(msg);
+	msg.msg_accrights = (caddr_t) &sendfd;
+	msg.msg_accrightslen = sizeof(int);
+#endif
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+
+	ZERO_STRUCT(iov);
+	iov[0].iov_base = ptr;
+	iov[0].iov_len = nbytes;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+
+	return (sendmsg(fd, &msg, 0));
+}
+
+static void aio_child_cleanup(struct event_context *event_ctx,
+			      struct timed_event *te,
+			      const struct timeval *now,
+			      void *private_data)
+{
+	struct aio_child_list *list = talloc_get_type_abort(
+		private_data, struct aio_child_list);
+	struct aio_child *child, *next;
+
+	TALLOC_FREE(list->cleanup_event);
+
+	for (child = list->children; child != NULL; child = next) {
+		next = child->next;
+
+		if (child->aiocb != NULL) {
+			DEBUG(10, ("child %d currently active\n",
+				   (int)child->pid));
+			continue;
+		}
+
+		if (child->dont_delete) {
+			DEBUG(10, ("Child %d was active since last cleanup\n",
+				   (int)child->pid));
+			child->dont_delete = false;
+			continue;
+		}
+
+		DEBUG(10, ("Child %d idle for more than 30 seconds, "
+			   "deleting\n", (int)child->pid));
+
+		TALLOC_FREE(child);
+	}
+
+	if (list->children != NULL) {
+		/*
+		 * Re-schedule the next cleanup round
+		 */
+		list->cleanup_event = event_add_timed(smbd_event_context(), list,
+						      timeval_add(now, 30, 0),
+						      "aio_child_cleanup",
+						      aio_child_cleanup, list);
+
+	}
+}
+
+static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
+{
+	struct aio_child_list *data = NULL;
+
+	if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
+		SMB_VFS_HANDLE_GET_DATA(handle, data, struct aio_child_list,
+					return NULL);
+	}
+
+	if (data == NULL) {
+		data = TALLOC_ZERO_P(NULL, struct aio_child_list);
+		if (data == NULL) {
+			return NULL;
+		}
+	}
+
+	/*
+	 * Regardless of whether the child_list had been around or not, make
+	 * sure that we have a cleanup timed event. This timed event will
+	 * delete itself when it finds that no children are around anymore.
+	 */
+
+	if (data->cleanup_event == NULL) {
+		data->cleanup_event = event_add_timed(smbd_event_context(), data,
+						      timeval_current_ofs(30, 0),
+						      "aio_child_cleanup",
+						      aio_child_cleanup, data);
+		if (data->cleanup_event == NULL) {
+			TALLOC_FREE(data);
+			return NULL;
+		}
+	}
+
+	if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
+		SMB_VFS_HANDLE_SET_DATA(handle, data, free_aio_children,
+					struct aio_child_list, return False);
+	}
+
+	return data;
+}
+
+static void aio_child_loop(int sockfd, struct mmap_area *map)
+{
+	while (true) {
+		int fd = -1;
+		ssize_t ret;
+		struct rw_cmd cmd_struct;
+		struct rw_ret ret_struct;
+
+		ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
+		if (ret != sizeof(cmd_struct)) {
+			DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
+				   strerror(errno)));
+			exit(1);
+		}
+
+		DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
+			   cmd_struct.read_cmd ? "read" : "write",
+			   (int)cmd_struct.n, (int)cmd_struct.offset, fd));
+
+#ifdef ENABLE_BUILD_FARM_HACKS
+		{
+			/*
+			 * In the build farm, we want erratic behaviour for
+			 * async I/O times
+			 */
+			uint8_t randval;
+			unsigned msecs;
+			/*
+			 * use generate_random_buffer, we just forked from a
+			 * common parent state
+			 */
+			generate_random_buffer(&randval, sizeof(randval));
+			msecs = randval + 20;
+			DEBUG(10, ("delaying for %u msecs\n", msecs));
+			smb_msleep(msecs);
+		}
+#endif
+
+
+		ZERO_STRUCT(ret_struct);
+
+		if (cmd_struct.read_cmd) {
+			ret_struct.size = sys_pread(
+				fd, (void *)map->ptr, cmd_struct.n,
+				cmd_struct.offset);
+		}
+		else {
+			ret_struct.size = sys_pwrite(
+				fd, (void *)map->ptr, cmd_struct.n,
+				cmd_struct.offset);
+		}
+
+		DEBUG(10, ("aio_child_loop: syscall returned %d\n",
+			   (int)ret_struct.size));
+
+		if (ret_struct.size == -1) {
+			ret_struct.ret_errno = errno;
+		}
+
+		ret = write_data(sockfd, (char *)&ret_struct,
+				 sizeof(ret_struct));
+		if (ret != sizeof(ret_struct)) {
+			DEBUG(10, ("could not write ret_struct: %s\n",
+				   strerror(errno)));
+			exit(2);
+		}
+
+		close(fd);
+	}
+}
+
+static void handle_aio_completion(struct event_context *event_ctx,
+				  struct fd_event *event, uint16 flags,
+				  void *p)
+{
+	struct aio_child *child = (struct aio_child *)p;
+	uint16 mid;
+
+	DEBUG(10, ("handle_aio_completion called with flags=%d\n", flags));
+
+	if ((flags & EVENT_FD_READ) == 0) {
+		return;
+	}
+
+	if (!NT_STATUS_IS_OK(read_data(child->sockfd,
+				       (char *)&child->retval,
+				       sizeof(child->retval)))) {
+		DEBUG(0, ("aio child %d died\n", (int)child->pid));
+		child->retval.size = -1;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list