svn commit: samba r16814 - in trunk/source: . modules

jpeach at samba.org jpeach at samba.org
Wed Jul 5 05:55:04 GMT 2006


Author: jpeach
Date: 2006-07-05 05:55:03 +0000 (Wed, 05 Jul 2006)
New Revision: 16814

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=16814

Log:
New VFS module "cacheprime". This is useful for equipment where
it is important to minimise the number of actual disk reads or
to make sure that actual disk reads are of a particular size.

Added:
   trunk/source/modules/vfs_cacheprime.c
Modified:
   trunk/source/Makefile.in
   trunk/source/configure.in


Changeset:
Modified: trunk/source/Makefile.in
===================================================================
--- trunk/source/Makefile.in	2006-07-05 03:40:40 UTC (rev 16813)
+++ trunk/source/Makefile.in	2006-07-05 05:55:03 UTC (rev 16814)
@@ -382,6 +382,7 @@
 VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o
 VFS_AFSACL_OBJ = modules/vfs_afsacl.o
 VFS_CATIA_OBJ = modules/vfs_catia.o
+VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -1407,6 +1408,10 @@
 	@$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_CATIA_OBJ:.o=. at PICSUFFIX@) \
 		@SONAMEFLAG@`basename $@`
 
+bin/cacheprime. at SHLIBEXT@: $(VFS_CACHEPRIME_OBJ:.o=. at PICSUFFIX@)
+	@echo "Building plugin $@"
+	@$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_CACHEPRIME_OBJ:.o=. at PICSUFFIX@) \
+		@SONAMEFLAG@`basename $@`
 
 bin/wbinfo at EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy
 	@echo Linking $@

