---------------------
PatchSet 950 
Date: 2000/12/17 14:36:23
Author: hno
Branch: raid
Tag: (none) 
Log:
Imported raid from squidng

Members: 
	acconfig.h:1.4.6.1.2.1->1.4.6.1.2.1.2.1 
	configure.in:1.7.6.1.2.1->1.7.6.1.2.1.2.1 
	doc/debug-sections.txt:1.2.22.1.2.1->1.2.22.1.2.1.2.1 
	src/Makefile.in:1.3.22.1->1.3.22.1.2.1 
	src/cache_cf.c:1.6.4.1->1.6.4.1.6.1 
	src/cf.data.pre:1.5->1.5.12.1 
	src/client_side.c:1.10.2.1.4.1->1.10.2.1.4.1.2.1 
	src/comm.c:1.4.14.1.4.1->1.4.14.1.4.1.2.1 
	src/comm_cio.c:1.1.2.1->1.1.2.1.2.1 
	src/defines.h:1.3.16.1.2.1->1.3.16.1.2.1.4.1 
	src/disk.c:1.4.20.1->1.4.20.1.2.1 
	src/enums.h:1.6.4.1.2.1->1.6.4.1.2.1.4.1 
	src/fd.c:1.4.10.1->1.4.10.1.2.1 
	src/ftp.c:1.5.10.1.4.1->1.5.10.1.4.1.2.1 
	src/gopher.c:1.5.4.1.4.1->1.5.4.1.4.1.2.1 
	src/http.c:1.5.10.1.4.1->1.5.10.1.4.1.2.1 
	src/main.c:1.6.4.1.4.1->1.6.4.1.4.1.2.1 
	src/protos.h:1.6.4.1.2.1.2.1->1.6.4.1.2.1.2.1.2.1 
	src/pump.c:1.4.14.1.4.1->1.4.14.1.4.1.2.1 
	src/raid.c:1.1->1.1.2.1 
	src/squid.h:1.3.16.1.2.1.2.1->1.3.16.1.2.1.2.1.2.1 
	src/ssl.c:1.3.16.1.4.1->1.3.16.1.4.1.2.1 
	src/store.c:1.6.4.1.2.1->1.6.4.1.2.1.4.1 
	src/store_dir.c:1.4.18.1->1.4.18.1.4.1 
	src/store_io.c:1.2->1.2.26.1 
	src/store_swapout.c:1.4.14.1.2.1->1.4.14.1.2.1.4.1 
	src/structs.h:1.8.8.1.2.1->1.8.8.1.2.1.2.1 
	src/typedefs.h:1.4.10.1.2.1.2.1->1.4.10.1.2.1.2.1.2.1 
	src/wais.c:1.3.16.1.4.1->1.3.16.1.4.1.2.1 
	src/whois.c:1.3.16.1.4.1->1.3.16.1.4.1.2.1 
	src/fs/butterfly/store_dir_bf.c:1.1.2.1.2.1->1.1.2.1.2.1.2.1 
	src/fs/butterfly/store_io_bf.c:1.1.2.1->1.1.2.1.4.1 
	src/fs/ufs/store_dir_ufs.c:1.5.4.1->1.5.4.1.6.1 

Index: squid/acconfig.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/Attic/acconfig.h,v
retrieving revision 1.4.6.1.2.1
retrieving revision 1.4.6.1.2.1.2.1
diff -u -r1.4.6.1.2.1 -r1.4.6.1.2.1.2.1
--- squid/acconfig.h	17 Dec 2000 14:09:08 -0000	1.4.6.1.2.1
+++ squid/acconfig.h	17 Dec 2000 14:36:23 -0000	1.4.6.1.2.1.2.1
@@ -20,7 +20,7 @@
  *
  */
 @ TOP @
-/* $Id: acconfig.h,v 1.4.6.1.2.1 2000/12/17 14:09:08 hno Exp $ */
+/* $Id: acconfig.h,v 1.4.6.1.2.1.2.1 2000/12/17 14:36:23 hno Exp $ */
 
 /*********************************
  * START OF CONFIGURABLE OPTIONS *
@@ -286,10 +286,16 @@
 /* Signal driven async network IO */
 #undef TCP_ASYNC
 
+/* Signal handling from signal handlers */
+#undef CIOCIOSAN_USE_SIGHANDLER
+
 /* Periodically dump profile snapshots from running squid */
 #undef PROFILE_SQUID
 #undef PROFIL_DELAY
 
+/* Enable on-fly drive replacement */
+#undef DISK_REPL
+
 /*
  * Define this if unlinkd is required
  * (strongly recommended for ufs storage type)
Index: squid/configure.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/configure.in,v
retrieving revision 1.7.6.1.2.1
retrieving revision 1.7.6.1.2.1.2.1
diff -u -r1.7.6.1.2.1 -r1.7.6.1.2.1.2.1
--- squid/configure.in	17 Dec 2000 14:09:08 -0000	1.7.6.1.2.1
+++ squid/configure.in	17 Dec 2000 14:36:23 -0000	1.7.6.1.2.1.2.1
@@ -3,13 +3,13 @@
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.7.6.1.2.1 2000/12/17 14:09:08 hno Exp $
+dnl  $Id: configure.in,v 1.7.6.1.2.1.2.1 2000/12/17 14:36:23 hno Exp $
 dnl
 dnl
 dnl
 AC_INIT(src/main.c)
 AC_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.7.6.1.2.1 $)dnl
+AC_REVISION($Revision: 1.7.6.1.2.1.2.1 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AC_CONFIG_AUX_DIR(cfgaux)
 
@@ -754,6 +754,15 @@
   fi
 ])
 
+dnl Enable signal handling from signal handlers
+AC_ARG_ENABLE(ciociosan-handlers,
+[  --enable-ciociosan-handlers      Enable signal handling from signal handlers (requires ciociosan)],
+[ if test "$enableval" = "yes" ; then
+    echo "Enabling signal handling from signal handlers"
+    AC_DEFINE(CIOCIOSAN_USE_SIGHANDLER)
+  fi
+])
+
 dnl Enable gmon-based profiling
 AC_ARG_ENABLE(profiling,
 [  --enable-profiling      Enable gmon-based profiling],
@@ -784,6 +793,15 @@
 echo "Profiling snapshot dumping interval is set to " $PROFILE_DELAY
 AC_DEFINE_UNQUOTED(PROFIL_DELAY,$PROFILE_DELAY)
 
+dnl Enable on-fly drive replacement
+AC_ARG_ENABLE(disk-repl,
+[  --enable-disk-repl      Enable on-fly drive replacement],
+[ if test "$enableval" = "yes" ; then
+    echo "Enable on-fly drive replacement"
+    AC_DEFINE(DISK_REPL)
+  fi
+])
+
 # Force some compilers to use ANSI features
 #
 case "$host" in
Index: squid/doc/debug-sections.txt
===================================================================
RCS file: /cvsroot/squid-sf//squid/doc/debug-sections.txt,v
retrieving revision 1.2.22.1.2.1
retrieving revision 1.2.22.1.2.1.2.1
diff -u -r1.2.22.1.2.1 -r1.2.22.1.2.1.2.1
--- squid/doc/debug-sections.txt	17 Dec 2000 14:09:08 -0000	1.2.22.1.2.1
+++ squid/doc/debug-sections.txt	17 Dec 2000 14:36:23 -0000	1.2.22.1.2.1.2.1
@@ -90,3 +90,4 @@
 section 88    Storage Manager TREE Interface I/O Routines, async
 section 89    Storage Manager TREE Interface I/O Routines
 section 90    Signal-driven netword IO
+section 91    RAID support
Index: squid/src/Makefile.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/Makefile.in,v
retrieving revision 1.3.22.1
retrieving revision 1.3.22.1.2.1
diff -u -r1.3.22.1 -r1.3.22.1.2.1
--- squid/src/Makefile.in	17 Dec 2000 14:09:08 -0000	1.3.22.1
+++ squid/src/Makefile.in	17 Dec 2000 14:36:23 -0000	1.3.22.1.2.1
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.3.22.1 2000/12/17 14:09:08 hno Exp $
+#  $Id: Makefile.in,v 1.3.22.1.2.1 2000/12/17 14:36:23 hno Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -74,7 +74,7 @@
 SHELL		= /bin/sh
 
 INCLUDE		= -I. -I../include -I$(top_srcdir)/include
-CFLAGS 		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+CFLAGS 		= -O3 $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
 SQUID_LIBS	= -L../lib $(CRYPTLIB) $(REGEXLIB) @SQUID_PTHREAD_LIB@ \
 		  $(SNMPLIB) $(MALLOCLIB) -lmiscutil $(XTRA_LIBS)
 CLIENT_LIBS	= -L../lib -lmiscutil $(XTRA_LIBS)
@@ -101,6 +101,7 @@
 		comm.o \
 		comm_cio.o \
 		comm_select.o \
+		raid.o \
 		debug.o \
 		@DELAY_OBJS@ \
 		disk.o \
Index: squid/src/cache_cf.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v
retrieving revision 1.6.4.1
retrieving revision 1.6.4.1.6.1
diff -u -r1.6.4.1 -r1.6.4.1.6.1
--- squid/src/cache_cf.c	17 Dec 2000 08:20:04 -0000	1.6.4.1
+++ squid/src/cache_cf.c	17 Dec 2000 14:36:23 -0000	1.6.4.1.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.c,v 1.6.4.1 2000/12/17 08:20:04 hno Exp $
+ * $Id: cache_cf.c,v 1.6.4.1.6.1 2000/12/17 14:36:23 hno Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -199,7 +199,7 @@
     int i;
     ssize_t ms = -1;
 
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    FOREACHSDINDEX(i) {
 	if (Config.cacheSwap.swapDirs[i].max_objsize > ms)
 	    ms = Config.cacheSwap.swapDirs[i].max_objsize;
     }
@@ -968,6 +968,7 @@
     swap->swapDirs = NULL;
     swap->n_allocated = 0;
     swap->n_configured = 0;
+    swap->n_offline = 0;
 }
 
 const char *
Index: squid/src/cf.data.pre
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v
retrieving revision 1.5
retrieving revision 1.5.12.1
diff -u -r1.5 -r1.5.12.1
--- squid/src/cf.data.pre	12 Dec 2000 23:21:17 -0000	1.5
+++ squid/src/cf.data.pre	17 Dec 2000 14:36:23 -0000	1.5.12.1
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.5 2000/12/12 23:21:17 adri Exp $
+# $Id: cf.data.pre,v 1.5.12.1 2000/12/17 14:36:23 hno Exp $
 #
 #
 # SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -3306,5 +3306,40 @@
 	force fresh content.
 DOC_END
 
+NAME: watch_failure
+IFDEF: DISK_REPL
+TYPE: wordlist
+LOC: Config.disk_repl_watch_list
+DEFAULT: none
+DOC_START
+	List of the form 
+    <device_file> <cache_dir> <device_file> <cache_dir> ...
+	when device_file fails, cache_dir goes offline.
+DOC_END
+
+NAME: offline_notify_cmd
+IFDEF: DISK_REPL
+TYPE: string
+LOC: Config.offline_notify_cmd
+DEFAULT: none
+DOC_START
+	Command to be executed when some cache_dir goes 
+	offline. This command will be executed with tree parameters:
+	path to the cache_dir, cache_dir index and device file on which dir 
+	is mounted.
+DOC_END
+
+NAME: online_notify_cmd
+IFDEF: DISK_REPL
+TYPE: string
+LOC: Config.online_notify_cmd
+DEFAULT: none
+DOC_START
+	Command to be executed when some cache_dir goes back
+	online. This command will be executed with tree parameters:
+	path to the cache_dir, cache_dir index and device file on which dir 
+	is mounted.
+DOC_END
+
 EOF
 
Index: squid/src/client_side.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v
retrieving revision 1.10.2.1.4.1
retrieving revision 1.10.2.1.4.1.2.1
diff -u -r1.10.2.1.4.1 -r1.10.2.1.4.1.2.1
--- squid/src/client_side.c	17 Dec 2000 14:09:08 -0000	1.10.2.1.4.1
+++ squid/src/client_side.c	17 Dec 2000 14:36:23 -0000	1.10.2.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.c,v 1.10.2.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: client_side.c,v 1.10.2.1.4.1.2.1 2000/12/17 14:36:23 hno Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -2530,11 +2530,10 @@
     int len = conn->in.size - conn->in.offset - 1;
     debug(33, 4) ("clientReadRequest: FD %d: reading request...\n", fd);
     statCounter.syscalls.sock.reads++;
-    size = read(fd, conn->in.buf + conn->in.offset, len);
+    size = comm_read_wrapper(fd, conn->in.buf + conn->in.offset, len);
     if (size > 0) {
 	fd_bytes(fd, size, FD_READ);
 	kb_incr(&statCounter.client_http.kbytes_in, size);
-	CLEAR_CAN_READ_IF_EMPTY( len, size, fd );
     }
     /*
      * Don't reset the timeout value here.  The timeout value will be
@@ -2567,7 +2566,6 @@
 	    comm_close(fd);
 	    return;
 	} else {
-	  CLEAR_CAN_READ( fd );
 	  if (conn->in.offset == 0) {
 	    debug(50, 2) ("clientReadRequest: FD %d: no data to process (%s)\n", fd, xstrerror());
 	    return;
Index: squid/src/comm.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/comm.c,v
retrieving revision 1.4.14.1.4.1
retrieving revision 1.4.14.1.4.1.2.1
diff -u -r1.4.14.1.4.1 -r1.4.14.1.4.1.2.1
--- squid/src/comm.c	17 Dec 2000 14:09:08 -0000	1.4.14.1.4.1
+++ squid/src/comm.c	17 Dec 2000 14:36:23 -0000	1.4.14.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm.c,v 1.4.14.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: comm.c,v 1.4.14.1.4.1.2.1 2000/12/17 14:36:23 hno Exp $
  *
  * DEBUG: section 5     Socket Functions
  * AUTHOR: Harvest Derived
@@ -73,6 +73,7 @@
 static int commResetFD(ConnectStateData * cs);
 static int commRetryConnect(ConnectStateData * cs);
 CBDATA_TYPE(ConnectStateData);
+static SyscallCBInvoc syscallCallback[ SYSCALL_MAX ][ MAX_SYSCALLCB ];
 
 static MemPool *comm_write_pool = NULL;
 static MemPool *conn_close_pool = NULL;
@@ -832,13 +833,18 @@
       fd_table[ fd ].flags.async_tcp = 1;
       fd_table[ fd ].flags.can_read = 1;
       fd_table[ fd ].flags.can_write = 1;
+      setLostIOBitmap( fd );
     }
 }
 
 /* TCP_ASYNC */
 #endif
 
-
+#if defined( DISK_REPL )
+/* for crash simulation */
+SimulateCrashData swatAButterfly;
+/* DISK_REPL */
+#endif
 
 void
 comm_init(void)
@@ -850,9 +856,22 @@
      * Since Squid_MaxFD can be as high as several thousand, don't waste them */
     RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
     CBDATA_INIT_TYPE(ConnectStateData);
-#ifdef TCP_ASYNC
+#if TCP_ASYNC
     our_pid = getpid();
 #endif
+    memset( syscallCallback, 0, sizeof syscallCallback );
+#if DISK_REPL
+    /* hard-coded */
+    swatAButterfly.swapDirNo = 0;
+    /* 20 seconds, ÐÏÌÅÔ ÎÏÒÍÁÌØÎÙÊ... */
+    swatAButterfly.crashTime = time( NULL ) + 20;
+#if SIMLUATE_READ_CRASH
+    addReadHook( simulateCrash, &swatAButterfly);
+#endif
+#if SIMULATE_WRITE_CRASH
+    addWriteHook( simulateCrash, &swatAButterfly);
+#endif
+#endif /* DISK_REPL */
     comm_write_pool = memPoolCreate("CommWriteStateData", sizeof(CommWriteStateData));
     conn_close_pool = memPoolCreate("close_handler", sizeof(close_handler));
 }
@@ -870,7 +889,7 @@
 	fd, (int) state->offset, state->size);
 
     nleft = state->size - state->offset;
-    len = write(fd, state->buf + state->offset, nleft);
+    len = comm_write_wrapper(fd, state->buf + state->offset, nleft);
     debug(5, 5) ("commHandleWrite: write() returns %d\n", len);
     fd_bytes(fd, len, FD_WRITE);
     statCounter.syscalls.sock.writes++;
@@ -890,7 +909,6 @@
 	} else if (ignoreErrno(errno)) {
 	    debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
 		fd, xstrerror());
