cachefs_log.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/pathname.h>
#include <sys/sysmacros.h>
/*
* ino64_t is a unsigned long on LP64 and unsigned long long on ILP32,
* the compiler emits many warnings when calling xdr_u_longlong_t with an
* unsigned long pointer on LP64 even though it's safe.
*/
/*
* cfs_time_t is an int in both LP64 and ILP32. To avoid compiler warnings
* define its xdr here explicitly
*/
#define CACHEFS_LOG_MAX_BUFFERED 65536
#define CACHEFS_LOG_LOWATER 8192
#define CACHEFS_LOG_ENCODE_SIZE 4096
#if (defined(_SYSCALL32_IMPL) || defined(_LP64))
if (TIME_OVERFLOW(time)) { \
goto out; \
}
if (TIME_OVERFLOW(time)) { \
return; \
}
#else /* not (_SYSCALL32_IMPL || _LP64) */
#endif /* (_SYSCALL32_IMPL || _LP64) */
typedef struct cachefs_log_work_list {
void *data;
struct cachefs_log_work_list *next;
/* forward declarations of static functions */
static int cachefs_log_save_lc(cachefscache_t *);
struct cachefs_log_logfile_header *);
struct cachefs_log_readlink_record *);
struct cachefs_log_truncate_record *);
struct cachefs_log_populate_record *);
struct cachefs_log_csymlink_record *);
struct cachefs_log_filldir_record *);
struct cachefs_log_mdcreate_record *);
struct cachefs_log_gpfront_record *);
struct cachefs_log_rfdir_record *);
struct cachefs_log_ualloc_record *);
struct cachefs_log_calloc_record *);
struct cachefs_log_nocache_record *);
/*
* cachefs_log_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
*
*
*/
int
{
int error = 0;
/* if they just want to read the kstat, get that out of the way. */
if (rw != KSTAT_WRITE) {
return (0);
}
/* make sure they're passing us a valid control cookie */
return (EIO);
/*
* if logging is currently off
* o insist that we're being handed a logfile path
* o set cl, and give our cachep its value
*
* after that, if something goes wrong, we must call
* cachefs_log_error to clear cachep->c_log.
*/
return (EIO);
return (EIO);
}
}
/*
* if we're being handed an empty logpath, then they must be
* turning off logging; also, logging must have been turned on
* before, or else the previous paragraph would have caught
* it.
*/
0);
return (0);
}
/*
* if we get here, we know that we're being handed a valid log
* control cookie, and that a path is set. try to open the
* log file, even if it's the same path, because they might
* have removed the old log file out from under us. if it
* really is the same file, no harm done.
*/
return (EIO);
}
/*
* if we get here, we have a valid logfile open. we don't do
* anything here with the bitmap of what's being logged, other
* than copy it. we're home free!
*/
return (EIO);
}
return (0);
}
static int
{
int error = 0;
return (EINVAL);
return (error);
return (ENOENT);
return (error);
}
/*
* cachefs_log_cookie_t *cachefs_log_create_cookie(void *)
*
* creates and initializes the cookie, which lives in cachep. called
* from either a kstat write which turns on logging, or from
* initializing cachep when a log-info-file exists.
*/
{
return (NULL);
return (rc);
}
/*
* void cachefs_log_destroy_cookie(cachefs_log_cookie_t *)
*
* destroys the log cookie. called from cachefs_log_error, or from
* destroying the cachep.
*
*/
void
{
return;
}
}
/*
* int cachefs_log_logfile_open(cachefscache_t *, char *)
*
* opens the logfile, and stores the path string if its successful.
*
* returns an errno if one occurred.
*
*/
int
{
int error = 0;
int i;
/* lookup the pathname -- it must already exist! */
if (error)
goto out;
goto out;
}
/* easy out if we just re-opened the same logfile */
goto out;
}
/* XXX we may change this to allow named pipes */
goto out;
}
goto out;
}
/* write out the header */
if (error)
goto out;
/* if we get here, we successfully opened the log. */
/*
* `fake' a mount entry for each mounted cachefs filesystem.
* this is overkill, but it's easiest and most foolproof way
* to do things here. the user-level consumers of the logfile
* have to expect extraneous mount entries and deal with it
* correctly.
*/
for (i = 0; i < cachefs_kstat_key_n; i++) {
k = cachefs_kstat_key + i;
if (! k->ks_mounted)
continue;
(char *)(uintptr_t)k->ks_cacheid);
}
out:
return (error);
}
/*
* called when an error occurred during logging. send the error to
* syslog, invalidate the logfile, and stop logging.
*/
void
{
int writable = 0;
if (getlock)
writable = 1;
if (writable)
0);
if (getlock)
}
static int
{
int Errno = 0;
int gotold = 0;
goto out;
if (error != 0)
goto out;
xdr_destroy(&xdrm);
goto out;
}
xdr_destroy(&xdrm);
gotold = 1;
goto out;
}
}
if (gotold) {
} else {
}
/* these are things that we stomp over for every header write */
goto out;
}
if (error)
goto out;
out:
xdr_destroy(&xdrm);
return (error);
}
/*
* enqueues a record to be written to the logfile.
*/
static void
{
return;
}
return;
}
}
}
/*
* processes the log queue. run by an async worker thread, or via
* cachefs_cache_sync().
*/
void
{
int error = 0;
/*
* NULL out the x_ops field of XDR. this way, if x_ops !=
* NULL, we know that we did the xdr*_create() successfully.
* this is documented in the xdr_create man page.
*/
/* see if we're still logging */
if (getlock)
if (getlock)
return;
}
/* get the work, and let go of the mutex asap. */
if (getlock)
return;
}
if (getlock)
/* we don't use vn_rdwr() because there's no way to set FNONBLOCK */
goto out;
}
(void) xdr_setpos(&xdrm, 0);
/* XXX future -- check for EAGAIN */
goto out;
}
}
out:
xdr_destroy(&xdrm);
/*
* if an error occurred, we need to free the buffers ourselves.
* cachefs_destory_cookie() can't do it.
*/
}
if (error) {
return;
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
/*
* the routines for logging each transaction follow...
*/
void
{
struct cachefs_log_mount_record *record;
char *cacheidt;
/* In Solaris 64 - if can't represent time don't bother */
if (seg == UIO_USERSPACE) {
goto out;
}
goto out;
}
} else {
}
goto out;
}
if (fscp) {
}
out:
}
static bool_t
{
char *cacheid;
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_umount_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_getpage_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_readdir_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_readlink_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_remove_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_rmdir_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_truncate_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_putpage_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_create_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_mkdir_record *record;
int size;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_rename_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_symlink_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_populate_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_csymlink_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_filldir_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_mdcreate_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_gpfront_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_rfdir_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_ualloc_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_calloc_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}
void
{
struct cachefs_log_nocache_record *record;
/* In Solaris 64 - if can't represent time don't bother */
return;
}
}
}
static bool_t
{
return (FALSE);
return (TRUE);
}