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

jpeach at samba.org jpeach at samba.org
Fri Jul 7 02:13:48 GMT 2006


Author: jpeach
Date: 2006-07-07 02:13:46 +0000 (Fri, 07 Jul 2006)
New Revision: 16849

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

Log:
New VFS module to preallocate file extents at creation time.

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


Changeset:
Modified: trunk/source/Makefile.in
===================================================================
--- trunk/source/Makefile.in	2006-07-07 02:09:49 UTC (rev 16848)
+++ trunk/source/Makefile.in	2006-07-07 02:13:46 UTC (rev 16849)
@@ -383,6 +383,7 @@
 VFS_AFSACL_OBJ = modules/vfs_afsacl.o
 VFS_CATIA_OBJ = modules/vfs_catia.o
 VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o
+VFS_PREALLOC_OBJ = modules/vfs_prealloc.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -1413,6 +1414,11 @@
 	@$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_CACHEPRIME_OBJ:.o=. at PICSUFFIX@) \
 		@SONAMEFLAG@`basename $@`
 
+bin/prealloc. at SHLIBEXT@: $(VFS_PREALLOC_OBJ:.o=. at PICSUFFIX@)
+	@echo "Building plugin $@"
+	@$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_PREALLOC_OBJ:.o=. at PICSUFFIX@) \
+		@SONAMEFLAG@`basename $@`
+
 bin/wbinfo at EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy
 	@echo Linking $@
 	@$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(LDFLAGS) $(WBINFO_OBJ) $(DYNEXP) $(LIBS) @POPTLIBS@

Modified: trunk/source/configure.in
===================================================================
--- trunk/source/configure.in	2006-07-07 02:09:49 UTC (rev 16848)
+++ trunk/source/configure.in	2006-07-07 02:13:46 UTC (rev 16849)
@@ -864,6 +864,7 @@
 AC_CHECK_HEADERS(sys/sysmacros.h security/_pam_macros.h dlfcn.h)
 AC_CHECK_HEADERS(sys/syslog.h syslog.h)
 AC_CHECK_HEADERS(langinfo.h locale.h)