-	    CLEAR_CAN_WRITE( fd );
 	    commSetSelect(fd,
 		COMM_SELECT_WRITE,
 		commHandleWrite,
@@ -902,7 +920,6 @@
 	    CommWriteStateCallbackAndFree(fd, COMM_ERROR);
 	}
     } else {
-        CLEAR_CAN_WRITE_IF_FULL( nleft, len, fd );
 	/* A successful write, continue */
 	state->offset += len;
 	if (state->offset < state->size) {
@@ -954,6 +971,48 @@
     comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
 }
 
+/* wrapper around syscall */
+int comm_read_wrapper( int fd, char *buf, int size )
+{
+  int ret;
+
+  assert( buf != NULL );
+  assert( size >= 0 );
+
+  ret = read( fd, buf, size );
+#if defined( TCP_ASYNC )
+  if( ( ( ret == -1 ) && ignoreErrno( errno ) ) ||
+      ( 0 && ( ret > 0 ) && ( ret < size ) ) )
+    {
+      CLEAR_CAN_READ( fd );
+    }
+/* TCP_ASYNC */
+#endif
+  callReadHook( fd, &errno );
+  return ret;
+}
+
+/* wrapper around syscall */
+int comm_write_wrapper( int fd, char *buf, int size )
+{
+  int ret;
+
+  assert( buf != NULL );
+  assert( size >= 0 );
+
+  ret = write( fd, buf, size );
+#if defined( TCP_ASYNC )
+  if( ( ( ret == -1 ) && ignoreErrno( errno ) ) ||
+      ( 0 && ( ret > 0 ) && ( ret < size ) ) )
+    {
+      CLEAR_CAN_WRITE( fd );
+    }
+/* TCP_ASYNC */
+#endif
+  callWriteHook( fd, &errno );
+  return ret;
+}
+
 /*
  * hm, this might be too general-purpose for all the places we'd
  * like to use it.
@@ -1005,3 +1064,103 @@
 	}
     }
 }
+
+/* syscall callbacks */
+#define SCB_DEBUG( format, args... )					\
+         debug( 5, 9 )( CURRENT_FUNCTION_NAME " (%s:%i): " format "\n",	\
+			__FILE__, __LINE__ , ##args )
+
+#define SCB_TRACE  SCB_DEBUG( "" )
+
+int addSyscallCB( SyscallCBInvoc *hook, SyscallCallBack cb, void *data )
+{
+  int i;
+
+  assert( hook != NULL );
+
+  SCB_TRACE;
+  for( i = 0 ; i < MAX_SYSCALLCB ; ++i )
+    {
+      if( hook[ i ].cb == NULL )
+	{
+	  hook[ i ].cb = cb;
+	  hook[ i ].data = data;
+	  return 1;
+	}
+    }
+  return 0;
+}
+
+int delSyscallCB( SyscallCBInvoc *hook, SyscallCallBack cb )
+{
+  int i;
+
+  assert( hook != NULL );
+
+  SCB_TRACE;
+  for( i = 0 ; i < MAX_SYSCALLCB ; ++i )
+    {
+      if( hook[ i ].cb == cb )
+	{
+	  hook[ i ].cb = NULL;
+	  hook[ i ].data = NULL;
+	  return 1;
+	}
+    }
+  return 0;
+}
+
+int addReadHook( SyscallCallBack cb, void *data )
+{
+  SCB_TRACE;
+  return addSyscallCB( syscallCallback[ SYSCALL_READ ], cb, data );
+}
+
+int addWriteHook( SyscallCallBack cb, void *data )
+{
+  SCB_TRACE;
+  return addSyscallCB( syscallCallback[ SYSCALL_WRITE ], cb, data );
+}
+
+syscallcb_result callSyscallCBHook( SyscallCBInvoc *hook, 
+				    syscall_type call,
+				    int fd, int *errNo )
+{
+  assert( hook != NULL );
+  
+  SCB_TRACE;
+  for( ; hook -> cb != NULL ; ++hook )
+    {
+      syscallcb_result result;
+
+      result = ( hook -> cb )( call, fd, errNo, hook -> data );
+      if( result == SYSCALLCB_ABORT )
+	{
+	  return SYSCALLCB_ABORT;
+	}
+    }
+  return SYSCALLCB_CONTINUE;
+}
+
+syscallcb_result callReadHook( int fd, int *errNo )
+{
+  SCB_TRACE;
+  return callSyscallCBHook( syscallCallback[ SYSCALL_READ ], 
+			    SYSCALL_READ, fd, errNo );
+}
+
+syscallcb_result callWriteHook( int fd, int *errNo )
+{
+  SCB_TRACE;
+  return callSyscallCBHook( syscallCallback[ SYSCALL_WRITE ], 
+			    SYSCALL_WRITE, fd, errNo );
+}
+
+syscallcb_result echoSyscallCB( syscall_type call,
+				int fd, int *errNo,
+				void *data )
+{
+  SCB_DEBUG( "call: %i fd: %i errno: %i data: %p", call, fd, *errNo, data );
+  return SYSCALLCB_CONTINUE;
+}
+
Index: squid/src/comm_cio.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/comm_cio.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.1.2.1
diff -u -r1.1.2.1 -r1.1.2.1.2.1
--- squid/src/comm_cio.c	17 Dec 2000 14:09:08 -0000	1.1.2.1
+++ squid/src/comm_cio.c	17 Dec 2000 14:36:23 -0000	1.1.2.1.2.1
@@ -1,5 +1,5 @@
 /*
- * $Id: comm_cio.c,v 1.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: comm_cio.c,v 1.1.2.1.2.1 2000/12/17 14:36:23 hno Exp $
  *
  * DEBUG: section 90     Signal-driven network IO
  * AUTHOR: Nikita Danilov <NikitaDanilov@Yahoo.COM>
@@ -136,9 +136,6 @@
 
 #include <linux/reiserfs_fs.h>
 
-/** if we use ioctl in stead of sigtimedwait, ioctl_fd is descriptor
-	of reiserfs directory on which ioctl is issued. */
-static int ioctl_fd = -1;
 /* SIGRTMAX is not constant?! */
 /** global array of per-signal-number callbacks */
 static CioCallback callbacks[ _NSIG ];
@@ -153,6 +150,61 @@
 	handlers, taking deferred reads into account */
 extern int cioStdCallback( siginfo_t *info );
 
+#if defined( __GNUC__ )
+#define BITMAP_TYPE   long long
+#define BITMAP_BIT    1LL
+#else
+#define BITMAP_TYPE   long
+#define BITMAP_BIT    1L
+#endif
+
+static BITMAP_TYPE *lostIOBitmap;
+
+#define INDEX_IN_BITMAP( offset ) ( offset / sizeof lostIOBitmap[ 0 ] )
+#define OFFSET_IN_BYTE( offset ) ( offset % sizeof lostIOBitmap[ 0 ] )
+
+#define MASK_IN_BITMAP( offset ) ( BITMAP_BIT << OFFSET_IN_BYTE( offset ) )
+#define SET_BIT_IN_BITMAP( offset ) \
+   lostIOBitmap[ INDEX_IN_BITMAP( offset ) ] |= MASK_IN_BITMAP( offset )
+
+#define CLN_BIT_IN_BITMAP( offset ) \
+   lostIOBitmap[ INDEX_IN_BITMAP( offset ) ] &= ~MASK_IN_BITMAP( offset )
+
+
+#if defined( CIOCIOSAN_USE_SIGHANDLER )
+
+#include <asm/atomic.h>
+#include <signal.h>
+
+#define SIGINFOS_IN_QUEUE ( 1024 + 42 ) /* XXX just some arbitrary number */
+static volatile struct CioSiginfoQueue {
+  /* 
+	 XXX sig_atomic_t is only guaranteed to work correctly 
+	 on the uniprocessor. Hence I will use atomic_t in it stead.
+  */
+  volatile atomic_t count;
+  volatile siginfo_t info[ SIGINFOS_IN_QUEUE ]; 
+} queue;
+
+static void cioSigHandler( int sigNum, siginfo_t *info, void *data )
+{
+  if( atomic_read( &queue.count ) < SIGINFOS_IN_QUEUE )
+	{
+	  memcpy( ( void * )&queue.info[ atomic_read( &queue.count ) ], info, 
+			  sizeof *info );
+	  atomic_inc( ( atomic_t * )&queue.count );
+	}
+}
+
+#else
+
+/** if we use ioctl in stead of sigtimedwait, ioctl_fd is descriptor
+	of reiserfs directory on which ioctl is issued. */
+static int ioctl_fd = -1;
+
+/* CIOCIOSAN_USE_SIGHANDLER */
+#endif
+
 /** call this to register your own callback. SIG_NUM will be blocked
 	by this call. */
 int commCioAddCB( int sig_num, CioCallback callback )
@@ -160,10 +212,21 @@
   TRACE;
   if( callbacks[ sig_num ] == NULL )
     {
-      callbacks[ sig_num ] = callback;
+#if !defined( CIOCIOSAN_USE_SIGHANDLER )
       sigaddset( &listenOn, sig_num );
       sigprocmask( SIG_BLOCK, &listenOn, NULL );
-  
+#else
+	  struct sigaction act;
+
+	  act.sa_sigaction = cioSigHandler;
+	  act.sa_flags = SA_SIGINFO;
+	  if( sigaction( sig_num, &act, NULL ) == -1 )
+		{
+		  DEBUG( "commCioAddCB: sigaction( %i ) fails: %s\n",
+				 sig_num, xstrerror() );
+		}
+#endif  
+      callbacks[ sig_num ] = callback;
       return 1;
     }
   else
@@ -175,12 +238,13 @@
 /** initialize Cio Cio San */
 int initCommCio()
 {
+#if !defined( CIOCIOSAN_USE_SIGHANDLER )
   int i;
 
   /* scan all configured cache dirs to find butterfly.  We need
 	 butterfly as it always works on top of a reiserfs directory and
 	 we need one reiserfs directory to use our magic ioctl. */
-  for( i = 0 ; i < Config.cacheSwap.n_configured ; i++ )
+  FOREACHSDINDEX( i )
 	{
 	  SwapDir *sd;
 	  
@@ -198,34 +262,72 @@
 	  ioctl_fd = open( "/cache", O_RDONLY );
 	}
 
-  if( ioctl_fd > 0 )
-	{
-	  /* prepare global data structures */
-	  memset( callbacks, 0, sizeof callbacks );
-	  sigemptyset( &listenOn );
-
-	  statCounter.syscalls.async.signals = 0;
-	  statCounter.syscalls.async.read_sigs = 0;
-	  statCounter.syscalls.async.write_sigs = 0;
-	  statCounter.syscalls.async.loops = 0;
-	  statCounter.syscalls.async.avg_ready_read = 0.0;
-	  statCounter.syscalls.async.avg_ready_write = 0.0;
-	  statCounter.syscalls.async.tail_reads = 0;
-	  statCounter.syscalls.async.tail_writes = 0;
-	  statCounter.syscalls.async.drain_reads = 0;
-	  statCounter.syscalls.async.drain_writes = 0;
-
-	  TRACE;
-	  commCioAddCB( SIGCIOCIOSAN, cioStdCallback );
-	  return 1;
-	}
-  else
+  if( ioctl_fd < 0 )
 	{
 	  /* will use normal sigtimedwait */
 	  DEBUG( "initCommCio: Keine butterfly cache_dir gefunden."
 			 " Cio Cio San will use sigtimedwait(2).\n" );
 	  return 0;
 	}
+#else
+  DEBUG( "initCommCio: will use notification through signal handler\n" );
+
+  atomic_set( &queue.count, 0 );
+  memset( ( void * ) queue.info, 0, sizeof queue.info );
+
+/* CIOCIOSAN_USE_SIGHANDLER */
+#endif
+  /* prepare global data structures */
+  memset( callbacks, 0, sizeof callbacks );
+  sigemptyset( &listenOn );
+  statCounter.syscalls.async.signals = 0;
+  statCounter.syscalls.async.read_sigs = 0;
+  statCounter.syscalls.async.write_sigs = 0;
+  statCounter.syscalls.async.loops = 0;
+  statCounter.syscalls.async.avg_ready_read = 0.0;
+  statCounter.syscalls.async.avg_ready_write = 0.0;
+  statCounter.syscalls.async.tail_reads = 0;
+  statCounter.syscalls.async.tail_writes = 0;
+  statCounter.syscalls.async.drain_reads = 0;
+  statCounter.syscalls.async.drain_writes = 0;
+  
+  lostIOBitmap = 
+	xcalloc( Biggest_FD / sizeof lostIOBitmap[ 0 ] / 8 + 1,
+			 sizeof lostIOBitmap[ 0 ] );
+  commCioAddCB( SIGCIOCIOSAN, cioStdCallback );
+  return 1;
+}
+
+static void processOneSiginfo( siginfo_t *info )
+{
+  if( callbacks[ info -> si_signo ] != NULL )
+	{
+	  if( fd_table[ info -> si_fd ].flags.async_tcp )
+		{
+		  TRACE0( "callback: fd: %i, signo: %i", 
+				  info -> si_fd, info -> si_signo );
+		  callbacks[ info -> si_signo ]( info );
+		  ++statCounter.syscalls.async.signals;
+		}
+	  else if( !fd_table[ info -> si_fd ].flags.open )
+		{
+		  DEBUG
+			( "commCioLoop: got signal: %i for already closed fd: %i\n", 
+			  info -> si_signo, info -> si_fd );
+		}
+	  else
+		{
+		  DEBUG
+			( "commCioLoop: got unexpected signal: %i for fd: %i\n", 
+			  info -> si_signo, info -> si_fd );
+		}
+	}
+  else
+	{
+	  DEBUG
+		( "commCioLoop: got unexpected signal: %i\n", 
+		  info -> si_signo );
+	}
 }
 
 /* main signal polling loop. Uses either ioctl( REISERFS_IOC_TIMEDWAIT )
@@ -233,11 +335,12 @@
    signals received. Sets can_* flags in fds. */   
 int commCioLoop()
 {
+  int ranOnce;
+#if !defined( CIOCIOSAN_USE_SIGHANDLER )
   struct reiserfs_sigtimedwait_arg arg;
   siginfo_t siginfo[ SIGINFO_PER_CALL ];
-  struct timespec timeout = {0,0};
+  struct timespec timeout = { 0, 0 };
   int numOfSigs;
-  int ranOnce;
 
   arg.uthese = &listenOn;
   arg.sigsetsize = 8; /* sizeof mask; */
@@ -262,37 +365,7 @@
 	  ranOnce = 1;
       for( i = 0 ; i < numOfSigs ; ++i )
 		{
-		  siginfo_t *info;
-
-		  info = &siginfo[ i ];
-		  if( callbacks[ info -> si_signo ] != NULL )
-			{
-			  if( fd_table[ info -> si_fd ].flags.async_tcp )
-				{
-				  TRACE0( "callback: fd: %i, signo: %i", 
-						  info -> si_fd, info -> si_signo );
-				  callbacks[ info -> si_signo ]( info );
-				  ++statCounter.syscalls.async.signals;
-				}
-			  else if( !fd_table[ info -> si_fd ].flags.open )
-				{
-				  DEBUG
-					( "commCioLoop: got signal: %i for already closed fd: %i\n", 
-					  info -> si_signo, info -> si_fd );
-				}
-			  else
-				{
-				  DEBUG
-					( "commCioLoop: got unexpected signal: %i for fd: %i\n", 
-					  info -> si_signo, info -> si_fd );
-				}
-			}
-		  else
-			{
-			  DEBUG
-				( "commCioLoop: got unexpected signal: %i\n", 
-				  info -> si_signo );
-			}
+		  processOneSiginfo( &siginfo[ i ] );
 		}
     }
   if( ranOnce )
@@ -315,6 +388,33 @@
 		  return COMM_ERROR;
 		}
 	}
+/* CIOCIOSAN_USE_SIGHANDLER */
+#else
+  ranOnce = 0;
+  if( atomic_read( &queue.count ) >= SIGINFOS_IN_QUEUE )
+	{
+	  debug( 90, 1 ) ( "commCioLoop: queue overrun.\n" );
+	  atomic_dec( ( atomic_t * ) &queue.count );
+	}
+  else while( atomic_read( &queue.count ) > 0 )
+	{
+	  /* blammm, handler breaks in here, but it only increases count, ok */
+	  siginfo_t info;
+	  ranOnce = 1;
+	  /* blammm, handler breaks in during memcpy, ok */
+	  assert( ( atomic_read( &queue.count ) > 0 ) &&
+			  ( atomic_read( &queue.count ) < SIGINFOS_IN_QUEUE ) );
+	  memcpy 
+		( &info, ( void * ) &queue.info[ atomic_read( &queue.count ) - 1 ], 
+		  sizeof info );
+	  /* blammm, handler breaks in here, increases count, ok */
+	  atomic_dec( ( atomic_t * ) &queue.count );
+	  /* blammm, handler breaks in here, increases count, ok */
+	  processOneSiginfo( &info );
+	}
+  return ranOnce ? COMM_OK : COMM_TIMEOUT;
+/* CIOCIOSAN_USE_SIGHANDLER */
+#endif
 }
 
 /* taken from comm_select.c */
