Mercurial > illumos > onarm
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"); +}