cfsd_fscache.cc revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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
*/
// -----------------------------------------------------------------
//
// fscache.cc
//
// Methods of the cfsd_fscache class.
#pragma ident "%Z%%M% %I% %E% SMI"
// Copyright (c) 1994-2001 by Sun Microsystems, Inc.
// All rights reserved.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <thread.h>
#include <synch.h>
#include <errno.h>
#include <unistd.h>
#include <stdarg.h>
#include <limits.h>
#include <fcntl.h>
#include "cfsd_kmod.h"
#include "cfsd_maptbl.h"
#include "cfsd_logfile.h"
#include "cfsd_logelem.h"
#include "cfsd_fscache.h"
// forward reference
// -----------------------------------------------------------------
//
// cfsd_fscache::cfsd_fscache
//
// Description:
// Arguments:
// name
// cachepath
// Returns:
// Preconditions:
// precond(name)
// precond(cachepath)
int fscacheid)
{
dbug_enter("cfsd_fscache::cfsd_fscache");
i_refcnt = 0;
i_disconnectable = 0;
i_mounted = 0;
i_threaded = 0;
i_connected = 0;
i_reconcile = 0;
i_changes = 0;
i_simdis = 0;
i_tryunmount = 0;
i_backunmount = 0;
i_time_state = 0;
i_time_mnt = 0;
i_modify = 1;
i_threadid = 0;
i_ofd = -1;
// initialize the locking mutex
dbug_assert(xx == 0);
dbug_assert(xx == 0);
}
// -----------------------------------------------------------------
//
// cfsd_fscache::~cfsd_fscache
//
// Description:
// Arguments:
// Returns:
// Preconditions:
{
dbug_enter("cfsd_fscache::~cfsd_fscache");
// close down the message file descriptor
if (i_ofd >= 0) {
i_ofd = -1;
}
// destroy the locking mutex
dbug_assert(xx == 0);
}
// -----------------------------------------------------------------
//
// cfsd_fscache::fscache_lock
//
// Description:
// Arguments:
// Returns:
// Preconditions:
void
{
dbug_enter("cfsd_fscache::fscache_lock");
mutex_lock(&i_lock);
}
// -----------------------------------------------------------------
//
// cfsd_fscache::fscache_unlock
//
// Description:
// Arguments:
// Returns:
// Preconditions:
void
{
dbug_enter("cfsd_fscache::fscache_unlock");
}
// -----------------------------------------------------------------
//
// cfsd_fscache::fscache_setup
//
// Description:
// Arguments:
// Returns:
// Preconditions:
void
{
dbug_enter("cfsd_fscache::fscache_setup");
i_modify++;
i_disconnectable = 0;
i_connected = 0;
i_reconcile = 0;
i_changes = 0;
i_time_state = 0;
i_time_mnt = 0;
i_backpath.resize(0);
i_backfstype.resize(0);
// get the modify time of the mount file
return;
}
// open for reading the file with the mount information
return;
}
// read the mount information from the file
char type[50];
int err = 0;
int xx;
err = 1;
}
i_backpath = buf;
i_backfstype = buf;
err = 1;
}
} else {
err = 1;
}
}
// see if this is a file system that is disconnectable
if ((err == 0) &&
char *dummy;
while (*strp != '\0') {
if (xx != -1) {
i_disconnectable = 1;
break;
}
}
}
// open up a fd on the console so we have a place to write
// log rolling errors
if (i_disconnectable) {
if (i_ofd < 0)
if (i_ofd < 0) {
"cachefsd: File system %s cannot"
i_disconnectable = 0;
}
}
// see if the file system is mounted
i_mounted = 0;
} else
i_mounted = 1;
// save the time of the last mount or unmount
i_time_mnt = mtime;
}
// -----------------------------------------------------------------
//
// cfsd_fscache::fscache_process
//
// Description:
// Arguments:
// Returns:
// Preconditions:
void
{
dbug_enter("cfsd_fscache::fscache_process");
int xx;
int changes;
int setup = 1;
int state;
for (;;) {
fscache_lock();
i_modify++;
// if we should try to unmount the file system
if (i_tryunmount) {
// shut down the interface to the kmod
if (setup == 0) {
setup = 1;
}
// try to unmount the file system
} else {
i_mounted = 0;
}
// wake up thread blocked in fscache_unmount
i_tryunmount = 0;
dbug_assert(xx == 0);
// all done if unmount succeeded
if (i_mounted == 0) {
break;
}
}
if (setup) {
setup = 0;
// make an interface into the cachefs kmod for this fs
if (xx != 0) {
dbug_print("err",
("setup of kmod interface failed %d", xx));
i_modify++;
break;
}
// verify that we got the file system we expected
// XXX
}
// get the current state of the file system
dbug_assert(xx == 0);
}
switch (state) {
case CFS_FS_CONNECTED:
fscache_lock();
i_connected = 1;
i_reconcile = 0;
i_modify++;
// wait for fs to switch to disconnecting
continue;
}
dbug_assert(xx == 0);
break;
case CFS_FS_DISCONNECTED:
fscache_lock();
i_connected = 0;
i_reconcile = 0;
i_modify++;
// wait until we are reconnected
if (i_tryunmount)
continue;
// switch to reconnecting mode
dbug_assert(xx == 0);
break;
case CFS_FS_RECONNECTING:
fscache_lock();
i_connected = 1;
i_reconcile = 1;
i_modify++;
changes = fscache_changes();
// roll the log
if (xx) {
// switch to disconnected
dbug_assert(xx == 0);
} else {
// switch to connected
dbug_assert(xx == 0);
changes = 0;
}
fscache_lock();
i_reconcile = 0;
i_modify++;
break;
default:
dbug_assert(0);
break;
}
}
}
//
// cfsd_fscache::fscache_simdisconnect
//
// Description:
// Simulates disconnection or reconnects from a simulated disconnection.
// Arguments:
// disconnect 1 means disconnect, !1 means connect
// Returns:
// Returns 0 for success, !0 on an error
// Preconditions:
int
{
dbug_enter("cfsd_fscache::fscache_simdisconnect");
int xx;
int ret = 0;
char *strp;
fscache_lock();
if (disconnect) {
// if file system cannot be disconnected
if (fscache_disconnectable() == 0) {
ret = 1;
goto out;
}
// if file system is already disconnected
if (i_connected == 0) {
ret = 2;
goto out;
}
i_simdis = 1;
} else {
// if file system is already connected
if (i_connected) {
ret = 1;
goto out;
}
// if file system is not "simulated" disconnected
if (i_simdis == 0) {
ret = 2;
goto out;
}
i_simdis = 0;
}
// if fs thread not running
if (i_threaded == 0) {
if (i_mounted) {
ret = -1;
} else {
if (i_simdis)
i_connected = 0;
else
i_connected = 1;
}
goto out;
}
// get the attention of the thread
if (xx) {
xx, i_threadid));
ret = -1;
}
out:
if (ret == 0) {
for (;;) {
strp));
fscache_lock();
int tcon = i_connected;
int trec = i_reconcile;
if (disconnect) {
if (tcon == 0)
break;
} else {
break;
}
mysleep(1);
}
} else {
}
return (ret);
}
//
// cfsd_fscache::fscache_unmount
//
// Description:
// Called to unmount the file system.
// Arguments:
// Returns:
// Returns 0 if the unmount is successful
// EIO if an error
// EBUSY if did not unmount because busy
// EAGAIN if umounted but should not unmount nfs mount
// Preconditions:
int
{
dbug_enter("cfsd_fscache::fscache_unmount");
int xx;
int ret = 0;
fscache_lock();
// if there is a thread running
if (i_threaded) {
// do not bother unmounting if rolling the log
if (i_reconcile) {
goto out;
}
// inform the thread to try the unmount
i_tryunmount = 1;
// get the attention of the thread
if (xx) {
xx, i_threadid));
}
// wait for the thread to wake us up
while (i_tryunmount) {
xx, i_tryunmount));
}
// if the file system is still mounted mounted
if (fscache_mounted())
}
// else if there is no thread running
else {
// try to unmount the file system
else
} else {
i_mounted = 0;
}
}
out:
return (ret);
}
// -----------------------------------------------------------------
//
// cfsd_fscache::operator==
//
// Description:
// Arguments:
// fscachep
// Returns:
// Returns ...
// Preconditions:
int
{
dbug_enter("cfsd_fscache::operator==");
int xx;
return (xx);
}
// -----------------------------------------------------------------
//
// cfsd_fscache::i_server_alive
//
// Description:
// Arguments:
// Returns:
// Preconditions:
void
{
dbug_enter("cfsd_fscache::i_server_alive");
int ret;
int xx;
int result;
for (;;) {
// wait for a little while
if (!i_simdis)
mysleep(30);
// if simulating disconnect
fscache_lock();
while (i_simdis && !i_tryunmount) {
}
if (i_tryunmount)
break;
// see if the server is alive
if (i_pingserver() == -1) {
// dead server
continue;
}
// try to mount the back file system if needed
if (i_backpath.isNull()) {
tcmd += ",slide,remount ";
tcmd += " ";
dbug_print("info",
}
// get the root fid of the file system
if (xx) {
mysleep(5);
continue;
}
// dummy up a fake kcred
// try to get attrs on the root
mysleep(5);
continue;
}
break;
}
}
//
// cfsd_fscache::i_pingserver
//
// Description:
// Trys to ping the nfs server to see if it is alive.
// Arguments:
// Returns:
// Returns 0 if it is alive, -1 if no answer.
// Preconditions:
int
{
dbug_enter("cfsd_fscache::i_pingserver");
int ret = 0;
// XXX this takes 75 seconds to time out
// XXX what if this fails other than TIMEDOUT
ret = -1;
} else {
// XXX this takes 45 seconds to time out
TIMEOUT);
if (retval != RPC_SUCCESS) {
// clnt_perror(clnt, "null rpc call failed");
ret = -1;
}
}
return (ret);
}
//
// cfsd_fscache::i_roll
//
// Description:
// Rolls the contents of the log to the server.
// Arguments:
// kmodp interface to kernel functions
// Returns:
// Returns 0 for success or ETIMEDOUT if a timeout error occurred.
// Preconditions:
// precond(kmodp)
int
{
int error = 0;
dbug_enter("cfsd_fscache::i_roll");
int xx;
// map in the log file
if (xx) {
return (0);
return (0);
}
fscache_lock();
fscache_changes(1);
// create a hashed mapping table for changes to cids
if (xx) {
return (0);
}
i_again_offset = 0;
i_again_seq = 0;
// Pass 1: collect all cid to fid mappings
for (;;) {
// get a pointer to the next record
if (xx == 1)
break;
if (xx == -1) {
return (0);
}
// skip record if not valid
continue;
// create an object for the appropriate log type
case CFS_DLOG_CREATE:
case CFS_DLOG_REMOVE:
case CFS_DLOG_LINK:
case CFS_DLOG_RENAME:
case CFS_DLOG_MKDIR:
case CFS_DLOG_RMDIR:
case CFS_DLOG_SYMLINK:
case CFS_DLOG_SETATTR:
case CFS_DLOG_SETSECATTR:
case CFS_DLOG_MODIFIED:
case CFS_DLOG_TRAILER:
break;
case CFS_DLOG_MAPFID:
break;
default:
dbug_assert(0);
break;
}
// do not bother if ignoring the record
continue;
// debuggging
logp->logelem_dump();
// roll the entry
if (xx) {
return (0);
}
// mark record as completed
if (xx) {
return (0);
}
// destroy the object
delete logp;
}
// Pass 2: modify the back file system
int eof = 0;
for (;;) {
// if we need the seq number of a deferred modify
if (i_again_offset && (i_again_seq == 0)) {
if (xx)
break;
dbug_assert(i_again_seq != 0);
}
// get a pointer to the next record to process
if (!eof) {
if (xx == 1) {
eof = 1;
} else if (xx)
break;
else
}
// if its time to process a deferred modify entry
if (xx)
break;
i_again_seq = 0;
} else if (eof) {
xx = 0;
break;
}
// else move the offset to the next record
else {
}
// skip record if not valid
continue;
// process the record
// timeout error, back to disconnected
return (xx);
break;
} else if (xx) {
// should never happen
dbug_assert(0);
break;
} else {
// mark record as completed
if (xx)
break;
}
}
// if an unrecoverable error occurred
if (xx) {
}
// dump stats about the hash table
// dump stats about the log file
// XXX debugging hack, rename the log files
char *xp;
// delete the log file
// XXX
return (error);
}
//
// cfsd_fscache::i_rollone
//
// Description:
// Arguments:
// kmodp
// tblp
// lfp
// Returns:
// Returns ...
// Preconditions:
// precond(kmodp)
// precond(tblp)
// precond(lfp)
int
{
dbug_enter("cfsd_fscache::i_rollone");
// create an object for the appropriate log type
case CFS_DLOG_CREATE:
break;
case CFS_DLOG_REMOVE:
break;
case CFS_DLOG_LINK:
break;
case CFS_DLOG_RENAME:
break;
case CFS_DLOG_MKDIR:
break;
case CFS_DLOG_RMDIR:
break;
case CFS_DLOG_SYMLINK:
break;
case CFS_DLOG_SETATTR:
break;
case CFS_DLOG_SETSECATTR:
break;
case CFS_DLOG_MODIFIED:
break;
case CFS_DLOG_MAPFID:
break;
case CFS_DLOG_TRAILER:
break;
default:
dbug_assert(0);
return (EIO);
}
// do not bother if ignoring the record
return (0);
}
// XXX debugging
logp->logelem_dump();
// roll the entry
if (strp) {
}
if (xx == 0)
}
// destroy the object
delete logp;
return (xx);
}
//
// cfsd_fscache::i_addagain
//
// Description:
// Arguments:
// kmodp
// lfp
// Returns:
// Returns ...
// Preconditions:
// precond(kmodp)
// precond(lfp)
int
{
dbug_enter("cfsd_fscache::i_addagain");
int xx;
// both set or both zero
// simple case, first one on list
i_again_seq = nseq;
return (0);
}
// Search until we find the element on the list prior to the
// insertion point.
// get pointer to next element on the list
if (xx) {
return (xx);
}
// done if we found the element after the insertion point
break;
}
// get pointer to element prior to the insertion point
if (xx) {
return (xx);
}
// set element to point to our new element
// get pointer to our new element
if (xx) {
return (xx);
}
// set it to point to next link or end of list
// return success
return (0);
}
//
// cfsd_fscache::i_fsproblem
//
// Description:
// Arguments:
// kmodp
// Returns:
// Preconditions:
// precond(kmodp)
void
{
dbug_enter("cfsd_fscache::i_fsproblem");
int xx;
// first try to put all modified files in lost+found
if (xx) {
// if that failed, put file system in read-only mode
fscache_lock();
i_modify++;
}
}
//
// cfsd_fscache::fscache_changes
//
// Description:
// Used to specify whether or not there are changes to roll to the
// server.
// Arguments:
// tt
// Returns:
// Preconditions:
void
{
i_modify++;
}
//
// mysleep
//
// Description:
// A reimplemenation of the sleep(3c) function call using
// cond_reltimedwait.
// Problem withe sleep(3c) hanging.
// May return early.
// Arguments:
// sec number of seconds to sleep for
// Returns:
// Preconditions:
void
{
#if 0
#else
cond_destroy(&cv);
mutex_destroy(&mt);
#endif
}