@@ -336,7 +436,7 @@
    ,,special processing`` means we have to call callbacks with special
    parameters (ask someone else why) */
 
-static int fdIsHttp( int fd )
+static inline int fdIsHttp( int fd )
 {
   int j;
 
@@ -350,31 +450,57 @@
   return 0;
 }
 
-static int fdIsIcp( int fd )
+static inline int fdIsIcp( int fd )
 {
-  if( fd == theInIcpConnection )
-	{
-	  return 1;
-	}
-  if( fd == theOutIcpConnection )
-	{
-	  return 1;
-	}
-  return 0;
+  return( ( fd == theInIcpConnection ) || ( fd == theOutIcpConnection ) );
+}
+
+static inline int fdIsDns( int fd )
+{
+  return( fd == DnsSocket );
 }
 
-static int fdIsDns( int fd )
+static int inline isDatalessSocket( int fd )
 {
-  if( fd == DnsSocket )
+  return( fdIsHttp( fd ) || fdIsIcp( fd ) || fdIsDns( fd ) );
+}
+
+static inline void cioProcessReadFD( int index )
+{
+  fde *F;
+  PF *handler;
+  int dummy;
+
+  assert( ( 0 <= index ) && ( index <= Biggest_FD ) );
+  assert( fd_table[ index ].flags.can_read );
+
+  F = &fd_table[ index ];
+  DEBUG( "cioProcessReadFD: FD %d lost read", index );
+  if( !commCioDeferRead( index ) && 
+	  ( ( handler = F -> read_handler ) != NULL ) )
 	{
-	  return 1;
+	  F -> read_handler = NULL;
+	  handler( index, isDatalessSocket( index ) ? &dummy : F -> read_data );
 	}
-  return 0;
 }
 
-int isDatalessSocket( int fd )
+static inline void cioProcessWriteFD( int index )
 {
-  return( fdIsHttp( fd ) || fdIsIcp( fd ) || fdIsDns( fd ) );
+  fde *F;
+  PF *handler;
+  int dummy;
+
+  assert( ( 0 <= index ) && ( index <= Biggest_FD ) );
+  assert( fd_table[ index ].flags.can_write );
+
+  F = &fd_table[ index ];
+
+  DEBUG( "cioProcessWriteFD: FD %d lost write", index );
+  if( ( handler = F -> write_handler ) != NULL )
+	{
+	  F -> write_handler = NULL;
+	  handler( index, isDatalessSocket( index ) ? &dummy : F -> write_data );
+	}
 }
 
 /* see description in declaration */
@@ -390,18 +516,21 @@
   assert( fd >= 0 );
   assert( f -> flags.open );
 
+  SET_BIT_IN_BITMAP( fd );
   result = 0;
   if( info -> si_band & ( POLLRDNORM | POLLIN | POLLHUP | POLLERR ) )
 	{
 	  /* non-blocking read is possible */
 	  fd_table[ fd ].flags.can_read = 1;
 	  ++statCounter.syscalls.async.read_sigs;
+	  cioProcessReadFD( fd );
 	}
   if( info -> si_band & ( POLLWRNORM | POLLOUT | POLLHUP | POLLERR ) )
 	{
 	  /* non-blocking write is possible */
 	  fd_table[ fd ].flags.can_write = 1;
 	  ++statCounter.syscalls.async.write_sigs;
+	  cioProcessWriteFD( fd );
 	}
   /* Just sanity check. */
   if( ( !( info -> si_band & 
@@ -449,9 +578,16 @@
   for( i = 0 ; i <= Biggest_FD ; i++ )
 	{
 	  fde *F;
-	  int dummy;
-	  PF *handler;
-	  int  incoming;
+
+	  /* run through bitmap */
+	  for( ; 
+		   lostIOBitmap[ INDEX_IN_BITMAP( i ) ] == 0 ; 
+		   i += sizeof lostIOBitmap[ 0 ] )
+		{}
+	  if( i > Biggest_FD )
+		{
+		  break;
+		}
 
 	  F = &fd_table[ i ];
 
@@ -467,28 +603,15 @@
 		{
 		  /* is this is socket listening for incoming HTTP connections or
 			 DNS socket etc.? */
-		  incoming = -1;
-		  if( F -> flags.can_read && ( handler = F -> read_handler ) )
+		  if( F -> flags.can_read )
 			{
 			  ++readReady;
-			  incoming = isDatalessSocket( i );
-			  DEBUG( "cioCatchLostIO: FD %d lost read", i );
-			  if( !commCioDeferRead( i ) )
-				{
-				  F -> read_handler = NULL;
-				  handler( i, incoming ? &dummy : F -> read_data );
-				}
+			  cioProcessReadFD( i );
 			}
-		  if( F -> flags.can_write && ( handler = F -> write_handler ) )
+		  if( F -> flags.can_write )
 			{
 			  ++writeReady;
-			  if( incoming == -1 )
-				{
-				  incoming = isDatalessSocket( i );
-				}
-			  DEBUG( "cioCatchLostIO: FD %d lost write", i );
-			  F -> write_handler = NULL;
-			  handler( i, incoming ? &dummy : F -> write_data );
+			  cioProcessWriteFD( i );
 			}
 		}
 	}
@@ -505,6 +628,16 @@
   return 1;
 }
 
+void clearLostIOBitmap( int fd )
+{
+  CLN_BIT_IN_BITMAP( fd );
+}
+
+void setLostIOBitmap( int fd )
+{
+  SET_BIT_IN_BITMAP( fd );
+}
+
 /* TCP_ASYNC */
 #endif
 
@@ -515,6 +648,9 @@
 
 /*
  * $Log: comm_cio.c,v $
+ * Revision 1.1.2.1.2.1  2000/12/17 14:36:23  hno
+ * Imported raid from squidng
+ *
  * Revision 1.1.2.1  2000/12/17 14:09:08  hno
  * Imported tcp_async from squidng
  *
Index: squid/src/defines.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/defines.h,v
retrieving revision 1.3.16.1.2.1
retrieving revision 1.3.16.1.2.1.4.1
diff -u -r1.3.16.1.2.1 -r1.3.16.1.2.1.4.1
--- squid/src/defines.h	17 Dec 2000 13:55:39 -0000	1.3.16.1.2.1
+++ squid/src/defines.h	17 Dec 2000 14:36:23 -0000	1.3.16.1.2.1.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: defines.h,v 1.3.16.1.2.1 2000/12/17 13:55:39 hno Exp $
+ * $Id: defines.h,v 1.3.16.1.2.1.4.1 2000/12/17 14:36:23 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -287,3 +287,92 @@
 #define CBDATA_TYPE(type)	static cbdata_type CBDATA_##type = 0
 #define CBDATA_INIT_TYPE(type)	(CBDATA_##type = cbdataAddType(CBDATA_##type, #type, sizeof(type)))
 
+/* cio cio san */
+#if defined( TCP_ASYNC )
+
+/* It's Butterfly's real name */
+#define SIGCIOCIOSAN ( SIGRTMIN + 8 )
+
+#define SIGINFO_PER_CALL 128
+
+#if defined( __GNUC__ )
+#define CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__
+#else
+#define CURRENT_FUNCTION_NAME __FUNC__
+#endif
+
+#define CLEAR_CAN_READ_INTERNAL( fd )									\
+	  debug( 90, 9 )( CURRENT_FUNCTION_NAME ": cleared can_read.\n" );	\
+	  fd_table[ fd ].flags.can_read = 0;								\
+      if( !fd_table[ fd ].flags.can_write ) clearLostIOBitmap( fd )
+
+#define CLEAR_CAN_WRITE_INTERNAL( fd )									\
+	  debug( 90, 9 )( CURRENT_FUNCTION_NAME ": cleared can_write.\n" );	\
+	  fd_table[ fd ].flags.can_write = 0;								\
+      if( !fd_table[ fd ].flags.can_read ) clearLostIOBitmap( fd )
+
+#define CLEAR_CAN_READ( fd ) do {							\
+      CLEAR_CAN_READ_INTERNAL( fd );						\
+      ++statCounter.syscalls.async.tail_reads; } while( 0 )
+
+#define CLEAR_CAN_WRITE( fd ) do {								\
+      CLEAR_CAN_WRITE_INTERNAL( fd );							\
+      ++statCounter.syscalls.async.tail_writes; } while( 0 )
+
+#define CLEAR_CAN_READ_IF_EMPTY( requestedSize, actuallyRead, fd )		\
+  do																	\
+    {																	\
+	  if( ( actuallyRead > 0 ) && ( actuallyRead < requestedSize ) )	\
+		{																\
+		  /* CLEAR_CAN_READ_INTERNAL( fd ); */							\
+          ++statCounter.syscalls.async.drain_reads;						\
+		}																\
+	}																	\
+  while( 0 )
+
+#define CLEAR_CAN_WRITE_IF_FULL( requestedSize, actuallyWritten, fd )		\
+  do																		\
+    {																		\
+	  if( ( actuallyWritten > 0 ) && ( actuallyWritten < requestedSize ) )	\
+		{																	\
+		  /* CLEAR_CAN_WRITE_INTERNAL( fd ); */								\
+          ++statCounter.syscalls.async.drain_writes;						\
+		}																	\
+	}																		\
+  while( 0 )
+
+/* !TCP_ASYNC */
+#else
+
+#define CLEAR_CAN_READ( fd )  do {} while( 0 )
+#define CLEAR_CAN_WRITE( fd ) do {} while( 0 )
+#define CLEAR_CAN_READ_IF_EMPTY( requestedSize, actuallyRead, fd ) \
+  do {} while( 0 )
+#define CLEAR_CAN_WRITE_IF_FULL( requestedSize, actuallyWritten, fd )	\
+  do {} while( 0 )
+
+/* TCP_ASYNC */
+#endif
+
+#if defined( DISK_REPL )
+
+/* errno returned if drive dies */
+#define DISK_DIES_ERRNO    EIO /* ENXIO */
+/* how many DISK_DIES_ERRNOs tolerate before declaring drive dead */
+#define ERRORS_THRESHOLD   2
+
+#define RAID_CTRL_SIG SIGRTMIN + 9
+
+/* RAID_REPL */
+#endif
+
+/* how many global syscall callbacks can be registered */
+#define MAX_SYSCALLCB   128
+
+#define FOREACHSDINDEX( var ) \
+           for( var = 0 ; var < Config.cacheSwap.n_configured ; ++var )
+
+#define FOREACHSD( var ) \
+           for( var = INDEXSD( 0 ) ; \
+                var < INDEXSD( Config.cacheSwap.n_configured ) ; ++var )
+
Index: squid/src/disk.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/disk.c,v
retrieving revision 1.4.20.1
retrieving revision 1.4.20.1.2.1
diff -u -r1.4.20.1 -r1.4.20.1.2.1
--- squid/src/disk.c	17 Dec 2000 14:09:08 -0000	1.4.20.1
+++ squid/src/disk.c	17 Dec 2000 14:36:23 -0000	1.4.20.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: disk.c,v 1.4.20.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: disk.c,v 1.4.20.1.2.1 2000/12/17 14:36:23 hno Exp $
  *
  * DEBUG: section 6     Disk I/O Routines
  * AUTHOR: Harvest Derived
@@ -71,7 +71,7 @@
 	    xstrerror());
 	fd = DISK_ERROR;
     } else {
-	debug(6, 5) ("file_open: FD %d\n", fd);
+	debug(91, 9) ("file_open: FD %d (%s)\n", fd, path);
 	commSetCloseOnExec(fd);
 	fd_open(fd, FD_FILE, path);
     }
@@ -192,7 +192,7 @@
     errno = 0;
     if (fdd->write_q->file_offset != -1)
 	lseek(fd, fdd->write_q->file_offset, SEEK_SET);
-    len = write(fd,
+    len = comm_write_wrapper(fd,
 	fdd->write_q->buf + fdd->write_q->buf_offset,
 	fdd->write_q->len - fdd->write_q->buf_offset);
     debug(6, 3) ("diskHandleWrite: FD %d len = %d\n", fd, len);
@@ -233,17 +233,8 @@
 		}
 	    } while ((q = fdd->write_q));
 	}
-	else
-	  {
-	    CLEAR_CAN_WRITE( fd );
-	  }
 	len = 0;
     }
-    else
-      {
-	CLEAR_CAN_WRITE_IF_FULL( fdd->write_q->len - fdd->write_q->buf_offset,
-				 len, fd );
-      }
     if (q != NULL) {
 	/* q might become NULL from write failure above */
 	q->buf_offset += len;
Index: squid/src/enums.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/enums.h,v
retrieving revision 1.6.4.1.2.1
retrieving revision 1.6.4.1.2.1.4.1
diff -u -r1.6.4.1.2.1 -r1.6.4.1.2.1.4.1
--- squid/src/enums.h	17 Dec 2000 13:55:39 -0000	1.6.4.1.2.1
+++ squid/src/enums.h	17 Dec 2000 14:36:24 -0000	1.6.4.1.2.1.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.6.4.1.2.1 2000/12/17 13:55:39 hno Exp $
+ * $Id: enums.h,v 1.6.4.1.2.1.4.1 2000/12/17 14:36:24 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -705,3 +705,15 @@
     CBDATA_storeIOState,
     CBDATA_FIRST_CUSTOM_TYPE
 } cbdata_type;
+
+typedef enum {
+  SYSCALLCB_CONTINUE,
+  SYSCALLCB_ABORT
+} syscallcb_result;
+
+typedef enum {
+  SYSCALL_READ = 0,
+  SYSCALL_WRITE,
+  SYSCALL_MAX
+} syscall_type;
+
Index: squid/src/fd.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fd.c,v
retrieving revision 1.4.10.1
retrieving revision 1.4.10.1.2.1
diff -u -r1.4.10.1 -r1.4.10.1.2.1
--- squid/src/fd.c	17 Dec 2000 14:09:08 -0000	1.4.10.1
+++ squid/src/fd.c	17 Dec 2000 14:36:24 -0000	1.4.10.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: fd.c,v 1.4.10.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: fd.c,v 1.4.10.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 51    Filedescriptor Functions
  * AUTHOR: Duane Wessels
@@ -88,6 +88,9 @@
     commUpdateWriteBits(fd, NULL);
     memset(F, '\0', sizeof(fde));
     F->timeout = 0;
+    F->swap_dir = -1;
+    CLEAR_CAN_READ( fd );
+    CLEAR_CAN_WRITE( fd );
 }
 
 void
@@ -108,6 +111,7 @@
     if (desc)
 	xstrncpy(F->desc, desc, FD_DESC_SZ);
     Number_FD++;
+    F->swap_dir = -1;
 }
 
 void
Index: squid/src/ftp.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/ftp.c,v
retrieving revision 1.5.10.1.4.1
retrieving revision 1.5.10.1.4.1.2.1
diff -u -r1.5.10.1.4.1 -r1.5.10.1.4.1.2.1
--- squid/src/ftp.c	17 Dec 2000 14:09:08 -0000	1.5.10.1.4.1
+++ squid/src/ftp.c	17 Dec 2000 14:36:24 -0000	1.5.10.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ftp.c,v 1.5.10.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: ftp.c,v 1.5.10.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 9     File Transfer Protocol (FTP)
  * AUTHOR: Harvest Derived
@@ -879,7 +879,7 @@
 #endif
     memset(ftpState->data.buf + ftpState->data.offset, '\0', read_sz);
     statCounter.syscalls.sock.reads++;
-    len = read(fd, ftpState->data.buf + ftpState->data.offset, read_sz);
+    len = comm_read_wrapper(fd, ftpState->data.buf + ftpState->data.offset, read_sz);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
 #if DELAY_POOLS
@@ -888,7 +888,6 @@
 	kb_incr(&statCounter.server.all.kbytes_in, len);
 	kb_incr(&statCounter.server.ftp.kbytes_in, len);
 	ftpState->data.offset += len;
