cfsd_fscache.c 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
*/
/*
* Copyright 1994-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Methods of the cfsd_fscache class.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.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 <locale.h>
#include "cfsd.h"
#include "cfsd_kmod.h"
#include "cfsd_maptbl.h"
#include "cfsd_logfile.h"
#include "cfsd_logelem.h"
#include "cfsd_fscache.h"
/*
* -----------------------------------------------------------------
* cfsd_fscache_create
*
* Description:
* Arguments:
* name
* cachepath
* Returns:
* Preconditions:
* precond(name)
* precond(cachepath)
*/
int fscacheid)
{
int xx;
dbug_enter("cfsd_fscache_create");
sizeof (fscache_object_p->i_name));
sizeof (fscache_object_p->i_cachepath));
fscache_object_p->i_refcnt = 0;
fscache_object_p->i_mounted = 0;
fscache_object_p->i_threaded = 0;
fscache_object_p->i_connected = 0;
fscache_object_p->i_reconcile = 0;
fscache_object_p->i_changes = 0;
fscache_object_p->i_simdis = 0;
fscache_object_p->i_tryunmount = 0;
fscache_object_p->i_time_state = 0;
fscache_object_p->i_time_mnt = 0;
fscache_object_p->i_threadid = 0;
/* initialize the locking mutex */
dbug_assert(xx == 0);
dbug_assert(xx == 0);
dbug_leave("cfsd_fscache_create");
return (fscache_object_p);
}
/*
* -----------------------------------------------------------------
* cfsd_fscache_destroy
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
int xx;
dbug_enter("cfsd_fscache_destroy");
/* dbug_assert(fscache_object_p->i_refcnt == 0); */
/* close down the message file descriptor */
if (fscache_object_p->i_ofd >= 0) {
errno));
}
/* destroy the locking mutex */
dbug_assert(xx == 0);
/* destroy the conditional variable */
dbug_assert(xx == 0);
dbug_leave("cfsd_fscache_destroy");
}
/*
* -----------------------------------------------------------------
* fscache_lock
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
dbug_enter("fscache_lock");
dbug_leave("fscache_lock");
}
/*
* -----------------------------------------------------------------
* fscache_unlock
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
dbug_enter("fscache_unlock");
dbug_leave("fscache_unlock");
}
/*
* -----------------------------------------------------------------
* fscache_setup
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
char *tmp;
char cfs_mnt_filename[MAXPATHLEN];
/*
* Line input buffer allows for type field (magic number size
* of 50 is historic), the field separator ": ", a large value
* (again historic) and a '\n' character.
*/
char type[50];
int err = 0;
int xx;
char *dummy;
dbug_enter("fscache_setup");
fscache_object_p->i_connected = 0;
fscache_object_p->i_reconcile = 0;
fscache_object_p->i_changes = 0;
fscache_object_p->i_time_state = 0;
fscache_object_p->i_time_mnt = 0;
/* open for reading the file with the mount information */
errno));
dbug_leave("fscache_setup");
return;
}
/* get the modify time of the mount file */
errno));
dbug_leave("fscache_setup");
return;
}
/* read the mount information from the file */
/* Buffer Overflow */
" of file %s", cfs_mnt_filename));
dbug_leave("fscache_setup");
return;
}
/*
* There is a valid value string so skip
* the space after the ":".
*/
tmp++;
>= sizeof (value)) {
/* Buffer Overflow */
dbug_print(("err",
"overflow in value field"
" of file %s", cfs_mnt_filename));
dbug_print(("err",
"cannot close %s, %d",
dbug_leave("fscache_setup");
return;
}
} else {
value[0] = '\0';
}
err = 1;
}
sizeof (fscache_object_p->i_mntpt));
sizeof (fscache_object_p->i_backfs));
sizeof (fscache_object_p->i_backpath));
sizeof (fscache_object_p->i_backfstype));
err = 1;
}
sizeof (fscache_object_p->i_cfsopt));
sizeof (fscache_object_p->i_bfsopt));
continue;
} else {
err = 1;
}
}
/* see if this is a file system that is disconnectable */
if ((err == 0) &&
(fscache_object_p->i_backfs[0] &&
fscache_object_p->i_cfsopt[0])) {
while (*strp != '\0') {
if (xx != -1) {
break;
}
}
}
/*
* open up a fd on the sysmsg so we have a place to write
* log rolling errors
*/
if (fscache_object_p->i_disconnectable) {
if (fscache_object_p->i_ofd < 0)
O_WRONLY);
if (fscache_object_p->i_ofd < 0) {
gettext("cachefsd: File system %s cannot be"
" disconnected.\n"),
}
}
/* see if the file system is mounted */
fscache_object_p->i_mounted = 0;
} else
/* save the time of the last mount or unmount */
dbug_leave("fscache_setup");
}
/*
* -----------------------------------------------------------------
* fscache_process
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
int xx;
int changes;
int setup = 1;
int state;
dbug_enter("fscache_process");
for (;;) {
/* if we should try to unmount the file system */
if (fscache_object_p->i_tryunmount) {
/* shut down the interface to the kmod */
if (setup == 0) {
setup = 1;
}
/* try to unmount the file system */
} else {
fscache_object_p->i_mounted = 0;
}
/* wake up thread blocked in fscache_unmount */
fscache_object_p->i_tryunmount = 0;
dbug_assert(xx == 0);
/* all done if unmount succeeded */
if (fscache_object_p->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));
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_object_p->i_reconcile = 0;
/* wait for fs to switch to disconnecting */
continue;
}
dbug_assert(xx == 0);
break;
case CFS_FS_DISCONNECTED:
fscache_object_p->i_connected = 0;
fscache_object_p->i_reconcile = 0;
/* wait until we are reconnected */
if (fscache_object_p->i_tryunmount)
continue;
/* switch to reconnecting mode */
dbug_assert(xx == 0);
break;
case CFS_FS_RECONNECTING:
/* roll the log */
if (xx) {
/* switch to disconnected */
dbug_assert(xx == 0);
} else {
/* switch to connected */
dbug_assert(xx == 0);
changes = 0;
}
fscache_object_p->i_reconcile = 0;
break;
default:
dbug_assert(0);
break;
}
}
dbug_leave("fscache_process");
}
/*
* 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
{
int xx;
int ret = 0;
char *strp;
int tcon;
int trec;
dbug_enter("fscache_simdisconnect");
if (disconnect) {
/* if file system cannot be disconnected */
if (fscache_object_p->i_disconnectable == 0) {
ret = 1;
goto out;
}
/* if file system is already disconnected */
if (fscache_object_p->i_connected == 0) {
ret = 2;
goto out;
}
} else {
/* if file system is already connected */
if (fscache_object_p->i_connected) {
ret = 1;
goto out;
}
/* if file system is not "simulated" disconnected */
if (fscache_object_p->i_simdis == 0) {
ret = 2;
goto out;
}
fscache_object_p->i_simdis = 0;
}
/* if fs thread not running */
if (fscache_object_p->i_threaded == 0) {
if (fscache_object_p->i_mounted) {
ret = -1;
} else {
if (fscache_object_p->i_simdis)
fscache_object_p->i_connected = 0;
else
}
goto out;
}
/* get the attention of the thread */
if (xx) {
ret = -1;
}
out:
if (ret == 0) {
for (;;) {
strp));
if (disconnect) {
if (tcon == 0)
break;
} else {
break;
}
cfsd_sleep(1);
}
} else {
}
dbug_leave("fscache_simdisconnect");
return (ret);
}
/*
* 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
* ENOTSUP - forced unmount is not supported by cachefs
* Preconditions:
*/
int
{
int xx;
int ret = 0;
dbug_enter("fscache_unmount");
/* if there is a thread running */
if (fscache_object_p->i_threaded) {
/* do not bother unmounting if rolling the log */
if (fscache_object_p->i_reconcile) {
goto out;
}
/* inform the thread to try the unmount */
/* get the attention of the thread */
if (xx) {
goto out;
}
/* wait for the thread to wake us up */
while (fscache_object_p->i_tryunmount) {
}
/* if the file system is still mounted */
if (fscache_object_p->i_mounted)
}
/* else if there is no thread running */
else {
/* try to unmount the file system */
else
} else {
fscache_object_p->i_mounted = 0;
}
}
out:
dbug_leave("fscache_unmount");
return (ret);
}
/*
* -----------------------------------------------------------------
* fscache_server_alive
*
* Description:
* Arguments:
* Returns:
* Preconditions:
*/
void
{
int xx;
char cfsopt[CFS_MAXMNTOPTLEN];
int child_pid;
int stat_loc;
dbug_enter("fscache_server_alive");
for (;;) {
/* wait for a little while */
if (fscache_object_p->i_simdis == 0)
cfsd_sleep(30);
/* if simulating disconnect */
while (fscache_object_p->i_simdis &&
}
if (fscache_object_p->i_tryunmount)
break;
/* see if the server is alive */
/* dead server */
continue;
}
/* try to mount the back file system if needed */
/*
* Mounting of a cachefs file system is done by calling
* done by the user, autofs and by us here in cachefsd
* are consistent.
*/
case -1:
/*
* The original code used system()
* but never checked for an error
* occurring. The rest of the code
* would suggest that "continue" is
* the correct thing to do.
*/
"process for back fs %s %d",
continue;
case 0:
(void) setsid();
break;
default:
}
}
/* get the root fid of the file system */
if (xx) {
continue;
}
/* dummy up a fake kcred */
/* try to get attrs on the root */
continue;
}
break;
}
dbug_leave("fscache_server_alive");
}
/*
* fscache_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
{
int ret = 0;
char *cptr;
dbug_enter("fscache_pingserver");
*cptr = '\0';
/* XXX this takes 75 seconds to time out */
/* XXX should use lower level routines to reduce overhead */
/* XXX what if this fails other than TIMEDOUT */
/* clnt_pcreateerror(hostname); */
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;
}
}
dbug_leave("fscache_pingserver");
return (ret);
}
/*
* fscache_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;
char namebuf[MAXPATHLEN];
char backupfile[MAXPATHLEN];
int xx;
int eof = 0;
char *xp;
dbug_enter("fscache_roll");
/* map in the log file */
if (xx) {
dbug_leave("fscache_roll");
return (0);
}
dbug_leave("fscache_roll");
return (0);
}
/* create a hashed mapping table for changes to cids */
if (xx) {
dbug_leave("fscache_roll");
return (0);
}
/*
* lock is not needed because they are only used when
* rolling the log by fscache_roll and fscache_addagain
*/
fscache_object_p->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) {
dbug_leave("fscache_roll");
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 */
if (logelem_object_p == NULL)
continue;
/* debuggging */
/* roll the entry */
if (xx) {
dbug_leave("fscache_roll");
return (0);
}
/* mark record as completed */
if (xx) {
dbug_leave("fscache_roll");
return (0);
}
/* destroy the object */
}
/* Pass 2: modify the back file system */
for (;;) {
/* if we need the seq number of a deferred modify */
if (fscache_object_p->i_again_offset &&
(fscache_object_p->i_again_seq == 0)) {
/* get a pointer to the next record */
if (xx == 1)
break;
if (xx == -1) {
dbug_leave("fscache_roll");
return (0);
}
}
/* get a pointer to the next record to process */
if (!eof) {
&entp);
if (xx == 1) {
eof = 1;
} else if (xx) {
break;
} else {
}
}
/* if its time to process a deferred modify entry */
if (fscache_object_p->i_again_seq &&
if (xx)
break;
fscache_object_p->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 */
dbug_leave("fscache_roll");
return (xx);
break;
continue;
} 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 */
/* debugging hack, rename the log files */
"for %s, path name is too long", namebuf));
} else {
/*
* No need to check return value from snprintf() as
* the previous check should suffice.
*/
dbug_print(("error",
"unable to create backup dlog_file"));
}
}
"for %s, path name is too long", namebuf));
} else {
/*
* No need to check return value from snprintf() as
* the previous check should suffice.
*/
dbug_print(("error",
"unable to create backup dmap_file"));
}
}
/* delete the log file */
/* XXX */
dbug_leave("fscache_roll");
return (error);
}
/*
* fscache_rollone
*
* Description:
* Arguments:
* kmodp
* tblp
* lfp
* Returns:
* Returns ...
* Preconditions:
* precond(kmodp)
* precond(tblp)
* precond(lfp)
*/
int
{
int xx;
char *strp;
dbug_enter("fscache_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);
dbug_leave("fscache_rollone");
return (EIO);
}
/* do not bother if ignoring the record */
if (logelem_object_p == NULL) {
dbug_leave("fscache_rollone");
return (0);
}
/* XXX debugging */
/* roll the entry */
if (strp) {
}
if (xx == 0)
}
/* destroy the object */
dbug_leave("fscache_rollone");
return (xx);
}
/*
* fscache_addagain
*
* Description:
* Arguments:
* lfp
* Returns:
* Returns ...
* Preconditions:
* precond(lfp)
*/
int
{
int xx;
dbug_enter("fscache_addagain");
/* both set or both zero */
!fscache_object_p->i_again_offset) == 0);
/* simple case, first one on list */
if ((fscache_object_p->i_again_seq == 0) ||
dbug_leave("fscache_addagain");
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) {
dbug_leave("fscache_addagain");
return (xx);
}
/* done if we found the element after the insertion point */
break;
}
/* get pointer to element prior to the insertion point */
if (xx) {
dbug_leave("fscache_addagain");
return (xx);
}
/* set element to point to our new element */
/* get pointer to our new element */
if (xx) {
dbug_leave("fscache_addagain");
return (xx);
}
/* set it to point to next link or end of list */
/* return success */
dbug_leave("fscache_addagain");
return (0);
}
/*
* fscache_fsproblem
*
* Description:
* Arguments:
* kmodp
* Returns:
* Preconditions:
* precond(kmodp)
*/
void
{
#if 0
int xx;
#endif
dbug_enter("fscache_fsproblem");
#if 0
/* first try to put all modified files in lost+found */
if (xx) {
/* if that failed, put file system in read-only mode */
#endif
#if 0
}
#endif
dbug_leave("fscache_fsproblem");
}
/*
* fscache_changes
*
* Description:
* Used to specify whether or not there are changes to roll to the
* server.
* Arguments:
* tt
* Returns:
* Preconditions:
*/
void
{
dbug_enter("fscache_changes");
dbug_leave("fscache_changes");
}