Modified: trunk/source/configure.in
===================================================================
--- trunk/source/configure.in	2006-07-05 03:40:40 UTC (rev 16813)
+++ trunk/source/configure.in	2006-07-05 05:55:03 UTC (rev 16814)
@@ -5593,6 +5593,8 @@
 SMB_MODULE(vfs_shadow_copy, \$(VFS_SHADOW_COPY_OBJ), "bin/shadow_copy.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_afsacl, \$(VFS_AFSACL_OBJ), "bin/afsacl.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_catia, \$(VFS_CATIA_OBJ), "bin/catia.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_cacheprime, \$(VFS_CACHEPRIME_OBJ), "bin/cacheprime.$SHLIBEXT", VFS)
+
 SMB_SUBSYSTEM(VFS,smbd/vfs.o)
 
 AC_DEFINE_UNQUOTED(STRING_STATIC_MODULES, "$string_static_modules", [String list of builtin modules])

Added: trunk/source/modules/vfs_cacheprime.c
===================================================================
--- trunk/source/modules/vfs_cacheprime.c	2006-07-05 03:40:40 UTC (rev 16813)
+++ trunk/source/modules/vfs_cacheprime.c	2006-07-05 05:55:03 UTC (rev 16814)
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) James Peach 2005-2006
+ *
+ * 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"
+
+/* Cache priming module.
+ *
+ * The purpose of this module is to do RAID stripe width reads to prime the
+ * buffer cache to do zero-copy I/O for subsequent sendfile calls. The idea is
+ * to do a single large read at the start of the file to make sure that most or
+ * all of the file is pulled into the buffer cache. Subsequent I/Os have
+ * reduced latency.
+ *
+ * Tunables.
+ *
+ *      cacheprime:rsize    Amount of readahead in bytes. This should be a
+ *                          multiple of the RAID stripe width.
+ *      cacheprime:debug    Debug level at which to emit messages.
+ */
+
+#define READAHEAD_MIN       (128 * 1024)        /* min is 128 KiB */
+#define READAHEAD_MAX       (100 * 1024 * 1024) /* max is 100 MiB */
+
+#define MODULE "cacheprime"
+
+static int module_debug;
+static ssize_t g_readsz = 0;
+static void * g_readbuf = NULL;
+
+static SMB_OFF_T conv_str_size(const char * str)
+{
+        SMB_OFF_T lval;
+        char * end;
+
+        if (str == NULL || *str == '\0') {
+                return 0;
+        }
+
+        if (sizeof(SMB_OFF_T) == 8) {
+                lval = strtoull(str, &end, 10 /* base */);
+        } else {
+                lval = strtoul(str, &end, 10 /* base */);
+        }
+
+        if (end == NULL || end == str) {
+                return 0;
+        }
+
+        if (*end) {
+                if (strwicmp(end, "K") == 0) {
+                        lval *= 1024ULL;
+                } else if (strwicmp(end, "M") == 0) {
+                        lval *= (1024ULL * 1024ULL);
+                } else if (strwicmp(end, "G") == 0) {
+                        lval *= (1024ULL * 1024ULL * 1024ULL);
+                } else if (strwicmp(end, "T") == 0) {
+                        lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
+                } else if (strwicmp(end, "P") == 0) {
+                        lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
+                } else {
+                        return 0;
+                }
+            }
+
+        return lval;
+}
+
+/* Prime the kernel buffer cache with data from the specified file. We use
+ * per-fsp data to make sure we only ever do this once. If pread is being
+ * emulated by seek/read/seek, when this will suck quite a lot.
+ */
+static BOOL prime_cache(
+            struct vfs_handle_struct *  handle,
+			files_struct *		        fsp,
+			int			                fd,
+			SMB_OFF_T		            offset,
+			size_t			            count)
+{
+        SMB_OFF_T * last;
+        ssize_t nread;
+
+        last = VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T);
+        if (!last) {
+                return False;
+        }
+
+        if (*last == -1) {
+            /* Readahead disabled. */
+            return False;
+        }
+
+        if ((*last + g_readsz) > (offset + count)) {
+            /* Skip readahead ... we've already been here. */
+            return False;
+        }
+
+        DEBUG(module_debug,
+            ("%s: doing readahead of %lld bytes at %lld for %s\n",
+            MODULE, (long long)g_readsz, (long long)*last,
+            fsp->fsp_name));
+
+        nread = sys_pread(fd, g_readbuf, g_readsz, *last);
+        if (nread < 0) {
+            *last = -1;
+            return False;
+        }
+
+        *last += nread;
+        return True;
+}
+
+static int cprime_connect(
+                struct vfs_handle_struct *  handle,
+                const char *                service,
+                const char *                user)
+{
+        module_debug = lp_parm_int(SNUM(handle->conn), MODULE, "debug", 100);
+        if (g_readbuf) {
+                /* Only allocate g_readbuf once. If the config changes and
+                 * another client multiplexes onto this smbd, we don't want
+                 * to risk memory corruption.
+                 */
+                return SMB_VFS_NEXT_CONNECT(handle, service, user);
+        }
+
+        g_readsz = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+                                        MODULE, "rsize", NULL));
+
+        if (g_readsz < READAHEAD_MIN) {
+                DEBUG(module_debug, ("%s: %ld bytes of readahead "
+                            "requested, using minimum of %u\n",
+                            MODULE, (long)g_readsz, READAHEAD_MIN));
+                g_readsz = READAHEAD_MIN;
+        } else if (g_readsz > READAHEAD_MAX) {
+                DEBUG(module_debug, ("%s: %ld bytes of readahead "
+                            "requested, using maximum of %u\n",
+                            MODULE, (long)g_readsz, READAHEAD_MAX));
+                g_readsz = READAHEAD_MAX;
+        }
+
+        if ((g_readbuf = SMB_MALLOC(g_readsz)) == NULL) {
+                /* Turn off readahead if we can't get a buffer. */
+                g_readsz = 0;
+        }
+
+        return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static ssize_t cprime_sendfile(
+                struct vfs_handle_struct *  handle,
+                int                         tofd,
+                files_struct *              fsp,
+                int                         fromfd,
+                const DATA_BLOB *           header,
+                SMB_OFF_T                   offset,
+                size_t                      count)
+{
+        if (g_readbuf && offset == 0) {
+                prime_cache(handle, fsp, fromfd, offset, count);
+        }
+
+        return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd,
+                                     header, offset, count);
+}
+
+static ssize_t cprime_read(
+                vfs_handle_struct * handle,
+                files_struct *      fsp,
+                int                 fd,
+                void *              data,
+                size_t              count)
+{
+        SMB_OFF_T offset;
+
+        offset = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+        if (offset >= 0 && g_readbuf)  {
+                prime_cache(handle, fsp, fd, offset, count);
+                SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET);
+        }
+
+        return SMB_VFS_NEXT_READ(handle, fsp, fd, data, count);
+}
+
+static ssize_t cprime_pread(
+                vfs_handle_struct * handle,
+                files_struct *      fsp,
+                int                 fd,
+                void *              data,
+		        size_t              count,
+                SMB_OFF_T           offset)
+{
+        if (g_readbuf) {
+                prime_cache(handle, fsp, fd, offset, count);
+        }
+
+        return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
+}
+
+static vfs_op_tuple cprime_ops [] =
+{
+        {SMB_VFS_OP(cprime_sendfile),
+                SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
+        {SMB_VFS_OP(cprime_pread),
+                SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
+        {SMB_VFS_OP(cprime_read),
+                SMB_VFS_OP_READ, SMB_VFS_LAYER_TRANSPARENT},
+        {SMB_VFS_OP(cprime_connect),
+                SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
+
+        {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+/* -------------------------------------------------------------------------
+ * Samba module initialisation entry point.
+ * -------------------------------------------------------------------------
+ */
+
+NTSTATUS vfs_cacheprime_init(void)
+{
+    return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, cprime_ops);
+}
+
+/* vim: set sw=4 ts=4 tw=79 et: */



More information about the samba-cvs mailing list