+AC_CHECK_HEADERS(xfs/libxfs.h)
 
 AC_CHECK_HEADERS(rpcsvc/yp_prot.h,,,[[
 #if HAVE_RPC_RPC_H
@@ -5604,6 +5605,7 @@
 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_MODULE(vfs_prealloc, \$(VFS_PREALLOC_OBJ), "bin/prealloc.$SHLIBEXT", VFS)
 
 SMB_SUBSYSTEM(VFS,smbd/vfs.o)
 

Added: trunk/source/modules/vfs_prealloc.c
===================================================================
--- trunk/source/modules/vfs_prealloc.c	2006-07-07 02:09:49 UTC (rev 16848)
+++ trunk/source/modules/vfs_prealloc.c	2006-07-07 02:13:46 UTC (rev 16849)
@@ -0,0 +1,252 @@
+/*
+ * XFS preallocation support module.
+ *
+ * Copyright (c) James Peach 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"
+
+/* Extent preallocation module.
+ *
+ * The purpose of this module is to preallocate space on the filesystem when
+ * we have a good idea of how large files are supposed to be. This lets writes
+ * proceed without having to allocate new extents and results in better file
+ * layouts on disk.
+ *
+ * Currently only implemented for XFS. This module is based on an original idea
+ * and implementation by Sebastian Brings.
+ *
+ * Tunables.
+ *
+ *      prealloc: <ext>	    Number of bytes to preallocate for a file with
+ *			    the matching extension.
+ *      prealloc:debug	    Debug level at which to emit messages.
+ *
+ * Example.
+ *
+ *	prealloc:mpeg = 500M  # Preallocate *.mpeg to 500 MiB.
+ */
+
+#ifdef HAVE_XFS_LIBXFS_H
+#include <xfs/libxfs.h>
+#define lock_type xfs_flock64_t
+#else
+#define lock_type struct flock64
+#endif
+
+#define MODULE "prealloc"
+static int module_debug;
+
+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;
+}
+
+static int preallocate_space(int fd, SMB_OFF_T size)
+{
+	lock_type fl = {0};
+	int err;
+
+	if (size <= 0) {
+		return 0;
+	}
+
+	fl.l_whence = SEEK_SET;
+	fl.l_start = 0;
+	fl.l_len = size;
+
+	/* IMPORTANT: We use RESVSP because we want the extents to be
+	 * allocated, but we don't want the allocation to show up in
+	 * st_size or persist after the close(2).
+	 */
+
+#if defined(XFS_IOC_RESVSP64)
+	/* On Linux this comes in via libxfs.h. */
+	err = xfsctl(NULL, fd, XFS_IOC_RESVSP64, &fl);
+#elif defined(F_RESVSP64)
+	/* On IRIX, this comes from fcntl.h. */
+	err = fcntl(fd, F_RESVSP64, &fl);
+#else
+	err = -1;
+	errno = ENOSYS;
+#endif
+
+	if (err) {
+		DEBUG(module_debug,
+			("%s: preallocate failed on fd=%d size=%lld: %s\n",
+			MODULE, fd, (long long)size, strerror(errno)));
+	}
+
+	return err;
+}
+
+static int prealloc_connect(
+                struct vfs_handle_struct *  handle,
+                const char *                service,
+                const char *                user)
+{
+	    module_debug = lp_parm_int(SNUM(handle->conn),
+					MODULE, "debug", 100);
+
+	    return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static int prealloc_open(vfs_handle_struct* handle,
+			const char *	    fname,
+			files_struct *	    fsp,
+			int		    flags,
+			mode_t		    mode)
+{
+	int fd;
+	off64_t size = 0;
+
+	const char * dot;
+	char fext[10];
+
+	if (!(flags & (O_CREAT|O_TRUNC))) {
+		/* Caller is not intending to rewrite the file. Let's not mess
+		 * with the allocation in this case.
+		 */
+		goto normal_open;
+	}
+
+	*fext = '\0';
+	dot = strrchr(fname, '.');
+	if (dot && *++dot) {
+		if (strlen(dot) < sizeof(fext)) {
+			strncpy(fext, dot, sizeof(fext));
+			strnorm(fext, CASE_LOWER);
+		}
+	}
+
+	if (*fext == '\0') {
+		goto normal_open;
+	}
+
+	/* Syntax for specifying preallocation size is:
+	 *	MODULE: <extension> = <size>
+	 * where
+	 *	<extension> is the file extension in lower case
+	 *	<size> is a size like 10, 10K, 10M
+	 */
+	size = conv_str_size(lp_parm_const_string(SNUM(handle->conn), MODULE,
+						    fext, NULL));
+	if (size <= 0) {
+		/* No need to preallocate this file. */
+		goto normal_open;
+	}
+
+	fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+	if (fd < 0) {
+		return fd;
+	}
+
+	/* Prellocate only if the file is being created or replaced. Note that
+	 * Samba won't ever pass down O_TRUNC, which is why we have to handle
+	 * truncate calls specially.
+	 */
+	if ((flags & O_CREAT) || (flags & O_TRUNC)) {
+		SMB_OFF_T * psize;
+
+		psize = VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T);
+		if (psize == NULL || *psize == -1) {
+			return fd;
+		}
+
+		DEBUG(module_debug,
+			("%s: preallocating %s (fd=%d) to %lld bytes\n",
+			MODULE, fname, fd, (long long)size));
+
+		*psize = size;
+		if (preallocate_space(fd, *psize) < 0) {
+			VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+		}
+	}
+
+	return fd;
+
+normal_open:
+	/* We are not creating or replacing a file. Skip the
+	 * preallocation.
+	 */
+	DEBUG(module_debug, ("%s: skipping preallocation for %s\n",
+		    MODULE, fname));
+	return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+}
+
+static int prealloc_ftruncate(vfs_handle_struct * handle,
+			files_struct *	fsp,
+			int		fd,
+			SMB_OFF_T	offset)
+{
+	SMB_OFF_T *psize;
+	int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset);
+
+	/* Maintain the allocated space even in the face of truncates. */
+	if ((psize = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
+		preallocate_space(fd, *psize);
+	}
+
+	return ret;
+}
+
+static vfs_op_tuple prealloc_op_tuples[] = {
+	{SMB_VFS_OP(prealloc_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+	{SMB_VFS_OP(prealloc_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_TRANSPARENT},
+	{SMB_VFS_OP(prealloc_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+	{NULL,	SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_prealloc_init(void)
+{
+	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+		MODULE, prealloc_op_tuples);
+}
+



More information about the samba-cvs mailing list