diff usr/src/cmd/fs.d/cachefs/cfsd/cfsd_logfile.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/cachefs/cfsd/cfsd_logfile.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,565 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1994-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)cfsd_logfile.c	1.7	05/06/08 SMI"
+
+/*
+ * Methods of the cfsd_maptbl classes.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <synch.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <sys/cred.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/fs/cachefs_fs.h>
+#include <sys/fs/cachefs_dlog.h>
+#include <mdbug/mdbug.h>
+#include "cfsd.h"
+#include "cfsd_logfile.h"
+
+/*
+ *			cfsd_logfile_create
+ *
+ * Description:
+ * Arguments:
+ * Returns:
+ * Preconditions:
+ */
+cfsd_logfile_object_t *
+cfsd_logfile_create(void)
+{
+	cfsd_logfile_object_t *logfile_object_p;
+
+	dbug_enter("cfsd_logfile_create");
+
+	logfile_object_p = cfsd_calloc(sizeof (cfsd_logfile_object_t));
+	logfile_object_p->i_fid = -1;
+	logfile_object_p->i_map_entry.i_pa = NULL;
+	logfile_object_p->i_map_entry.i_paoff = 0;
+	logfile_object_p->i_map_entry.i_paend = 0;
+	logfile_object_p->i_map_entry.i_palen = 0;
+	logfile_object_p->i_map_offset.i_pa = NULL;
+	logfile_object_p->i_map_offset.i_paoff = 0;
+	logfile_object_p->i_map_offset.i_paend = 0;
+	logfile_object_p->i_map_offset.i_palen = 0;
+	logfile_object_p->i_cur_offset = 0;
+	logfile_object_p->i_cur_entry = NULL;
+	dbug_leave("cfsd_logfile_create");
+	return (logfile_object_p);
+}
+
+/*
+ *			cfsd_logfile_destroy
+ *
+ * Description:
+ * Arguments:
+ * Returns:
+ * Preconditions:
+ */
+void
+cfsd_logfile_destroy(cfsd_logfile_object_t *logfile_object_p)
+{
+	dbug_enter("cfsd_logfile_destroy");
+	logfile_sync(logfile_object_p);
+	logfile_teardown(logfile_object_p);
+	cfsd_free(logfile_object_p);
+	dbug_leave("cfsd_logfile_destroy");
+}
+
+/*
+ *			logfile_domap
+ *
+ * Description:
+ *	Maps in the specified section of the file.
+ * Arguments:
+ *	off	The offset to map in.  Must be i_pagesize aligned.
+ *	map	0 means use map_entry, 1 means use map_offset
+ * Returns:
+ *	Returns 0 for success or an errno value on failure.
+ * Preconditions:
+ */
+int
+logfile_domap(cfsd_logfile_object_t *logfile_object_p, off_t off, int map)
+{
+	int xx;
+	int len;
+	mmap_info_t *mmp;
+
+	dbug_enter("logfile_domap");
+	dbug_precond(logfile_object_p->i_fid >= 0);
+
+	len = logfile_object_p->i_maplen;
+	mmp = (map == 0) ?
+		&logfile_object_p->i_map_entry :
+		&logfile_object_p->i_map_offset;
+
+	logfile_object_p->i_stat_mapmove++;
+
+	/* destroy old mapping if it exists */
+	if (mmp->i_pa) {
+		/* determine how far we have to move the map */
+		logfile_object_p->i_stat_mapdist += abs(mmp->i_paoff - off);
+
+		/* remove the map */
+		xx = munmap(mmp->i_pa, mmp->i_palen);
+		if (xx == -1) {
+			xx = errno;
+			dbug_print(("error", "Could not unmap %s, %d, %p, %d",
+			    logfile_object_p->i_name, xx, mmp->i_pa,
+			    mmp->i_palen));
+		}
+		mmp->i_pa = NULL;
+		mmp->i_palen = 0;
+		mmp->i_paoff = 0;
+		mmp->i_paend = 0;
+	}
+
+	/* do the mapping */
+	mmp->i_pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+	    logfile_object_p->i_fid, off);
+	if (mmp->i_pa == MAP_FAILED) {
+		xx = errno;
+		dbug_print(("error",
+		    "Could not map %s, error %d, off %d, len %d",
+		    logfile_object_p->i_name, xx, off, len));
+		mmp->i_pa = NULL;
+		dbug_leave("logfile_domap");
+		return (xx);
+	}
+
+	mmp->i_palen = len;
+	mmp->i_paoff = off;
+	mmp->i_paend = off + len - 1;
+	dbug_leave("logfile_domap");
+	return (0);
+}
+
+/*
+ *			logfile_getaddr
+ *
+ * Description:
+ *	Returns an address of a particular offset in the file.
+ *	The size of the item to map is i_maxmap
+ *	This routine assumes that if we have to remap that i_maxmap
+ *	will fit inside the default mapping size.
+ * Arguments:
+ *	start	offset in the file to map
+ *	map	0 means use map_entry, 1 means use map_offset
+ * Returns:
+ *	Returns NULL for a failure with the mapping file.
+ * Preconditions:
+ */
+caddr_t
+logfile_getaddr(cfsd_logfile_object_t *logfile_object_p, off_t start, int map)
+{
+	mmap_info_t *mmp;
+	caddr_t pa;
+	off_t end;
+
+	dbug_enter("logfile_getaddr");
+
+	mmp = (map == 0) ?
+	    &logfile_object_p->i_map_entry :
+	    &logfile_object_p->i_map_offset;
+
+	/* determine the end of the item */
+	end = start + logfile_object_p->i_maxmap - 1;
+
+	/* map the entry in if necessary */
+	if ((start < mmp->i_paoff) || (mmp->i_paend < end)) {
+		if (logfile_domap(logfile_object_p,
+		    start & logfile_object_p->i_pagemask, map)) {
+			dbug_leave("logfile_getaddr");
+			return (NULL);
+		}
+		dbug_assert((mmp->i_paoff <= start) && (end <= mmp->i_paend));
+	}
+
+	/* make an address and return it */
+	pa = mmp->i_pa + (start - mmp->i_paoff);
+	dbug_leave("logfile_getaddr");
+	return (pa);
+}
+
+/*
+ *			logfile_setup
+ *
+ * Description:
+ *	Sets up to use the specified file.
+ *	Call this routine before using any of the other routines.
+ * Arguments:
+ *	filename	file to use
+ *	maxmap		max amount needed after a map
+ * Returns:
+ *	Returns 0 for success or an errno value.
+ * Preconditions:
+ *	precond(filename)
+ */
+int
+logfile_setup(cfsd_logfile_object_t *logfile_object_p,
+	const char *filename, int maxmap)
+{
+	int xx;
+	struct stat sinfo;
+	long *versionp;
+
+	dbug_enter("logfile_setup");
+	dbug_precond(filename);
+
+	/* clean up from a previous setup */
+	logfile_teardown(logfile_object_p);
+
+	strlcpy(logfile_object_p->i_name, filename,
+	    sizeof (logfile_object_p->i_name));
+	dbug_print(("info", "filename %s", logfile_object_p->i_name));
+	logfile_object_p->i_maxmap = maxmap;
+
+	/* get the page info */
+	logfile_object_p->i_pagesize = PAGESIZE;
+	logfile_object_p->i_pagemask = PAGEMASK;
+	logfile_object_p->i_maplen = logfile_object_p->i_pagesize * 100;
+
+	/* open the file */
+	logfile_object_p->i_fid = open(logfile_object_p->i_name,
+	    O_RDWR | O_NONBLOCK);
+	if (logfile_object_p->i_fid == -1) {
+		xx = errno;
+		dbug_print(("error", "Could not open %s, %d",
+		    logfile_object_p->i_name, xx));
+		dbug_leave("logfile_setup");
+		return (xx);
+	}
+
+	/* get the size and type of file */
+	xx = fstat(logfile_object_p->i_fid, &sinfo);
+	if (xx) {
+		xx = errno;
+		if (xx == ENOENT) {
+			dbug_print(("info", "No log file to roll"));
+		} else {
+			dbug_print(("error", "Could not stat %s, %d",
+			    logfile_object_p->i_name, xx));
+		}
+		dbug_leave("logfile_setup");
+		return (xx);
+	}
+	logfile_object_p->i_size = sinfo.st_size;
+
+	/* sanity check, better be a regular file */
+	if (!S_ISREG(sinfo.st_mode)) {
+		xx = ENOTSUP;
+		dbug_print(("error", "%s Not a regular file.",
+		    logfile_object_p->i_name));
+		dbug_leave("logfile_setup");
+		return (xx);
+	}
+
+	/* better not be too small */
+	if (logfile_object_p->i_size < LOGFILE_ENTRY_START) {
+		dbug_print(("error", "File %s is too small %d.",
+		    logfile_object_p->i_name, logfile_object_p->i_size));
+		dbug_leave("logfile_setup");
+		return (EINVAL);
+	}
+
+	/* initialize statistic gathering */
+	logfile_object_p->i_stat_mapmove = 0;
+	logfile_object_p->i_stat_mapdist = 0;
+
+	/* check the version number */
+	versionp = (long *)logfile_getaddr(logfile_object_p, 0, 1);
+	if (versionp == NULL) {
+		dbug_leave("logfile_setup");
+		return (EIO);
+	}
+	if (*versionp != CFS_DLOG_VERSION) {
+		dbug_print(("error", "Log file version mismatch %d != %d",
+		    *versionp, CFS_DLOG_VERSION));
+		dbug_leave("logfile_setup");
+		return (EINVAL);
+	}
+
+	/* return success */
+	dbug_leave("logfile_setup");
+	return (0);
+}
+
+/*
+ *			logfile_teardown
+ *
+ * Description:
+ *	Uninitializes the object.
+ *	Call logfile_setup before using this object again.
+ * Arguments:
+ * Returns:
+ * Preconditions:
+ */
+void
+logfile_teardown(cfsd_logfile_object_t *logfile_object_p)
+{
+	int xx;
+
+	dbug_enter("logfile_teardown");
+
+	if (logfile_object_p->i_map_entry.i_pa) {
+		xx = munmap(logfile_object_p->i_map_entry.i_pa,
+		    logfile_object_p->i_map_entry.i_palen);
+		if (xx == -1) {
+			xx = errno;
+			dbug_print(("error", "Could not unmap %s, %d, %p, %d",
+			    logfile_object_p->i_name, xx,
+			    logfile_object_p->i_map_entry.i_pa,
+			    logfile_object_p->i_map_entry.i_palen));
+		}
+		logfile_object_p->i_map_entry.i_pa = NULL;
+	}
+	logfile_object_p->i_map_entry.i_paoff = 0;
+	logfile_object_p->i_map_entry.i_paend = 0;
+	logfile_object_p->i_map_entry.i_palen = 0;
+
+	if (logfile_object_p->i_map_offset.i_pa) {
+		xx = munmap(logfile_object_p->i_map_offset.i_pa,
+		    logfile_object_p->i_map_offset.i_palen);
+		if (xx == -1) {
+			xx = errno;
+			dbug_print(("error", "Could not unmap %s, %d, %p, %d",
+			    logfile_object_p->i_name, xx,
+			    logfile_object_p->i_map_offset.i_pa,
+			    logfile_object_p->i_map_offset.i_palen));
+		}
+		logfile_object_p->i_map_offset.i_pa = NULL;
+	}
+	logfile_object_p->i_map_offset.i_paoff = 0;
+	logfile_object_p->i_map_offset.i_paend = 0;
+	logfile_object_p->i_map_offset.i_palen = 0;
+
+	if (logfile_object_p->i_fid != -1) {
+		if (close(logfile_object_p->i_fid))
+			dbug_print(("error", "Could not close %s, %d",
+			    logfile_object_p->i_name, errno));
+		logfile_object_p->i_fid = -1;
+	}
+	logfile_object_p->i_cur_offset = 0;
+	logfile_object_p->i_cur_entry = NULL;
+	dbug_leave("logfile_teardown");
+}
+
+/*
+ *			logfile_entry
+ *
+ * Description:
+ *	Sets addrp to the address of the log entry at offset
+ *	The mapping remains in effect until:
+ *		a) this routine is called again
+ *		b) logfile_teardown is called
+ *		c) this object is destroyed
+ * Arguments:
+ *	offset	offset to start of entry
+ *	entpp	place to store address
+ * Returns:
+ *	Returns 0 for success, 1 for EOF, -1 if a fatal error occurs.
+ * Preconditions:
+ *	precond(addrp)
+ */
+int
+logfile_entry(cfsd_logfile_object_t *logfile_object_p,
+	off_t offset,
+	cfs_dlog_entry_t **entpp)
+{
+	cfs_dlog_entry_t *entp;
+
+	dbug_enter("logfile_entry");
+	dbug_precond(entpp);
+	dbug_precond(offset >= sizeof (long));
+
+
+	logfile_object_p->i_stat_nextcnt++;
+
+	/* check for eof */
+	if (offset >= logfile_object_p->i_size) {
+		dbug_leave("logfile_entry");
+		return (1);
+	}
+	dbug_assert((offset & 3) == 0);
+
+	/* get the address of the entry */
+	entp = (cfs_dlog_entry_t *)logfile_getaddr(logfile_object_p, offset, 0);
+	if (entp == NULL) {
+		dbug_leave("logfile_entry");
+		return (-1);
+	}
+	/* sanity check, record should be alligned */
+	if (entp->dl_len & 3) {
+		dbug_print(("error",
+		    "Record at offset %d length is not alligned %d",
+		    offset, entp->dl_len));
+		dbug_leave("logfile_entry");
+		return (-1);
+	}
+
+	/* sanity check record should a reasonable size */
+	if ((entp->dl_len < CFS_DLOG_ENTRY_MINSIZE) ||
+	    (entp->dl_len > CFS_DLOG_ENTRY_MAXSIZE)) {
+		dbug_print(("error",
+		    "Record at offset %d has an invalid size %d", offset,
+		    entp->dl_len));
+		dbug_leave("logfile_entry");
+		return (-1);
+	}
+
+	/* preserve offset and pointer */
+	logfile_object_p->i_cur_offset = offset;
+	logfile_object_p->i_cur_entry = entp;
+
+	/* return success */
+	*entpp = entp;
+	dbug_leave("logfile_entry");
+	return (0);
+}
+
+/*
+ *			logfile_offset
+ *
+ * Description:
+ *	Sets addrp to the address of the specified offset.
+ *	The mapping remains in effect until:
+ *		a) this routine is called again
+ *		b) logfile_teardown is called
+ *		c) this object is destroyed
+ * Arguments:
+ *	offset	offset into file, must be 0 <= offset < i_size
+ *	addrp	returns mapped address
+ * Returns:
+ *	Returns 0 for success, -1 if a fatal error occurs.
+ * Preconditions:
+ *	precond(addrp)
+ */
+int
+logfile_offset(cfsd_logfile_object_t *logfile_object_p,
+	off_t offset,
+	caddr_t *addrp)
+{
+	caddr_t pa;
+
+	dbug_enter("logfile_offset");
+	dbug_precond(addrp);
+	dbug_precond((0 <= offset) && (offset < logfile_object_p->i_size));
+
+	logfile_object_p->i_stat_offcnt++;
+
+	/* get the address for the offset */
+	pa = logfile_getaddr(logfile_object_p, offset, 1);
+	if (pa == NULL) {
+		dbug_leave("logfile_offset");
+		return (-1);
+	}
+	/* return success */
+	*addrp = pa;
+	dbug_leave("logfile_offset");
+	return (0);
+}
+
+/*
+ *			logfile_sync
+ *
+ * Description:
+ *	Performs an fsync on the log file.
+ * Arguments:
+ * Returns:
+ *	Returns 0 for success or an errno value on failure.
+ * Preconditions:
+ */
+int
+logfile_sync(cfsd_logfile_object_t *logfile_object_p)
+{
+	int xx;
+
+	dbug_enter("logfile_sync");
+
+	if (logfile_object_p->i_fid == -1) {
+		dbug_leave("logfile_sync");
+		return (0);
+	}
+	xx = fsync(logfile_object_p->i_fid);
+	if (xx) {
+		xx = errno;
+		dbug_print(("error", "fsync failed %d", xx));
+	}
+	dbug_leave("logfile_sync");
+	return (xx);
+}
+
+/*
+ *			logfile_dumpstats
+ *
+ * Description:
+ *	Prints out various stats about the hashing.
+ * Arguments:
+ * Returns:
+ * Preconditions:
+ */
+void
+logfile_dumpstats(cfsd_logfile_object_t *logfile_object_p)
+{
+	int xx;
+	double dd;
+
+	dbug_enter("logfile_dumpstats");
+
+	dbug_print(("dump", "Request - next %d",
+	    logfile_object_p->i_stat_nextcnt));
+	dbug_print(("dump", "Request - offset %d",
+	    logfile_object_p->i_stat_offcnt));
+	dbug_print(("dump", "Map Moves %d", logfile_object_p->i_stat_mapmove));
+	dbug_print(("dump", "Mapping Size %d", logfile_object_p->i_maplen));
+	dbug_print(("dump", "Item Size %d", logfile_object_p->i_maxmap));
+	dbug_print(("dump", "File Size %d", logfile_object_p->i_size));
+	if (logfile_object_p->i_stat_mapmove == 0) {
+		dbug_leave("logfile_dumpstats");
+		return;
+	}
+
+	dd = (double)logfile_object_p->i_stat_mapmove /
+	    (logfile_object_p->i_stat_nextcnt +
+	    logfile_object_p->i_stat_offcnt);
+	dbug_print(("dump", "Mmap moves per Request %.2f", dd));
+
+	xx = logfile_object_p->i_stat_mapdist /
+	    logfile_object_p->i_stat_mapmove;
+	dbug_print(("dump", "Average distance per mmap moves %d", xx));
+	dbug_leave("logfile_dumpstats");
+}