-	CLEAR_CAN_READ_IF_EMPTY( read_sz, len, fd );
     }
     debug(9, 5) ("ftpDataRead: FD %d, Read %d bytes\n", fd, len);
     if (len > 0) {
@@ -903,7 +902,6 @@
     if (len < 0) {
 	debug(50, ignoreErrno(errno) ? 3 : 1) ("ftpDataRead: read error: %s\n", xstrerror());
 	if (ignoreErrno(errno)) {
-	    CLEAR_CAN_READ( fd );
 	    commSetSelect(fd,
 		COMM_SELECT_READ,
 		ftpDataRead,
@@ -1251,21 +1249,18 @@
     }
     assert(ftpState->ctrl.offset < ftpState->ctrl.size);
     statCounter.syscalls.sock.reads++;
-    len = read(fd,
+    len = comm_read_wrapper(fd,
 	ftpState->ctrl.buf + ftpState->ctrl.offset,
 	ftpState->ctrl.size - ftpState->ctrl.offset);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
 	kb_incr(&statCounter.server.all.kbytes_in, len);
 	kb_incr(&statCounter.server.ftp.kbytes_in, len);
-	CLEAR_CAN_READ_IF_EMPTY( ftpState->ctrl.size - ftpState->ctrl.offset,
-				 len, fd );
     }
     debug(9, 5) ("ftpReadControlReply: FD %d, Read %d bytes\n", fd, len);
     if (len < 0) {
 	debug(50, ignoreErrno(errno) ? 3 : 1) ("ftpReadControlReply: read error: %s\n", xstrerror());
 	if (ignoreErrno(errno)) {
-	    CLEAR_CAN_READ( fd );
 	    ftpScheduleReadControlReply(ftpState, 0);
 	} else {
 	    ftpFailed(ftpState, ERR_READ_ERROR);
Index: squid/src/gopher.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/gopher.c,v
retrieving revision 1.5.4.1.4.1
retrieving revision 1.5.4.1.4.1.2.1
diff -u -r1.5.4.1.4.1 -r1.5.4.1.4.1.2.1
--- squid/src/gopher.c	17 Dec 2000 14:09:08 -0000	1.5.4.1.4.1
+++ squid/src/gopher.c	17 Dec 2000 14:36:24 -0000	1.5.4.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: gopher.c,v 1.5.4.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: gopher.c,v 1.5.4.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 10    Gopher
  * AUTHOR: Harvest Derived
@@ -612,7 +612,7 @@
 #endif
     /* leave one space for \0 in gopherToHTML */
     statCounter.syscalls.sock.reads++;
-    len = read(fd, buf, read_sz);
+    len = comm_read_wrapper(fd, buf, read_sz);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
 #if DELAY_POOLS
@@ -620,7 +620,6 @@
 #endif
 	kb_incr(&statCounter.server.all.kbytes_in, len);
 	kb_incr(&statCounter.server.other.kbytes_in, len);
-	CLEAR_CAN_READ_IF_EMPTY( read_sz, len, fd );
 	commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
 	IOStats.Gopher.reads++;
 	for (clen = len - 1, bin = 0; clen; bin++)
@@ -631,7 +630,6 @@
     if (len < 0) {
 	debug(50, 1) ("gopherReadReply: error reading: %s\n", xstrerror());
 	if (ignoreErrno(errno)) {
-	    CLEAR_CAN_READ( fd );
 	    commSetSelect(fd, COMM_SELECT_READ, gopherReadReply, data, 0);
 	} else if (entry->mem_obj->inmem_hi == 0) {
 	    ErrorState *err;
Index: squid/src/http.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/http.c,v
retrieving revision 1.5.10.1.4.1
retrieving revision 1.5.10.1.4.1.2.1
diff -u -r1.5.10.1.4.1 -r1.5.10.1.4.1.2.1
--- squid/src/http.c	17 Dec 2000 14:09:08 -0000	1.5.10.1.4.1
+++ squid/src/http.c	17 Dec 2000 14:36:24 -0000	1.5.10.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.c,v 1.5.10.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: http.c,v 1.5.10.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -483,7 +483,7 @@
     read_sz = delayBytesWanted(delay_id, 1, read_sz);
 #endif
     statCounter.syscalls.sock.reads++;
-    len = read(fd, buf, read_sz);
+    len = comm_read_wrapper(fd, buf, read_sz);
     debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
@@ -497,7 +497,6 @@
 	for (clen = len - 1, bin = 0; clen; bin++)
 	    clen >>= 1;
 	IOStats.Http.read_hist[bin]++;
-	CLEAR_CAN_READ_IF_EMPTY( read_sz, len, fd );
     }
     if (!httpState->reply_hdr && len > 0) {
 	/* Skip whitespace */
@@ -513,7 +512,6 @@
 	debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
 	    fd, xstrerror());
 	if (ignoreErrno(errno)) {
-	  CLEAR_CAN_READ( fd );
 	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
 	} else if (entry->mem_obj->inmem_hi == 0) {
 	    ErrorState *err;
Index: squid/src/main.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/main.c,v
retrieving revision 1.6.4.1.4.1
retrieving revision 1.6.4.1.4.1.2.1
diff -u -r1.6.4.1.4.1 -r1.6.4.1.4.1.2.1
--- squid/src/main.c	17 Dec 2000 14:09:08 -0000	1.6.4.1.4.1
+++ squid/src/main.c	17 Dec 2000 14:36:24 -0000	1.6.4.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.c,v 1.6.4.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: main.c,v 1.6.4.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -493,6 +493,10 @@
     refererOpenLog();
     httpHeaderInitModule();	/* must go before any header processing (e.g. the one in errorInitialize) */
     httpReplyInitModule();	/* must go before accepting replies */
+#if defined( TCP_ASYNC )
+    /* must go before error text loading */
+    initCommCio();
+#endif
     errorInitialize();
     accessLogInit();
 #if USE_IDENT
@@ -563,10 +567,9 @@
 	eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
     }
 
-#if defined( TCP_ASYNC )
-    initCommCio();
+#if defined( DISK_REPL )
+    raidInitListener();
 #endif
-
     configured_once = 1;
 }
 
@@ -722,7 +725,7 @@
 	if ((loop_delay = eventNextTime()) < 0)
 	    loop_delay = 0;
 #if defined( TCP_ASYNC )
-	/* cannot remove poll/select loops at this time, bacause disk IO 
+	/* cannot remove poll/select loops at this time, because disk IO 
 	   doesn't use signals yet */
 	switch( commCioLoop() ) {
 	case COMM_OK:
@@ -751,10 +754,11 @@
 /* PROFILE_SQUID */
 #endif
 #if HAVE_POLL
-	switch (comm_poll(loop_delay)) {
+	switch (comm_poll(loop_delay))
 #else
-	switch (comm_select(loop_delay)) {
+	switch (comm_select(loop_delay))
 #endif
+	{
 	case COMM_OK:
 	    errcount = 0;	/* reset if successful */
 	    break;
Index: squid/src/protos.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/protos.h,v
retrieving revision 1.6.4.1.2.1.2.1
retrieving revision 1.6.4.1.2.1.2.1.2.1
diff -u -r1.6.4.1.2.1.2.1 -r1.6.4.1.2.1.2.1.2.1
--- squid/src/protos.h	17 Dec 2000 14:09:08 -0000	1.6.4.1.2.1.2.1
+++ squid/src/protos.h	17 Dec 2000 14:36:24 -0000	1.6.4.1.2.1.2.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.6.4.1.2.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: protos.h,v 1.6.4.1.2.1.2.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -149,6 +149,8 @@
     CWCB * handler,
     void *handler_data,
     FREE *);
+extern int comm_read_wrapper( int fd, char *buf, int size );
+extern int comm_write_wrapper( int fd, char *buf, int size );
 extern void comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data);
 extern void commCallCloseHandlers(int fd);
 extern int commSetTimeout(int fd, int, PF *, void *);
@@ -156,6 +158,34 @@
 extern int ignoreErrno(int);
 extern void commCloseAllSockets(void);
 
+extern int addSyscallCB( SyscallCBInvoc *hook, SyscallCallBack cb, void *data );
+extern int delSyscallCB( SyscallCBInvoc *hook, SyscallCallBack cb );
+extern int addReadHook( SyscallCallBack cb, void *data );
+extern int addWriteHook( SyscallCallBack cb, void *data );
+extern syscallcb_result callSyscallCBHook( SyscallCBInvoc *hook, 
+										   syscall_type call,
+										   int fd, int *errNo );
+extern syscallcb_result callReadHook( int fd, int *errNo );
+extern syscallcb_result callWriteHook( int fd, int *errNo );
+extern syscallcb_result echoSyscallCB( syscall_type call,
+									   int fd, int *errNo,
+									   void *data );
+
+/* raid.c */
+#if defined( DISK_REPL )
+extern syscallcb_result watchDiskDies( syscall_type call,
+									   int fd, int *errNo,
+									   void *data );
+extern int offlineSwapDir( int index );
+extern int onlineSwapDir( int index );
+syscallcb_result simulateCrash( syscall_type call, 
+								int fd, int *errNo, void *data );
+int findFirstOnlineSD();
+int raidInit();
+void raidInitListener();
+/* DISK_REPL */
+#endif
+
 
 /*
  * comm_select.c
@@ -1229,6 +1259,8 @@
 extern int commCioLoop();
 extern int cioCatchLostIO();
 extern int initCommCio();
+extern void clearLostIOBitmap( int fd );
+extern void setLostIOBitmap( int fd );
 #endif
 extern int checkAsyncFlag( int fd );
 /*
Index: squid/src/pump.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/pump.c,v
retrieving revision 1.4.14.1.4.1
retrieving revision 1.4.14.1.4.1.2.1
diff -u -r1.4.14.1.4.1 -r1.4.14.1.4.1.2.1
--- squid/src/pump.c	17 Dec 2000 14:09:08 -0000	1.4.14.1.4.1
+++ squid/src/pump.c	17 Dec 2000 14:36:24 -0000	1.4.14.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: pump.c,v 1.4.14.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: pump.c,v 1.4.14.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 61    PUMP handler
  * AUTHOR: Kostas Anagnostakis
@@ -230,17 +230,15 @@
     int len = 0;
     errno = 0;
     statCounter.syscalls.sock.reads++;
-    len = read(fd, buf, bytes_to_read);
+    len = comm_read_wrapper(fd, buf, bytes_to_read);
     fd_bytes(fd, len, FD_READ);
     debug(61, 5) ("pumpReadFromClient: FD %d: len %d.\n", fd, len);
     if (len > 0) {
 	(void) 0;		/* continue */
-	CLEAR_CAN_READ_IF_EMPTY( bytes_to_read, len, fd );
     } else if (len < 0) {
 	debug(61, 2) ("pumpReadFromClient: FD %d: read failure: %s.\n",
 	    fd, xstrerror());
 	if (ignoreErrno(errno)) {
-	  CLEAR_CAN_READ( fd );
 	    debug(61, 5) ("pumpReadFromClient: FD %d: len %d and ignore!\n",
 		fd, len);
 	    commSetSelect(fd,
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/raid.c	Wed Feb 14 00:47:22 2007
@@ -0,0 +1,645 @@
+
+/*
+ * $Id: raid.c,v 1.1.2.1 2000/12/17 14:36:24 hno Exp $
+ *
+ * DEBUG: section 91     RAID support
+ * AUTHOR: Nikita Danilov <NikitaDanilov@Yahoo.COM>
+ * COPYRIGHT: This file is Copyright 2000 by Hans Reiser <Hans@Reiser.TO>
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by the
+ *  Regents of the University of California.  Please see the COPYRIGHT
+ *  file for full details.  Squid incorporates software developed
+ *  and/or copyrighted by other sources such as this file.  Please see
+ *  the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * */
+
+/*
+
+  This is main part of squid sub-system through which one can
+  dynamically switch squid cache_dirs offline and back online.
+
+  The main and initial reason for this was support for the disk
+  hot-replacement (when supported by hardware), but this can be used
+  for any purpose.
+
+  OUTLINE:
+
+  (*) kernel or user notifies squid about cache directory state
+  change. This is done through signals. Such signal should came with
+  siginfo structure. Hence you cannot use kill. Simple utility ss (for
+  Send-signal, not Schutzstaffel) is provided for this purpose.
+
+  (*) from the value in siginfo struct, squid extracts number of
+  cache_dir (index in Config.cacheSwap.swapDirs) and direction of
+  status change (00 --- goes offline, 01 --- goes online).
+
+  (*) squid marks cache_dir offline, updates total number of online
+  caches and calls back-end specific callback (through function
+  pointer in _SwapDir.offline, _SwapDir.online). If all caches are
+  offline, squid dies miserably (this is not logically necessary: we
+  can in stead just serve all requests from network, but this will
+  require changes all over code, I guess).
+
+  (*) squid executes command, specified by new config option:
+  offline_notify_cmd or online_notify_cmd. This command is supplied
+  with 3 arguments: path of the cache_dir in question, its index and
+  device where it's mounted (as indicated by watch_failure
+  option). Reasonable command may send message to the operator and
+  umount drive.
+
+  (*) from this moment on, store dir selection functions
+  (storeDirSelectSwapDirLeastLoad() and
+  storeDirSelectSwapDirRoundRobin()) will skip offline cache and
+  Butterfly reselection will try to re-hash requests to different
+  directories.
+
+  HOT-REPLACEMENT:
+
+  This is mainly in raidInitListener(). It instructs kernel (by
+  issuing special ioctls) no notify Squid when SCSI drive dies.
+
+
+  There is also old errno-based error detection, described below. Per
+  dir errnos and thresholds were added.
+
+  ---------------- old outdated description ---------------------
+
+  Here is general outline:
+  [posted as <14822.56117.262849.688030@beta.namesys.com> in 
+   squidng@cacheboy.net]
+
+  * In struct _fde I have added backpointer to the swapdir this file
+  descriptor serves. This is currently only maintained for the butterfly
+  fds but this ought to be improved.
+
+  * All calls to read/write were replaced to the calls to
+  comm_(read|write)_wrapper (This is logical thing to do anyway,
+  right?).
+
+  * Wrappers call watchDiskDies(). These calls are done through some
+  callback mechanism, so anyone can dynamically add function(s) to be
+  called on each read or write.
+
+  * watchDiskDies() checks for some magic errno (I use ENXIO, but
+  ENODEV, ENOTSUP or ENOMEDIUM are possible candidates too.).
+
+  * If there were more than ERRORS_THRESHOLD errnos watchDiskDies()
+  declares drive dead (offline) and calls offlineSwapDir() taking swap
+  dir number from the fde.
+
+  * offlineSwapDir() just updates flags in swapdir. These flags are
+  taken into account by storeBfSelectSwapDir(), that chooses only
+  online dirs. Other backends should be updated too.
+
+  There are obvious deficiencies in this prototype: only global
+  counter of errnos is kept. Thus if there are two drives dying at the
+  same time we cannot distinguish their errnos. I am not sure this is
+  at all important. Also, there are insufficient provisions for
+  adequate debugging yet. Some way should be devised to force
+  reads/writes from certain device to return given errno. This can be
+  put into kernel (as special block device driver and I have seen
+  something about this on fsdevel list, or as patch for reiserfs) or
+  we can do this in the squid. This is simpler but we have then keep
+  track which device fd is attached to. I think this can be done as
+  special read/write-callback fired before watchDiskDies() and setting
+  errno. But how to control it? Signals are over-used already.  */
+
+/* TODO:
+
+   \begin{itemize}
+   \item proper debugging (in progress)
+   \item store information about online/offline state. Think squid 
+         crashes when some disks are offline and restarts. We would
+		 like to start without going through errnos for these disks 
+		 again
+   \item per drive errno counters (and settings: DISK_DIES_ERRNO and 
+         ERRORS_THRESHOLD)
+   \item install fde.swap_dir in backends other than butterfly
+   \item update cache_dir selection functions other than storeBfSelectSwapDir
+   \end{itemize}
+*/
+
+#include "squid.h"
+
+#if defined( DISK_REPL )
+
+#include <signal.h>
+
+#include <sys/types.h>
+#define CONFIG_SCSI_HOT_REPLACE
+#include <scsi/scsi.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <scsi/sg.h>
+
+#define DEBUG( format, args... )					\
+         debug( 91, 9 )( CURRENT_FUNCTION_NAME " (%s:%i): " format "\n",	\
+			__FILE__, __LINE__ , ##args )
+
+#define TRACE    DEBUG( "" )
+#define LOGERROR debug( 91, 3 )
+
+typedef enum { goOffline = 0, goOnline = 1, wrongEvent } CtrlEvent;
+
+static sig_atomic_t hasCtrlEvent = 0;
+static CtrlEvent ctrlEvent   = wrongEvent;
+static int       ctrlSwapDir = -1;
+
+void raidCtrl( int sigNum, siginfo_t *info, void *data );
+static char *getDeviceByCache( char *path );
+EVH doRaidCtrl;
+static void registerRaidCtrlEvent();
+
+static void notifyAboutOffline( SwapDir *dir );
+static void notifyAboutOnline( SwapDir *dir );
+static void notifyAboutStateSwitch( char *cmd, SwapDir *dir );
+
+int raidInit()
+{
+  struct sigaction act;
+
+  act.sa_sigaction = raidCtrl;
+  act.sa_flags     = SA_SIGINFO;
+  if( sigaction( RAID_CTRL_SIG, &act, NULL ) == 0 )
+    {
+      registerRaidCtrlEvent();
+    }
+  else
+    {
+      DEBUG( "sigaction failed: %s", xstrerror() );
+    }
+  addReadHook( watchDiskDies, NULL );
+  addWriteHook( watchDiskDies, NULL );
+  return 1;
+}
+
+void raidInitListener()
+{
+  wordlist *watcher;
+
+  for( watcher = Config.disk_repl_watch_list ;
+       watcher != NULL ; watcher = watcher -> next )
+    {
+      if( ( watcher -> key != NULL ) && 
+          ( watcher -> next != NULL ) && ( watcher -> next -> key != NULL ) )
+        {
+          int fd;
+
+          fd = open( watcher -> key, O_RDONLY );
+          if( fd != -1 )
+            {
+              struct SCSI_hot_replace repl;
+              char *path;
+              int   swap;
+          
+              repl.offline_code = ( int ) watcher;
+              repl.signo = RAID_CTRL_SIG;
+              repl.pid = getpid();
+              repl.sigval = -1;
+
+              path = watcher -> next -> key;
+              FOREACHSDINDEX( swap )
+                {
+                  if( !strcmp( INDEXSD( swap ) -> path, path ) )
+                    {
+                      if( swap > 0xff )
+                        {
+                          LOGERROR
+                            ( "raidInitListener: sorry, index too big: %i\n",
+                              swap );
+                        }
+                      else
+                        {
+                          repl.sigval = ( goOffline << 8 ) | swap;
+                        }
+                      break;
+                    }
+                }
+
+              if( repl.sigval != -1 )
+                {
+                  if( ioctl( fd, SCSI_IOCTL_ADD_FAILURE_NOTIFY, &repl ) != -1 )
+                    {
+                      DEBUG( "adding watcher: %s -> %s (%i)",
+                             watcher -> key, path, swap );
+                    }
+                  else
+                    {
+                      LOGERROR( "raidInitListener: ioctl: %s\n", xstrerror() );
+                    }
+                }
+              else
+                {
+                  LOGERROR
+                    ( "raidInitListener: cannot find swap_dir: %s\n", path );
+                }
+              close( fd );
+            }
+          else
+            {
+              LOGERROR( "raidInitListener: error opening %s: %s\n",
+                              watcher -> key, xstrerror() );
+            }
+        }
+      else
+        {
+          LOGERROR
+            ( "raidInitListener: wrong syntax of `watch_failure' field\n" );
+          break;
+        }
+      watcher = watcher -> next;
+    }
+}
+
+syscallcb_result watchDiskDies( syscall_type call,
+                                int fd, int *errNo,
+                                void *data )
+{
+  /*   DEBUG( "swap_dir: %i errno: %i (%i)", fd_table[ fd ].swap_dir, *errNo, errno ); */
+  if( fd_table[ fd ].swap_dir != -1 )
+    {
+      SwapDir *dir;
+
+      assert( ( 0 <= fd_table[ fd ].swap_dir ) &&
+              ( fd_table[ fd ].swap_dir < Config.cacheSwap.n_configured ) );
+      dir = INDEXSD( fd_table[ fd ].swap_dir );
+      if( ( *errNo != 0 ) &&
+          ( *errNo == dir -> raid.offline_errno ) &&
+          ( ++( dir -> raid.errnos_detected ) >= dir -> raid.errno_threshold ) )
+        {
+          debug( 91, 1 )( "Cache_dir %i is dying...\n", dir -> index );
+          offlineSwapDir( dir -> index );
+          dir -> raid.errnos_detected = 0;
+        }
+    }
+#if 0
+  else if( *errNo == DISK_DIES_ERRNO )
+    {
+      /* If a system drive (not a cache dir drive) dies, we are toast,
+         no hope of continuing without interrruption, so print an
+         informative message and bail out. -hans */
+      debug( 91, 1 )( "System drive died. Finis.\n" );
+      shut_down( 0 );
+      return SYSCALLCB_ABORT;
+    }
+#endif
+  return SYSCALLCB_CONTINUE;
+}
+
+int offlineSwapDir( int index )
+{
+  if( index < 0 )
+    {
+      LOGERROR( "offlineSwapDir: %i < 0\n", index );
+      return 0;
+    }
+  else if( index >= Config.cacheSwap.n_configured )
+    {
+      LOGERROR( "offlineSwapDir: %i >= %i\n", 
+                index, Config.cacheSwap.n_configured );
+      return 0;
+    }
+
+  TRACE;
+  if( INDEXSD( index ) -> flags.offline )
+    {
+      DEBUG( "%i already offline", index );
+      return 0;
+    }
+  ++Config.cacheSwap.n_offline;
+  if( Config.cacheSwap.n_offline >= Config.cacheSwap.n_configured )
+    {
+      debug( 91, 1 )( "Last drive dies. Fare thee well.\n" );
+      /* just to maintain invariant that n_offline is the number of
+         swapdirs with (offline == 1) */
+      --Config.cacheSwap.n_offline;
+      shut_down( 0 );
+    }
+  else
+    {
+      SwapDir *dir;
+
+      dir = INDEXSD( index );
+      dir -> flags.offline = 1;
+      dir -> log.close( dir );
+      chdir( "/" ); /* to get out of umount's way */
+      if( dir -> offline != NULL )
+        {
+          dir -> offline( dir );
+        }
+      debug( 91, 1 )( "Cache_dir %i turned offline...\n", index );
+      notifyAboutOffline( dir );
+    }
+  return 1;
+}
+
+int onlineSwapDir( int index )
+{
+  SwapDir *dir;
+
+  if( index < 0 )
+    {
+      LOGERROR( "onlineSwapDir: %i < 0\n", index );
+      return 0;
+    }
+  else if( index >= Config.cacheSwap.n_configured )
+    {
+      LOGERROR( "onlineSwapDir: %i >= %i\n", 
+                index, Config.cacheSwap.n_configured );
+      return 0;
+    }
+
+
+  DEBUG( "index: %i", index );
+  dir = INDEXSD( index );
+  if( !dir -> flags.offline )
+    {
+      DEBUG( "%i already online", index );
+      return 0;
+    }
+  if( ( dir -> online != NULL ) && dir -> online( dir ) )
+    {
+      char *device;
+
+      debug( 91, 1 )( "Cache_dir %i turned online...\n", index );
+      dir -> log.open( dir );
+      dir -> flags.offline = 0;
+      dir -> raid.errnos_detected = 0;
+      --Config.cacheSwap.n_offline;
+      notifyAboutOnline( dir );
+      device = getDeviceByCache( dir -> path );
+      if( device != NULL )
+        {
+          int fd;
+
+          fd = open( device, O_RDONLY );
+          if( fd != -1 )
+            {
+              struct SCSI_hot_replace repl;
+          
+              repl.offline_code = ( int ) device;
+              repl.signo = RAID_CTRL_SIG;
+              repl.pid = getpid();
+              repl.sigval = -1;
+              repl.sigval = ( goOffline << 8 ) | index;
+
+              if( ioctl( fd, SCSI_IOCTL_ADD_FAILURE_NOTIFY, &repl ) != -1 )
+                {
+                  DEBUG( "re-adding watcher: %s -> %s (%i)",
+                         device, dir -> path, index );
+                }
+              else
+                {
+                  LOGERROR( "raidInitListener: ioctl: %s\n", xstrerror() );
+                }
+              close( fd );
+            }
+          else
+            {
+              LOGERROR( "Cannot re-establish fault notification at %s:%s (%s)",
+                        dir -> path, device, xstrerror() );
+            }
+        }
+    }
+  else
+    {
+      debug( 91, 1 )( "Cannot turn online cache_dir %i...\n", index );
+    }
+  return 1;
+}
+
+syscallcb_result simulateCrash( syscall_type call, 
+                                int fd, int *errNo, void *data )
+{
+  SimulateCrashData *crash = ( SimulateCrashData * ) data;
+
+  /*   DEBUG( "fd: %i swap_dir: %i time: %li fireTime: %li", */
+  /* 	 fd, fd_table[ fd ].swap_dir, squid_curtime, crash -> crashTime ); */
+  if( ( fd_table[ fd ].swap_dir == crash -> swapDirNo ) &&
+      ( squid_curtime >= crash -> crashTime ) )
+    {
+      static int sparseLogging = 0;
+
+      *errNo = INDEXSD( crash -> swapDirNo ) -> raid.offline_errno;
+      ++sparseLogging;
+      if( !( sparseLogging & ( sparseLogging - 1 ) ) )
+        {
+          DEBUG( "And therefore I claim swap_dir %i have to be ruined (%i:%i)", 
+                 crash -> swapDirNo, sparseLogging, *errNo );
+        }
+    }
+  return SYSCALLCB_CONTINUE;
+}
+
+int findFirstOnlineSD()
+{
+  int i;
+
+  assert( Config.cacheSwap.n_configured > Config.cacheSwap.n_offline );
+
+  FOREACHSDINDEX( i )
+    {
+      if( !( INDEXSD( i ) -> flags.offline ) )
+        {
+          return i;
+        }
+    }
+  assert( 0 );
+  return 0;
+}
+
+void raidCtrl( int sigNum, siginfo_t *info, void *data )
+{
+  /* don't risk asserts from signal handler, Just for documentation. */
+  assert( 1 || ( sigNum == RAID_CTRL_SIG ) );
+  assert( 1 || ( info != NULL ) );
+  assert( 1 || ( info -> si_code == SI_QUEUE ) );
+
+  /* don't bother to queue events. */
+  if( hasCtrlEvent == 0 )
+    {
+      ++hasCtrlEvent;
+      ctrlEvent = info -> si_value.sival_int >> 8;
+      ctrlSwapDir = info -> si_value.sival_int & 0xff;
+    }
+}
+
+void doRaidCtrl( void *data )
+{
+  if( hasCtrlEvent )
+    {
+      DEBUG( "event: %i dir: %i", ctrlEvent, ctrlSwapDir );
+      switch( ctrlEvent )
+        {
+        case goOffline:
+          DEBUG( "offlineSwapDir" );
+          offlineSwapDir( ctrlSwapDir );
+          break;
+        case goOnline:
+          DEBUG( "onlineSwapDir" );
+          onlineSwapDir( ctrlSwapDir );
+          break;
+        default:
+          DEBUG( "Wrong RAID control request" );
+          break;
+        }
+      hasCtrlEvent = 0;
+    }
+  registerRaidCtrlEvent();
+}
+
+static void registerRaidCtrlEvent()
+{
+  eventAdd( "RAID control", doRaidCtrl, NULL, 1, 0 );
+}
+
+static void notifyAboutOffline( SwapDir *dir )
+{
+  assert( dir != NULL );
+
+  if( Config.offline_notify_cmd != NULL )
+    {
+      notifyAboutStateSwitch( Config.offline_notify_cmd, dir );
+    }
+}
+
+static void notifyAboutOnline( SwapDir *dir )
+{
+  assert( dir != NULL );
+
+  if( Config.online_notify_cmd != NULL )
+    {
+      notifyAboutStateSwitch( Config.online_notify_cmd, dir );
+    }
+}
+
+static char *getDeviceByCache( char *path )
+{
+  wordlist *watcher;
+
+  assert( path != NULL );
+
+  for( watcher = Config.disk_repl_watch_list ;  watcher != NULL ; 
+       watcher = watcher -> next )
+    {
+      if( ( watcher -> key != NULL ) && 
+          ( watcher -> next != NULL ) && ( watcher -> next -> key != NULL ) )
+        {
+          if( !strcmp( watcher -> next -> key, path ) )
+            {
+              return watcher -> key;
+            }
+        }
+      watcher = watcher -> next;
+    }
+  return NULL;
+}
+
+static void notifyAboutStateSwitch( char *cmd, SwapDir *dir )
+{
+  int len;
+  char *cmd_buf;
+  char *dev;
+  int ret;
+  
+  assert( cmd != NULL );
+  assert( dir != NULL );
+
+  dev = getDeviceByCache( dir -> path );
+  dev = ( dev == NULL ) ? "<unknown-device>" : dev;
+
+  len = strlen( cmd ) + strlen( dir -> path ) + 20 + strlen( dev );
+  cmd_buf = xmalloc( len );
+  
+  snprintf( cmd_buf, len, "%s %s %i %s", cmd, dir -> path, dir -> index, dev );
+  DEBUG( "about to execute `%s'", cmd_buf );
+  /* XXX system is insecure. Will replace to 
+     fork()/dup()/close()/exec() later. 
+     Famous last words. */  
+  if( ( ret = system( cmd_buf ) ) != 0 )
+    {
+      LOGERROR( "notifyAboutStateSwitch: cannot execute `%s': %i: %s", 
+                cmd_buf, ret, xstrerror() );
+    }
+  xfree( cmd_buf );
+}
+
+/* DISK_REPL */
+#endif
+
+/*
+ * $Log: raid.c,v $
+ * Revision 1.1.2.1  2000/12/17 14:36:24  hno
+ * Imported raid from squidng
+ *
+ * Revision 1.1.2.11  2000/12/15 18:48:21  nikitadanilov
+ * Re-install fault notification when cache goes back online. Don't monitor errnos beyond cache_dirs.
+ *
+ * Revision 1.1.2.10  2000/12/15 14:45:23  nikitadanilov
+ * Bug fixes in ciociosan: clear can_* flags on file close; corrected work with fd-bitmap etc.
+ *
+ * Revision 1.1.2.9  2000/12/07 16:47:36  nikitadanilov
+ * new code commented
+ *
+ * Revision 1.1.2.8  2000/11/24 20:41:48  nikitadanilov
+ * Execute command specified in squid.conf when drive goes offline
+ *
+ * Revision 1.1.2.7  2000/11/22 14:42:59  nikitadanilov
+ * generally improved
+ *
+ * Revision 1.1.2.6  2000/11/08 11:49:07  nikitadanilov
+ * Dynamic switching cache_dirs offline and back through signals
+ *
+ * Revision 1.1.2.5  2000/10/19 09:57:12  nikitadanilov
+ * Added manual online/offline switching through signals (Signals with siginfo, e.g., sent by sigqueue.).
+ *
+ * Revision 1.1.2.4  2000/10/17 19:28:47  nikitadanilov
+ * Switched to per-swapdir errno settings and counters. Fallback findFirstOnlineSD() added: used by storeBfSelectSwapDir()
+ *
+ * Revision 1.1.2.3  2000/10/17 12:13:42  nikitadanilov
+ * Comments added. Check for last drive death corrected.
+ *
+ * Revision 1.1.2.2  2000/10/13 15:43:18  nikitadanilov
+ * RAID disk replcement changes: added per-fs callbacks called on on/of-line switch; Crash simulation added; Code commented. It started to work (with crash simulation). Alpha release state reached.
+ *
+ */
+
+/*
+ * Make Linus happy.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
+
Index: squid/src/squid.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/squid.h,v
retrieving revision 1.3.16.1.2.1.2.1
retrieving revision 1.3.16.1.2.1.2.1.2.1
diff -u -r1.3.16.1.2.1.2.1 -r1.3.16.1.2.1.2.1.2.1
--- squid/src/squid.h	17 Dec 2000 14:09:08 -0000	1.3.16.1.2.1.2.1
+++ squid/src/squid.h	17 Dec 2000 14:36:24 -0000	1.3.16.1.2.1.2.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: squid.h,v 1.3.16.1.2.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: squid.h,v 1.3.16.1.2.1.2.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -89,7 +89,13 @@
 #define assert(EX)  ((EX)?((void)0):xassert("EX", __FILE__, __LINE__))
 #endif
 
-#define LINGERING_CLOSE 1
+#define LINGERING_CLOSE 0
+
+#if defined( __GNUC__ )
+#define CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__
+#else
+#define CURRENT_FUNCTION_NAME ""
+#endif
 
 /* 
    SIGIO-driven IO hack. Don't look here.
@@ -98,11 +104,6 @@
 /* #define TCP_ASYNC */
 #if defined( TCP_ASYNC )
 
-/* It's Butterfly's real name */
-#define SIGCIOCIOSAN ( SIGRTMIN + 8 )
-
-#define SIGINFO_PER_CALL 128
-
 /* this should be done before #include <fcntl.h>,
    because we need F_SETSIG. */
 #define _GNU_SOURCE
@@ -111,63 +112,11 @@
 #include <signal.h>
 #endif
 
-#if defined( __GNUC__ )
-#define CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__
-#else
-#define CURRENT_FUNCTION_NAME __FUNC__
-#endif
-
-#define CLEAR_CAN_READ_INTERNAL( fd )									\
-	  debug( 90, 9 )( CURRENT_FUNCTION_NAME ": cleared can_read.\n" );	\
-	  fd_table[ fd ].flags.can_read = 0
-
-#define CLEAR_CAN_WRITE_INTERNAL( fd )									\
-	  debug( 90, 9 )( CURRENT_FUNCTION_NAME ": cleared can_write.\n" );	\
-	  fd_table[ fd ].flags.can_write = 0
-
-#define CLEAR_CAN_READ( fd ) do {							\
-      CLEAR_CAN_READ_INTERNAL( fd );						\
-      ++statCounter.syscalls.async.tail_reads; } while( 0 )
-
-#define CLEAR_CAN_WRITE( fd ) do {								\
-      CLEAR_CAN_WRITE_INTERNAL( fd );							\
-      ++statCounter.syscalls.async.tail_writes; } while( 0 )
-
-#define CLEAR_CAN_READ_IF_EMPTY( requestedSize, actuallyRead, fd )		\
-  do																	\
-    {																	\
-	  if( ( actuallyRead > 0 ) && ( actuallyRead < requestedSize ) )	\
-		{																\
-		  /* CLEAR_CAN_READ_INTERNAL( fd ); */							\
-          ++statCounter.syscalls.async.drain_reads;						\
-		}																\
-	}																	\
-  while( 0 )
-
-#define CLEAR_CAN_WRITE_IF_FULL( requestedSize, actuallyWritten, fd )		\
-  do																		\
-    {																		\
-	  if( ( actuallyWritten > 0 ) && ( actuallyWritten < requestedSize ) )	\
-		{																	\
-		  /* CLEAR_CAN_WRITE_INTERNAL( fd ); */								\
-          ++statCounter.syscalls.async.drain_writes;						\
-		}																	\
-	}																		\
-  while( 0 )
-
-#else
-
-#define CLEAR_CAN_READ( fd )  do {} while( 0 )
-#define CLEAR_CAN_WRITE( fd ) do {} while( 0 )
-#define CLEAR_CAN_READ_IF_EMPTY( requestedSize, actuallyRead, fd ) \
-  do {} while( 0 )
-#define CLEAR_CAN_WRITE_IF_FULL( requestedSize, actuallyWritten, fd )	\
-  do {} while( 0 )
-
 /* TCP_ASYNC */
 #endif
 
 
+
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
Index: squid/src/ssl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/ssl.c,v
retrieving revision 1.3.16.1.4.1
retrieving revision 1.3.16.1.4.1.2.1
diff -u -r1.3.16.1.4.1 -r1.3.16.1.4.1.2.1
--- squid/src/ssl.c	17 Dec 2000 14:09:08 -0000	1.3.16.1.4.1
+++ squid/src/ssl.c	17 Dec 2000 14:36:24 -0000	1.3.16.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ssl.c,v 1.3.16.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: ssl.c,v 1.3.16.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 26    Secure Sockets Layer Proxy
  * AUTHOR: Duane Wessels
@@ -200,7 +200,7 @@
     read_sz = delayBytesWanted(sslState->delay_id, 1, read_sz);
 #endif
     statCounter.syscalls.sock.reads++;
-    len = read(fd, sslState->server.buf + sslState->server.len, read_sz);
+    len = comm_read_wrapper(fd, sslState->server.buf + sslState->server.len, read_sz);
     debug(26, 3) ("sslReadServer: FD %d, read   %d bytes\n", fd, len);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
@@ -210,7 +210,6 @@
 	kb_incr(&statCounter.server.all.kbytes_in, len);
 	kb_incr(&statCounter.server.other.kbytes_in, len);
 	sslState->server.len += len;
-	CLEAR_CAN_READ_IF_EMPTY( read_sz, len, fd );
     }
     cbdataLock(sslState);
     if (len < 0) {
@@ -219,7 +218,6 @@
 	if (!ignoreErrno(errno))
 	    comm_close(fd);
     } else {
-      CLEAR_CAN_READ( fd );
       if (len == 0) {
 	comm_close(sslState->server.fd);
       }
@@ -240,7 +238,7 @@
 	fd, SQUID_TCP_SO_RCVBUF - sslState->client.len,
 	sslState->client.len);
     statCounter.syscalls.sock.reads++;
-    len = read(fd,
+    len = comm_read_wrapper(fd,
 	sslState->client.buf + sslState->client.len,
 	SQUID_TCP_SO_RCVBUF - sslState->client.len);
     debug(26, 3) ("sslReadClient: FD %d, read   %d bytes\n", fd, len);
@@ -248,8 +246,6 @@
 	fd_bytes(fd, len, FD_READ);
 	kb_incr(&statCounter.client_http.kbytes_in, len);
 	sslState->client.len += len;
-	CLEAR_CAN_READ_IF_EMPTY( SQUID_TCP_SO_RCVBUF - sslState->client.len,
-				 len, fd );
     }
     cbdataLock(sslState);
     if (len < 0) {
@@ -260,7 +256,6 @@
 #endif
 	if (ignoreErrno(errno))
 	  {
-	    CLEAR_CAN_READ( fd );
 	    level = 3;
 	  }
 	debug(50, level) ("sslReadClient: FD %d: read failure: %s\n",
@@ -285,7 +280,7 @@
     debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n",
 	fd, sslState->client.len);
     statCounter.syscalls.sock.writes++;
-    len = write(fd,
+    len = comm_write_wrapper(fd,
 	sslState->client.buf,
 	sslState->client.len);
     debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd, len);
@@ -294,7 +289,6 @@
 	kb_incr(&statCounter.server.all.kbytes_out, len);
 	kb_incr(&statCounter.server.other.kbytes_out, len);
 	assert(len <= sslState->client.len);
-	CLEAR_CAN_WRITE_IF_FULL( sslState->client.len, len, fd );
 	sslState->client.len -= len;
 	if (sslState->client.len > 0) {
 	    /* we didn't write the whole thing */
@@ -309,10 +303,6 @@
 	    ("sslWriteServer: FD %d: write failure: %s.\n", fd, xstrerror());
 	if (!ignoreErrno(errno))
 	    comm_close(fd);
-	else
-	  {
-	    CLEAR_CAN_WRITE( fd );
-	  }
     }
     if (cbdataValid(sslState))
 	sslSetSelect(sslState);
@@ -329,7 +319,7 @@
     debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n",
 	fd, sslState->server.len);
     statCounter.syscalls.sock.writes++;
-    len = write(fd,
+    len = comm_write_wrapper(fd,
 	sslState->server.buf,
 	sslState->server.len);
     debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd, len);
@@ -337,7 +327,6 @@
 	fd_bytes(fd, len, FD_WRITE);
 	kb_incr(&statCounter.client_http.kbytes_out, len);
 	assert(len <= sslState->server.len);
-	CLEAR_CAN_WRITE_IF_FULL( sslState->server.len, len, fd );
 	sslState->server.len -= len;
 	/* increment total object size */
 	if (sslState->size_ptr)
@@ -355,10 +344,6 @@
 	    ("sslWriteClient: FD %d: write failure: %s.\n", fd, xstrerror());
 	if (!ignoreErrno(errno))
 	    comm_close(fd);
-	else
-	  {
-	    CLEAR_CAN_WRITE( fd );
-	  }
     }
     if (cbdataValid(sslState))
 	sslSetSelect(sslState);
Index: squid/src/store.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store.c,v
retrieving revision 1.6.4.1.2.1
retrieving revision 1.6.4.1.2.1.4.1
diff -u -r1.6.4.1.2.1 -r1.6.4.1.2.1.4.1
--- squid/src/store.c	17 Dec 2000 13:55:39 -0000	1.6.4.1.2.1
+++ squid/src/store.c	17 Dec 2000 14:36:24 -0000	1.6.4.1.2.1.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store.c,v 1.6.4.1.2.1 2000/12/17 13:55:39 hno Exp $
+ * $Id: store.c,v 1.6.4.1.2.1.4.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 20    Storage Manager
  * AUTHOR: Harvest Derived
@@ -780,7 +780,7 @@
     static time_t last_warn_time = 0;
 
     /* walk each fs */
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    FOREACHSDINDEX( i ) {
 	/* call the maintain function .. */
 	SD = INDEXSD(i);
 	/* XXX FixMe: This should be done "in parallell" on the different
Index: squid/src/store_dir.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_dir.c,v
retrieving revision 1.4.18.1
retrieving revision 1.4.18.1.4.1
diff -u -r1.4.18.1 -r1.4.18.1.4.1
--- squid/src/store_dir.c	17 Dec 2000 13:55:39 -0000	1.4.18.1
+++ squid/src/store_dir.c	17 Dec 2000 14:36:24 -0000	1.4.18.1.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir.c,v 1.4.18.1 2000/12/17 13:55:39 hno Exp $
+ * $Id: store_dir.c,v 1.4.18.1.4.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
@@ -48,10 +48,8 @@
 void
 storeDirInit(void)
 {
-    int i;
     SwapDir *sd;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-	sd = &Config.cacheSwap.swapDirs[i];
+    FOREACHSD( sd ) {
 	sd->init(sd);
     }
     if (0 == strcasecmp(Config.store_dir_select_algorithm, "round-robin")) {
@@ -66,14 +64,14 @@
 void
 storeCreateSwapDirectories(void)
 {
-    int i;
     SwapDir *sd;
     pid_t pid;
     int status;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    FOREACHSD( sd ) {
+	if( sd -> flags.offline )
+	    continue;
 	if (fork())
 	    continue;
-	sd = &Config.cacheSwap.swapDirs[i];
 	sd->newfs(sd);
 	exit(0);
     }
@@ -136,7 +134,11 @@
 	if (++dirn >= Config.cacheSwap.n_configured)
 	    dirn = 0;
 	sd = &Config.cacheSwap.swapDirs[dirn];
-	if (sd->cur_size > sd->max_size)
+	if ((sd->cur_size > sd->max_size) 
+#if defined( DISK_REPL )
+	    || sd->flags.offline
+#endif
+	    )
 	    continue;
 	break;
     }
@@ -146,9 +148,15 @@
        act together like hash buckets.  They use a hash based on URL
        to select which dir the object should go to -- this allows to
        have only one open() in storeTreeGet(). */
+    debug( 47, 9 )( "storeDirSelectSwapDirRoundRobin: fdirn: %i\n", dirn );
+    /* may be we should not store re-selected cache_dir index back into
+       dirn? Otherwise, if we have mixture of storetree and usual 
+       caches, round-robin will somewhat stuck into storetree,
+       giving unfair amount of load to it? --nikita */
     if (sd->reselectdir)
 	dirn = sd->reselectdir(e)->index;
 #endif
+    debug( 47, 9 )( "storeDirSelectSwapDirRoundRobin: dirn: %i\n", dirn );
     return dirn;
 }
 
@@ -184,9 +192,13 @@
     /* Initial defaults */
     least_size = Config.cacheSwap.swapDirs[0].cur_size;
     least_objsize = Config.cacheSwap.swapDirs[0].max_objsize;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    FOREACHSDINDEX( i ) {
 	SD = &Config.cacheSwap.swapDirs[i];
 	SD->flags.selected = 0;
+#if defined( DISK_REPL )
+	if (SD->flags.offline)
+	    continue;
+#endif
 	if (SD->flags.read_only)
 	    continue;
 	/* Valid for object size check */
@@ -212,6 +224,7 @@
     if (dirn >= 0)
 	Config.cacheSwap.swapDirs[dirn].flags.selected = 1;
 
+    debug( 47, 9 )( "storeDirSelectSwapDirLeastLoad: dirn: %i\n", dirn );
     return dirn;
 }
 
@@ -251,7 +264,10 @@
 	e->swap_dirn,
 	e->swap_filen);
     sd = &Config.cacheSwap.swapDirs[e->swap_dirn];
-    sd->log.write(sd, e, op);
+    if( !sd -> flags.offline )
+      {
+	sd->log.write(sd, e, op);
+      }
 }
 
 void
@@ -284,7 +300,7 @@
 	percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize));
 
     /* Now go through each swapdir, calling its statfs routine */
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    FOREACHSDINDEX( i ) {
 	storeAppendPrintf(sentry, "\n");
 	SD = &(Config.cacheSwap.swapDirs[i]);
 	storeAppendPrintf(sentry, "Store Directory #%d (%s): %s\n", i, SD->type,
@@ -297,10 +313,8 @@
 storeDirConfigure(void)
 {
     SwapDir *SD;
-    int i;
     Config.Swap.maxSize = 0;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-	SD = &Config.cacheSwap.swapDirs[i];
+    FOREACHSD( SD ) {
 	Config.Swap.maxSize += SD->max_size;
 	SD->low_size = (int) (((float) SD->max_size *
 		(float) Config.Swap.lowWaterMark) / 100.0);
@@ -322,10 +336,12 @@
 void
 storeDirOpenSwapLogs(void)
 {
-    int dirn;
     SwapDir *sd;
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	sd = &Config.cacheSwap.swapDirs[dirn];
+    FOREACHSD( sd ) {
+	if( sd -> flags.offline )
+	  {
+	    continue;
+	  }
 	sd->log.open(sd);
     }
 }
@@ -333,10 +349,12 @@
 void
 storeDirCloseSwapLogs(void)
 {
-    int dirn;
     SwapDir *sd;
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	sd = &Config.cacheSwap.swapDirs[dirn];
+    FOREACHSD( sd ) {
+	if( sd -> flags.offline )
+	  {
+	    continue;
+	  }
 	sd->log.close(sd);
     }
 }
@@ -360,7 +378,6 @@
     double dt;
     SwapDir *sd;
     RemovalPolicyWalker **walkers;
-    int dirn;
     int notdone = 1;
     if (store_dirs_rebuilding) {
 	debug(20, 1) ("Not currently OK to rewrite swap log.\n");
@@ -371,8 +388,11 @@
     getCurrentTime();
     start = current_time;
     walkers = xcalloc(Config.cacheSwap.n_configured, sizeof *walkers);
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	sd = &Config.cacheSwap.swapDirs[dirn];
+    FOREACHSD( sd ) {
+	if( sd -> flags.offline )
+	  {
+	    continue;
+	  }
 	if (sd->log.clean.start(sd) < 0) {
 	    debug(20, 1) ("log.clean.start() failed for dir #%d\n", sd->index);
 	    continue;
@@ -380,8 +400,11 @@
     }
     while (notdone) {
 	notdone = 0;
-	for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	    sd = &Config.cacheSwap.swapDirs[dirn];
+	FOREACHSD( sd ) {
+	    if( sd -> flags.offline )
+	      {
+		continue;
+	      }
 	    if (NULL == sd->log.clean.write)
 		continue;
 	    e = sd->log.clean.nextentry(sd);
@@ -408,8 +431,11 @@
 	}
     }
     /* Flush */
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	sd = &Config.cacheSwap.swapDirs[dirn];
+    FOREACHSD( sd ) {
+	if( sd -> flags.offline )
+	  {
+	    continue;
+	  }
 	sd->log.clean.done(sd);
     }
     if (reopen)
@@ -429,11 +455,13 @@
 void
 storeDirSync(void)
 {
-    int i;
     SwapDir *SD;
 
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-	SD = &Config.cacheSwap.swapDirs[i];
+    FOREACHSD( SD ) {
+	if( SD -> flags.offline )
+	  {
+	    continue;
+	  }
 	if (SD->sync != NULL)
 	    SD->sync(SD);
     }
@@ -450,12 +478,16 @@
     static int ndir = 0;
     do {
 	j = 0;
-	for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+	FOREACHSDINDEX( i ) {
 	    if (ndir >= Config.cacheSwap.n_configured)
 		ndir = ndir % Config.cacheSwap.n_configured;
 	    SD = &Config.cacheSwap.swapDirs[ndir++];
 	    if (NULL == SD->callback)
 		continue;
+	    if( SD -> flags.offline )
+	      {
+		continue;
+	      }
 	    j += SD->callback(SD);
 	}
     } while (j > 0);
Index: squid/src/store_io.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_io.c,v
retrieving revision 1.2
retrieving revision 1.2.26.1
diff -u -r1.2 -r1.2.26.1
--- squid/src/store_io.c	21 Oct 2000 15:16:13 -0000	1.2
+++ squid/src/store_io.c	17 Dec 2000 14:36:24 -0000	1.2.26.1
@@ -62,13 +62,18 @@
     void *callback_data)
 {
     SwapDir *SD = &Config.cacheSwap.swapDirs[e->swap_dirn];
-    return SD->obj.open(SD, e, file_callback, callback, callback_data);
+    if( SD -> flags.offline )
+      return NULL;
+    else
+      return SD->obj.open(SD, e, file_callback, callback, callback_data);
 }
 
 void
 storeClose(storeIOState * sio)
 {
     SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
+    if( SD -> flags.offline )
+      return;
     if (sio->flags.closing)
 	return;
     sio->flags.closing = 1;
@@ -79,6 +84,8 @@
 storeRead(storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
 {
     SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
+    if( SD -> flags.offline )
+      return;
     SD->obj.read(SD, sio, buf, size, offset, callback, callback_data);
 }
 
@@ -86,6 +93,8 @@
 storeWrite(storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
 {
     SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
+    if( SD -> flags.offline )
+      return;
     SD->obj.write(SD, sio, buf, size, offset, free_func);
 }
 
@@ -93,6 +102,8 @@
 storeUnlink(StoreEntry * e)
 {
     SwapDir *SD = INDEXSD(e->swap_dirn);
+    if( SD -> flags.offline )
+      return;
     SD->obj.unlink(SD, e);
 }
 
Index: squid/src/store_swapout.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_swapout.c,v
retrieving revision 1.4.14.1.2.1
retrieving revision 1.4.14.1.2.1.4.1
diff -u -r1.4.14.1.2.1 -r1.4.14.1.2.1.4.1
--- squid/src/store_swapout.c	17 Dec 2000 13:55:39 -0000	1.4.14.1.2.1
+++ squid/src/store_swapout.c	17 Dec 2000 14:36:24 -0000	1.4.14.1.2.1.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_swapout.c,v 1.4.14.1.2.1 2000/12/17 13:55:39 hno Exp $
+ * $Id: store_swapout.c,v 1.4.14.1.2.1.4.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 20    Storage Manager Swapout Functions
  * AUTHOR: Duane Wessels
@@ -280,7 +280,7 @@
     assert(e->swap_status == SWAPOUT_WRITING);
     cbdataFree(c);
     if (errflag) {
-	debug(20, 1) ("storeSwapOutFileClosed: dirno %d, swapfile %08X, errflag=%d\n\t%s\n",
+	debug(20, 1) ("storeSwapOutFileClosed: dirno %d, swapfile %08X, errflag=%d: %s\n",
 	    e->swap_dirn, e->swap_filen, errflag, xstrerror());
 	if (errflag == DISK_NO_SPACE_LEFT) {
 	    storeDirDiskFull(e->swap_dirn);
Index: squid/src/structs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/structs.h,v
retrieving revision 1.8.8.1.2.1
retrieving revision 1.8.8.1.2.1.2.1
diff -u -r1.8.8.1.2.1 -r1.8.8.1.2.1.2.1
--- squid/src/structs.h	17 Dec 2000 14:09:08 -0000	1.8.8.1.2.1
+++ squid/src/structs.h	17 Dec 2000 14:36:24 -0000	1.8.8.1.2.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.8.8.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: structs.h,v 1.8.8.1.2.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -463,6 +463,9 @@
 	SwapDir *swapDirs;
 	int n_allocated;
 	int n_configured;
+#if defined( DISK_REPL )
+	int n_offline;
+#endif
     } cacheSwap;
     char *fake_ua;
     struct {
@@ -517,6 +520,11 @@
 	size_t high_memory;
     } warnings;
     char *store_dir_select_algorithm;
+#if defined( DISK_REPL )
+  wordlist *disk_repl_watch_list;
+  char *offline_notify_cmd;
+  char *online_notify_cmd;
+#endif
 };
 
 struct _SquidConfig2 {
@@ -628,6 +636,9 @@
     DEFER *defer_check;		/* check if we should defer read */
     void *defer_data;
     CommWriteStateData *rwstate;	/* State data for comm_write */
+#if defined( DISK_REPL )
+    int swap_dir;
+#endif
 };
 
 struct _fileMap {
@@ -1360,6 +1371,7 @@
     struct {
 	unsigned int selected:1;
 	unsigned int read_only:1;
+	unsigned int offline:1;
     } flags;
     STINIT *init;		/* Initialise the fs */
     STNEWFS *newfs;		/* Create a new fs */
@@ -1374,6 +1386,10 @@
     STUNREFOBJ *unrefobj;	/* Unreference this object */
     STCALLBACK *callback;	/* Handle pending callbacks */
     STSYNC *sync;		/* Sync the directory */
+#if defined( DISK_REPL )
+    STONOFF *offline;		/* Go offline */
+    STONOFF *online;		/* Go online */
+#endif
     /* The following are for storetree */
     STHALFRELEASE *halfrelease;	/* Release StoreEntry but keep disk object */
     STRESELECTDIR *reselectdir; /* Swap dir redirection function */
@@ -1398,6 +1414,14 @@
 	} clean;
 	int writes_since_clean;
     } log;
+#if defined( DISK_REPL )
+  struct 
+  {
+    int offline_errno;
+    int errno_threshold;
+    int errnos_detected;
+  } raid;
+#endif
     void *fsdata;
 };
 
Index: squid/src/typedefs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v
retrieving revision 1.4.10.1.2.1.2.1
retrieving revision 1.4.10.1.2.1.2.1.2.1
diff -u -r1.4.10.1.2.1.2.1 -r1.4.10.1.2.1.2.1.2.1
--- squid/src/typedefs.h	17 Dec 2000 14:09:08 -0000	1.4.10.1.2.1.2.1
+++ squid/src/typedefs.h	17 Dec 2000 14:36:24 -0000	1.4.10.1.2.1.2.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.4.10.1.2.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: typedefs.h,v 1.4.10.1.2.1.2.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -247,6 +247,7 @@
 typedef void STDONE(void);
 typedef int STCALLBACK(SwapDir *);
 typedef void STSYNC(SwapDir *);
+typedef int  STONOFF(SwapDir *);
 typedef void STHALFRELEASE(StoreEntry *);
 typedef SwapDir *STRESELECTDIR(const StoreEntry *);
 
@@ -319,7 +320,22 @@
 /* 
  * comm_cio.h
  */
- typedef int ( *CioCallback ) ( siginfo_t *info );
+typedef int ( *CioCallback ) ( siginfo_t *info );
 
+typedef syscallcb_result ( *SyscallCallBack )( syscall_type call,
+											   int fd, int *errNo,
+											   void *data );
+typedef struct {
+  SyscallCallBack cb;
+  void *data;
+} SyscallCBInvoc;
+
+#if defined( DISK_REPL )
+typedef struct {
+  int    swapDirNo;
+  time_t crashTime;
+} SimulateCrashData;
+/* DISK_REPL */
+#endif
 
 #endif /* _TYPEDEFS_H_ */
Index: squid/src/wais.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/wais.c,v
retrieving revision 1.3.16.1.4.1
retrieving revision 1.3.16.1.4.1.2.1
diff -u -r1.3.16.1.4.1 -r1.3.16.1.4.1.2.1
--- squid/src/wais.c	17 Dec 2000 14:09:08 -0000	1.3.16.1.4.1
+++ squid/src/wais.c	17 Dec 2000 14:36:24 -0000	1.3.16.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: wais.c,v 1.3.16.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: wais.c,v 1.3.16.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 24    WAIS Relay
  * AUTHOR: Harvest Derived
@@ -103,7 +103,7 @@
     read_sz = delayBytesWanted(delay_id, 1, read_sz);
 #endif
     statCounter.syscalls.sock.reads++;
-    len = read(fd, buf, read_sz);
+    len = comm_read_wrapper(fd, buf, read_sz);
     if (len > 0) {
 	fd_bytes(fd, len, FD_READ);
 #if DELAY_POOLS
@@ -119,13 +119,11 @@
 	for (clen = len - 1, bin = 0; clen; bin++)
 	    clen >>= 1;
 	IOStats.Wais.read_hist[bin]++;
-	CLEAR_CAN_READ_IF_EMPTY( read_sz, len, fd );
     }
     if (len < 0) {
 	debug(50, 1) ("waisReadReply: FD %d: read failure: %s.\n",
 	    fd, xstrerror());
 	if (ignoreErrno(errno)) {
-	  CLEAR_CAN_READ( fd );
 	    /* reinstall handlers */
 	    /* XXX This may loop forever */
 	    commSetSelect(fd, COMM_SELECT_READ,
Index: squid/src/whois.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/whois.c,v
retrieving revision 1.3.16.1.4.1
retrieving revision 1.3.16.1.4.1.2.1
diff -u -r1.3.16.1.4.1 -r1.3.16.1.4.1.2.1
--- squid/src/whois.c	17 Dec 2000 14:09:08 -0000	1.3.16.1.4.1
+++ squid/src/whois.c	17 Dec 2000 14:36:24 -0000	1.3.16.1.4.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: whois.c,v 1.3.16.1.4.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: whois.c,v 1.3.16.1.4.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 75    WHOIS protocol
  * AUTHOR: Duane Wessels, Kostas Anagnostakis
@@ -92,7 +92,7 @@
     MemObject *mem = entry->mem_obj;
     int len;
     statCounter.syscalls.sock.reads++;
-    len = read(fd, buf, 4095);
+    len = comm_read_wrapper(fd, buf, 4095);
     buf[len] = '\0';
     debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len);
     debug(75, 5) ("{%s}\n", buf);
@@ -104,12 +104,10 @@
 	kb_incr(&statCounter.server.http.kbytes_in, len);
 	storeAppend(entry, buf, len);
 	commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read);
-	CLEAR_CAN_READ_IF_EMPTY( 4095, len, fd );
     } else if (len < 0) {
 	debug(50, 2) ("whoisReadReply: FD %d: read failure: %s.\n",
 	    fd, xstrerror());
 	if (ignoreErrno(errno)) {
-	  CLEAR_CAN_READ( fd );
 	  commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read);
 	} else if (mem->inmem_hi == 0) {
 	    ErrorState *err;
Index: squid/src/fs/butterfly/store_dir_bf.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/butterfly/Attic/store_dir_bf.c,v
retrieving revision 1.1.2.1.2.1
retrieving revision 1.1.2.1.2.1.2.1
diff -u -r1.1.2.1.2.1 -r1.1.2.1.2.1.2.1
--- squid/src/fs/butterfly/store_dir_bf.c	17 Dec 2000 14:09:08 -0000	1.1.2.1.2.1
+++ squid/src/fs/butterfly/store_dir_bf.c	17 Dec 2000 14:36:24 -0000	1.1.2.1.2.1.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir_bf.c,v 1.1.2.1.2.1 2000/12/17 14:09:08 hno Exp $
+ * $Id: store_dir_bf.c,v 1.1.2.1.2.1.2.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 86    Store Directory, the "Butterfly" version
  * AUTHOR: Yury Shevchuk <sizif@botik.ru>
@@ -54,6 +54,7 @@
 };
 
 int n_bf_dirs = 0;
+int n_bf_offline = 0;
 static int *bf_dir_index = NULL;
 MemPool *bf_state_pool = NULL;
 MemPool *bf_op_pool = NULL;
@@ -73,6 +74,10 @@
 static void storeBfDirInit(SwapDir * sd);
 static void storeBfStats(StoreEntry * sentry);
 static void storeBfDirSync(SwapDir * SD);
+#if defined( DISK_REPL )
+static int storeBfDirOffline(SwapDir * SD);
+static int storeBfDirOnline(SwapDir * SD);
+#endif
 static int  storeBfDirCallback(SwapDir * SD);
 static void storeBfRelease(StoreEntry *e);
 static SwapDir *storeBfReselectDir (const StoreEntry *e);
@@ -92,6 +97,7 @@
 static void storeBfDirFree(SwapDir * s);
 static int  storeBfCleanupDoubleCheck(SwapDir * sd, StoreEntry * e);
 static void storeBfDirParse(SwapDir * sd, int index, char *path);
+static int findNthBf( int n );
 
 
 int
@@ -227,28 +233,47 @@
 	snprintf(aio_nthreads, sizeof(aio_nthreads), "%d", bf_nthreads);
 	setenv(AIO_THREAD_ENVIRON, aio_nthreads, 0);
     }
-    if (storeBfDirVerifyCacheDirs(sd) < 0)
+    if (storeBfDirVerifyCacheDirs(sd) < 0) {
+#if defined( DISK_REPL )
+	sd -> flags.offline = 1;
+	bfi->dir = -1;
+#else
 	fatal(errmsg);
-
-    bfi->dir = open (sd->path, O_RDONLY);
-    if (bfi->dir < 0) {
+#endif
+    } else {
+      bfi->dir = open (sd->path, O_RDONLY);
+      if (bfi->dir < 0) {
 	debug(50, 0) ("storeBfInit: open(%s): %s\n", sd->path, xstrerror());
+#if defined( DISK_REPL )
+	sd -> flags.offline = 1;
+#else
 	fatal ("cache_dir open failed");
-    }
+#endif
+      }
+      else
+	{
 #if 0				/* TODO: consider legalizing dir fd? */
-    fd_note(bfi->dir, sd->path);
-    commSetTimeout(bfi->dir, -1, NULL, NULL);
-    commSetNonBlocking(bfi->dir);
-#endif
-    /* We are doing polled I/O, don't wait too long in comm_poll */
-    comm_quick_poll_required();
-    storeBfDirOpenSwapLog(sd);
-    storeBfDirRebuild(sd);
+      fd_note(bfi->dir, sd->path);
+      commSetTimeout(bfi->dir, -1, NULL, NULL);
+      commSetNonBlocking(bfi->dir);
+#endif
+      /* We are doing polled I/O, don't wait too long in comm_poll */
+      comm_quick_poll_required();
+      storeBfDirOpenSwapLog(sd);
+      storeBfDirRebuild(sd);
+	}
+    }
 #if 0 && defined( TCP_ASYNC )
     debug(50, 0) ("storeBfDirInit: commCioAddCB\n");
     commCioAddCB( SIGBUTTERFLY, storeBfDirCioCallback );
 /* TCP_ASYNC */
 #endif
+#if defined( DISK_REPL )
+    sd -> raid.offline_errno = DISK_DIES_ERRNO;
+    sd -> raid.errno_threshold = 2;
+    sd -> raid.errnos_detected = 0;
+#endif
+    assert( n_bf_dirs >= 0 );
 }
 
 
@@ -301,6 +326,50 @@
 #endif
 }
 
+#if defined( DISK_REPL )
+static int storeBfDirOffline(SwapDir * SD)
+{
+  bfinfo_t *bfi = SD -> fsdata;
+
+  assert( SD != NULL );
+  debug( 86, 9 ) ( "storeBfDirOffline: offline: %i total: %i\n",
+		   n_bf_offline, n_bf_dirs );
+
+  close( bfi -> dir );
+  bfi -> dir = -1;
+
+  ++n_bf_offline;
+  if( 0 >= n_bf_dirs )
+    {
+      debug( 86, 8 ) ( "storeBfDirOffline: all Butterfly dirs are gone.\n" );
+    }
+  return 1;
+}
+
+static int storeBfDirOnline(SwapDir * SD)
+{
+  bfinfo_t *bfi = SD -> fsdata;
+
+  assert( SD != NULL );
+  assert( n_bf_offline >= 0 );
+  
+  bfi -> dir = open( SD -> path, O_RDONLY );
+  if( bfi -> dir < 0 )
+    {
+      debug(50, 0) ("storeBfDirOnline: open(%s): %s\n", 
+		    SD -> path, xstrerror() );
+      return 0;
+    }
+  else
+    {
+      --n_bf_offline;
+      assert( n_bf_offline >= 0 );
+      return 1;
+    }
+}
+
+#endif
+
 /* Write down op duration profiling data */
 
 static void
@@ -451,7 +520,7 @@
 static SwapDir *
 storeBfReselectDir (const StoreEntry *e)
 {
-    return INDEXSD(storeBfSelectSwapDir(e));
+  return INDEXSD(storeBfSelectSwapDir(e));
 }
 
 
@@ -575,6 +644,11 @@
 	return NULL;
     if (strncasecmp (url, "cache_object://", sizeof "cache_object://"-1) == 0)
 	return NULL;
+#if defined( DISK_REPL )
+    if (n_storetree_dirs <= n_bf_offline)
+	return NULL;
+#endif
+
 
     debug(86, 5) ("StoreTreeGet for %s %s  Callers %p %p %p %p\n", url,
 		  storeKeyText (key),
@@ -678,41 +752,124 @@
 static int
 storeBfSelectSwapDir(const StoreEntry * e)
 {
-    int dirn;
-    int x;
-
+    int shift;
+    
     if (! e->id_valid) {
 	assert (e->mem_obj);
 	assert (e->mem_obj->url);
-	e->id = make_id (e->key, e->mem_obj->url, strlen (e->mem_obj->url));
-	e->id_valid = 1;
-    }
-
-    x = *(unsigned *)e->key % n_bf_dirs;
-    
-    if (Config.cacheSwap.n_configured == n_bf_dirs)
-	return x;
-    else for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-	SwapDir *sd = INDEXSD(dirn);
-	if (storeBfDirIs(sd)) {
-	    if (x == 0)
+	/* To avoid constness complaints from cc */
+	((StoreEntry *)e)->id = make_id 
+	  (e->key, e->mem_obj->url, strlen (e->mem_obj->url));
+	((StoreEntry *)e)->id_valid = 1;
+    }
+
+    /* it is not very clean way of coding (it is not clean at all) 
+       but keep with it just for the time being (and being and being and...) */
+    /* This was updated to handle case when some disks are offline.
+       We take each sizeof( unsigned int ) chars from MD5 checksum of
+       URL, divide it to the number of configured butterfly cache_dirs
+       and see if it points to the online dir. If it is not we just
+       move to the next char, otherwise return this dir.
+    */
+    for( shift = 0 ; shift < MD5_DIGEST_CHARS - sizeof( unsigned ) ; ++shift )
+      {
+	int dirn;
+	int x;
+
+	/* n_bf_dirs is decremented when cache goes offline.
+	   n_bf_dirs + n_bf_offline is invariant */
+	x = *(unsigned *)(e->key + shift) % ( n_bf_dirs + n_bf_offline );
+	/* All caches are butterfly and all of them are online. Normal case. */
+	if((Config.cacheSwap.n_configured == n_bf_dirs) && 
+	   (n_bf_offline == 0))
+	  {
+	    debug( 91, 9 ) ("storeBfSelectSwapDir(shortcut): dirn: %i\n", x );
+	    return x;
+	  }
+	/* Some cache_dirs are offline */
+	else if( n_bf_dirs > 0 )
+	  {
+	    dirn = findNthBf( x );
+	    assert( dirn >= 0 );
+#if defined( DISK_REPL )
+	    if( !INDEXSD(dirn) -> flags.offline )
+	      {
 		return dirn;
-	    x--;
+	      }
+	    else
+	      {
+		/* try next portion of md5 */
+		debug( 91, 9 ) 
+		  ("storeBfSelectSwapDir: skipped dirn: %i(%i:%i:%i)\n", 
+		   dirn, x, *(unsigned *)( e -> key + shift ),
+		   n_bf_dirs + n_bf_offline );
+		continue;
+	      }
+#else
+	    return dirn;
+#endif
+	  }
+	/* All butterfly caches are offline. */
+	else
+	  { 
+	    break;
+	  } 
+      }
+    /* 
+       All butterfly caches are offline or we tried all possible
+       hashes and always hit offline dir. Forget about load balancing
+       etc., and just return the first online butterfly directory that
+       we can find.  The frequency of this code being invoked should
+       be very small, causing insignificant distortion of optimal load
+       balancing. --hans
+    */
+    if( n_bf_dirs > 0 )
+      {
+	SwapDir *sd;
+
+	FOREACHSD( sd )
+	  {
+	    if( storeBfDirIs( sd ) && sd -> flags.offline )
+	      {
+		return sd -> index;
+	      }
+	  }
+	assert( 0 );
+	return 0;
+      }
+    else
+      {
+	/* As a last resort try to use any online cache whatsover. */
+	/* Will assert(0) if there are no online caches. */
+	return findFirstOnlineSD();
+      }
+}
+
+static int findNthBf( int n )
+{
+  SwapDir *sd;
+
+  FOREACHSD( sd ) 
+    {
+      if( storeBfDirIs( sd ) )
+	{
+	  if( n == 0 )
+	    {
+	      return sd -> index;
+	    }
+	  n--;
 	}
     }
-    assert (0);
-    return 0;
+  return -1;
 }
 
-
 /*
  * storeBfDirRefObj
  *
  * This routine is called whenever an object is referenced, so we can
  * maintain replacement information within the storage fs.
  *
- * TODO put reiserfs_raw setattr here!
- */
+ * TODO put reiserfs_raw setattr here!  */
 static void
 storeBfDirRefObj(SwapDir *sd, StoreEntry * e)
 {
@@ -943,6 +1100,10 @@
     sd->unrefobj = storeBfDirUnrefObj;
     sd->callback = storeBfDirCallback;
     sd->sync = storeBfDirSync;
+#if defined( DISK_REPL )
+    sd->online = storeBfDirOnline;
+    sd->offline = storeBfDirOffline;
+#endif
     sd->halfrelease = storeBfRelease;
     sd->reselectdir = storeBfReselectDir;
     sd->obj.create = storeBfCreate;
@@ -1003,9 +1164,57 @@
 
 /*
  * $Log: store_dir_bf.c,v $
+ * Revision 1.1.2.1.2.1.2.1  2000/12/17 14:36:24  hno
+ * Imported raid from squidng
+ *
  * Revision 1.1.2.1.2.1  2000/12/17 14:09:08  hno
  * Imported tcp_async from squidng
  *
+ * --- below are from squidng ---
+ *
+ * Revision 1.1.2.7.2.3.2.12  2000/12/07 16:49:31  nikitadanilov
+ * storeBfDirInit: asserts and n_bf_dirs handling corrected (Sizif noted that 
+ * it crashed if first dir was initially offline)
+ *
+ * Revision 1.1.2.7.2.3.2.11  2000/11/28 16:01:39  nikitadanilov
+ * Missing braces (noted by Sizif) inserted.
+ *
+ * Revision 1.1.2.7.2.3.2.10  2000/11/28 11:52:16  sizif
+ * Missing {}s in the recent change
+ *
+ * Revision 1.1.2.7.2.3.2.9  2000/11/27 19:55:56  nikitadanilov
+ * if storeBfDirVerifyCacheDirs() returns -1 just mark cache_dir as offline,
+ * don't bail
+ *
+ * Revision 1.1.2.7.2.3.2.8  2000/11/24 20:43:34  nikitadanilov
+ * If Butterfly cache_dir is inaccessible during startup, mark it offline, not
+ * bail out (NOT TESTED)
+ *
+ * Revision 1.1.2.7.2.3.2.7  2000/11/22 14:49:01  nikitadanilov
+ * Online/offline callbacks improved. Hash function changed for new semantics 
+ * of n_bf_dirs and n_bf_offline
+ *
+ * Revision 1.1.2.7.2.3.2.6  2000/10/20 12:05:04  nikitadanilov
+ * Correct invalid return value from storeBfSelectSwapDir() when compiled w/o 
+ * DISK_REPL
+ *
+ * Revision 1.1.2.7.2.3.2.5  2000/10/19 09:59:48  nikitadanilov
+ * storeBfSelectSwapDir corrected
+ *
+ * Revision 1.1.2.7.2.3.2.4  2000/10/17 19:44:00  nikitadanilov
+ * Move .raid initialisation into storeBfDirInit()
+ *
+ * Revision 1.1.2.7.2.3.2.3  2000/10/17 19:31:26  nikitadanilov
+ * storeBfSelectSwapDir() should be more stable to disk crashes
+ *
+ * Revision 1.1.2.7.2.3.2.2  2000/10/13 15:43:19  nikitadanilov
+ * RAID disk replcement changes: added per-fs callbacks called on on/of-line s
+ * witch; Crash simulation added; Code commented. It started to work (with
+ * crash simulation). Alpha release state reached.
+ *
+ * Revision 1.1.2.7.2.3.2.1  2000/10/12 21:02:21  nikitadanilov
+ * Prototype of put-disk-offline-on-the-fly sub-system
+ *
  * Revision 1.1.2.7.2.3  2000/10/12 15:06:25  nikitadanilov
  * Small typo corrected
  *
Index: squid/src/fs/butterfly/store_io_bf.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/butterfly/Attic/store_io_bf.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.1.4.1
diff -u -r1.1.2.1 -r1.1.2.1.4.1
--- squid/src/fs/butterfly/store_io_bf.c	17 Dec 2000 13:55:40 -0000	1.1.2.1
+++ squid/src/fs/butterfly/store_io_bf.c	17 Dec 2000 14:36:24 -0000	1.1.2.1.4.1
@@ -1,5 +1,5 @@
 
-/* $Id: store_io_bf.c,v 1.1.2.1 2000/12/17 13:55:40 hno Exp $
+/* $Id: store_io_bf.c,v 1.1.2.1.4.1 2000/12/17 14:36:24 hno Exp $
  *
  * DEBUG: section 81   Butterfly cache_dir I/O functions.
  * Written by Yury Shevchuk <sizif@botik.ru>
@@ -563,6 +563,15 @@
 	    sio->e->swap_file_sz = bfstate->ra.size;
 	    store_open_disk_fd++;
 	    debug(81, 4) ("storeBfOpCompletion: sio %p fd %d opened\n", sio, bfstate->fd);
+#if defined( DISK_REPL )
+	    fd_table[ bfstate->fd ].swap_dir = sio -> swap_dirn;
+#endif
+	    debug( 81, 9 )( "butterfly fd: %i in swap_dir: %i\n", 
+			    bfstate->fd, sio -> swap_dirn );
+	    if( op -> type == BFCREAT )
+	      {
+		fd_note( bfstate->fd, "Butterfly KAIO" );
+	      }
 	}
 	break;
 
@@ -572,6 +581,18 @@
 	rlen = (x == 0)? aio_return (&op->aio): -1;
 	op->rlen = (x == 0)? aio_return (&op->aio): 0;
 	storeBfUpdateOffset (bfstate);
+#if defined( DISK_REPL )
+	if( fd_table[ bfstate->fd ].swap_dir != sio -> swap_dirn )
+	  {
+	    debug( 81, 9 )( "BFREAD: swap_dir anomaly: fd: %i\n", bfstate->fd );
+	    print_fde( &fd_table[ bfstate->fd ] );
+	    debug( 81, 9 ) ( "op: %s", storeBfOpDump( op ) );
+	  }
+	else
+#endif
+	  {
+	    callReadHook( bfstate->fd, &x );
+	  }
 	if (! bfstate->aborting && cbdataValid(op->callback_data))
 	    op->callback.read (op->callback_data, op->aio.aio_buf, rlen);
 	cbdataUnlock (op->callback_data);
@@ -582,6 +603,18 @@
 	    storeBfIOAbort (sio, op->type, x);
 	op->rlen = (x == 0)? aio_return (&op->aio): 0;
 	storeBfUpdateOffset (bfstate);
+#if defined( DISK_REPL )
+	if( fd_table[ bfstate->fd ].swap_dir != sio -> swap_dirn )
+	  {
+	    debug( 81, 9 )( "BFWRITE: swap_dir anomaly: fd: %i\n", bfstate->fd );
+	    print_fde( &fd_table[ bfstate->fd ] );
+	    debug( 81, 9 ) ( "op: %s", storeBfOpDump( op ) );
+	  }
+	else
+#endif
+	  {
+		callWriteHook( bfstate->fd, &x );
+	  }
 	if (op->callback.write)
 	    op->callback.write (op->aio.aio_buf); /* free_func */
 	break;
Index: squid/src/fs/ufs/store_dir_ufs.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/ufs/store_dir_ufs.c,v
retrieving revision 1.5.4.1
retrieving revision 1.5.4.1.6.1
diff -u -r1.5.4.1 -r1.5.4.1.6.1
--- squid/src/fs/ufs/store_dir_ufs.c	17 Dec 2000 08:20:06 -0000	1.5.4.1
+++ squid/src/fs/ufs/store_dir_ufs.c	17 Dec 2000 14:36:24 -0000	1.5.4.1.6.1
@@ -862,6 +862,10 @@
     char *new_path = xstrdup(storeUfsDirSwapLogFile(sd, ".new"));
     int fd;
     file_close(ufsinfo->swaplog_fd);
+    if( sd -> flags.offline )
+      {
+	return;
+      }
 #ifdef _SQUID_OS2_
     if (unlink(swaplog_path) < 0) {
 	debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
@@ -893,6 +897,10 @@
     struct stat clean_sb;
     FILE *fp;
     int fd;
+    if( sd -> flags.offline )
+      {
+	return;
+      }
     if (stat(swaplog_path, &log_sb) < 0) {
 	debug(47, 1) ("Cache Dir #%d: No log file\n", sd->index);
 	safe_free(swaplog_path);
@@ -952,6 +960,11 @@
 {
     struct _clean_state *state = xcalloc(1, sizeof(*state));
     struct stat sb;
+
+    if( sd -> flags.offline )
+      {
+	return;
+      }
     sd->log.clean.write = NULL;
     sd->log.clean.state = NULL;
     state->new = xstrdup(storeUfsDirSwapLogFile(sd, ".clean"));
@@ -1001,6 +1014,11 @@
     storeSwapLogData s;
     static size_t ss = sizeof(storeSwapLogData);
     struct _clean_state *state = sd->log.clean.state;
+
+    if( sd -> flags.offline )
+      {
+	return;
+      }
     memset(&s, '\0', ss);
     s.op = (char) SWAP_LOG_ADD;
     s.swap_filen = e->swap_filen;
@@ -1035,6 +1053,8 @@
 storeUfsDirWriteCleanDone(SwapDir * sd)
 {
     struct _clean_state *state = sd->log.clean.state;
+    if (sd->flags.offline)
+	return;
     if (NULL == state)
 	return;
     if (state->fd < 0)
@@ -1095,7 +1115,10 @@
 storeUfsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op)
 {
     ufsinfo_t *ufsinfo = (ufsinfo_t *) sd->fsdata;
-    storeSwapLogData *s = memAllocate(MEM_SWAP_LOG_DATA);
+    storeSwapLogData *s;
+    if (sd->flags.offline)
+	return;
+    s = memAllocate(MEM_SWAP_LOG_DATA);
     s->op = (char) op;
     s->swap_filen = e->swap_filen;
     s->timestamp = e->timestamp;
@@ -1118,6 +1141,10 @@
 static void
 storeUfsDirNewfs(SwapDir * sd)
 {
+    if( sd -> flags.offline )
+      {
+	return;
+      }
     debug(47, 3) ("Creating swap space in %s\n", sd->path);
     storeUfsDirCreateDirectory(sd->path, 0);
     storeUfsDirCreateSwapSubDirs(sd);
@@ -1153,6 +1180,10 @@
     N0 = n_ufs_dirs;
     D0 = ufs_dir_index[swap_index % N0];
     SD = &Config.cacheSwap.swapDirs[D0];
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     ufsinfo = (ufsinfo_t *) SD->fsdata;
     N1 = ufsinfo->l1;
     D1 = (swap_index / N0) % N1;
@@ -1229,6 +1260,10 @@
 	ufs_dir_index = xcalloc(n_ufs_dirs, sizeof(*ufs_dir_index));
 	for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) {
 	    sd = &Config.cacheSwap.swapDirs[i];
+	    if( sd -> flags.offline )
+	      {
+		continue;
+	      }
 	    if (!storeUfsDirIs(sd))
 		continue;
 	    ufs_dir_index[n++] = i;
@@ -1309,6 +1344,10 @@
     double f;
     RemovalPurgeWalker *walker;
     /* We can't delete objects while rebuilding swap */
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     if (store_dirs_rebuilding) {
 	return;
     } else {
@@ -1356,6 +1395,10 @@
 	return -1;
     }
 #endif
+    if( SD -> flags.offline )
+      {
+	return -1;
+      }
     /* Return 999 (99.9%) constant load */
     return 999;
 }
@@ -1371,6 +1414,10 @@
 {
     debug(1, 3) ("storeUfsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn,
 	e->swap_filen);
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     if (SD->repl->Referenced)
 	SD->repl->Referenced(SD->repl, e, &e->repl);
 }
@@ -1385,6 +1432,10 @@
 {
     debug(1, 3) ("storeUfsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn,
 	e->swap_filen);
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     if (SD->repl->Dereferenced)
 	SD->repl->Dereferenced(SD->repl, e, &e->repl);
 }
@@ -1401,6 +1452,10 @@
 {
     debug(79, 3) ("storeUfsDirUnlinkFile: unlinking fileno %08X\n", f);
     /* storeUfsDirMapBitReset(SD, f); */
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     unlinkdUnlink(storeUfsDirFullPath(SD, f, NULL));
 }
 
@@ -1414,6 +1469,10 @@
 {
     debug(20, 4) ("storeUfsDirReplAdd: added node %p to dir %d\n", e,
 	SD->index);
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     SD->repl->Add(SD->repl, e, &e->repl);
 }
 
@@ -1424,6 +1483,10 @@
     SwapDir *SD = INDEXSD(e->swap_dirn);
     debug(20, 4) ("storeUfsDirReplRemove: remove node %p from dir %d\n", e,
 	SD->index);
+    if( SD -> flags.offline )
+      {
+	return;
+      }
     SD->repl->Remove(SD->repl, e, &e->repl);
 }
 
@@ -1494,6 +1557,10 @@
     int l2;
     unsigned int read_only = 0;
 
+    if( sd -> flags.offline )
+      {
+	return;
+      }
     i = GetInteger();
     size = i << 10;		/* Mbytes to kbytes */
     if (size <= 0)
@@ -1529,13 +1596,13 @@
 storeUfsDirDump(StoreEntry * entry, const char *name, SwapDir * s)
 {
     ufsinfo_t *ufsinfo = (ufsinfo_t *) s->fsdata;
-    storeAppendPrintf(entry, "%s %s %s %d %d %d\n",
+    storeAppendPrintf(entry, "%s %s %s %d %d %d [%s]\n",
 	name,
 	"ufs",
 	s->path,
 	s->max_size >> 10,
 	ufsinfo->l1,
-	ufsinfo->l2);
+	ufsinfo->l2, s -> flags.offline ? "offline" : "online");
 }
 
 /*
@@ -1582,6 +1649,8 @@
 storeUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e)
 {
     struct stat sb;
+    if (sd->flags.offline)
+	return -1;
     if (stat(storeUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) {
 	debug(20, 0) ("storeUfsCleanupDoubleCheck: MISSING SWAP FILE\n");
 	debug(20, 0) ("storeUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen);
