Coda File System

patch for kernel / Venus

From: Peter Braam <braam_at_cs.cmu.edu>
Date: Thu, 21 May 1998 17:40:40 -0400 (EDT)
Henry,

I think the mount point problems are gone with the attached patches:

1. apply the patch to linux-2.1.102 (don't take 103 that has problems)

2. put time.c in arch/i386/kernel/time.c (the original doesn't compile)

3. in coda-src/venus/worker.cc edit the line ~440 in 
int k_Purge(ViceFid *fid, int severely) {

to read: 
    if (MsgWrite((char *)&msg, (int) sizeof(msg)) !=  (int) sizeof(msg)) {

4. rebuild kernel/module and venus. 

Tell me if this helps! I found some fairly bad problems, that really
needed correction.

- Peter -



/*
 *  linux/arch/i386/kernel/time.c
 *
 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
 *
 * This file contains the PC-specific time handling details:
 * reading the RTC at bootup, etc..
 * 1994-07-02    Alan Modra
 *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
 * 1995-03-26    Markus Kuhn
 *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
 *      precision CMOS clock update
 * 1996-05-03    Ingo Molnar
 *      fixed time warps in do_[slow|fast]_gettimeoffset()
 */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>

#include <linux/mc146818rtc.h>
#include <linux/timex.h>
#include <linux/config.h>

/*
 * for x86_do_profile()
 */
#include "irq.h"

extern int setup_x86_irq(int, struct irqaction *);
extern volatile unsigned long lost_ticks;

/* change this if you have some constant time drift */
#define USECS_PER_JIFFY (1000020/HZ)

#ifndef	CONFIG_APM	/* cycle counter may be unreliable */
/* Cycle counter value at the previous timer interrupt.. */
static struct {
	unsigned long low;
	unsigned long high;
} init_timer_cc, last_timer_cc;

static unsigned long do_fast_gettimeoffset(void)
{
	register unsigned long eax asm("ax");
	register unsigned long edx asm("dx");
	unsigned long tmp, quotient, low_timer;

	/* Last jiffy when do_fast_gettimeoffset() was called. */
	static unsigned long last_jiffies=0;

	/*
	 * Cached "1/(clocks per usec)*2^32" value. 
	 * It has to be recalculated once each jiffy.
	 */
	static unsigned long cached_quotient=0;

	tmp = jiffies;

	quotient = cached_quotient;
	low_timer = last_timer_cc.low;

	if (last_jiffies != tmp) {
		last_jiffies = tmp;

		/* Get last timer tick in absolute kernel time */
		eax = low_timer;
		edx = last_timer_cc.high;
		__asm__("subl "SYMBOL_NAME_STR(init_timer_cc)",%0\n\t"
			"sbbl "SYMBOL_NAME_STR(init_timer_cc)"+4,%1"
			:"=a" (eax), "=d" (edx)
			:"0" (eax), "1" (edx));

		/*
		 * Divide the 64-bit time with the 32-bit jiffy counter,
		 * getting the quotient in clocks.
		 *
		 * Giving quotient = "1/(average internal clocks per usec)*2^32"
		 * we do this '1/...' trick to get the 'mull' into the critical 
		 * path. 'mull' is much faster than divl (10 vs. 41 clocks)
		 */
		__asm__("divl %2"
			:"=a" (eax), "=d" (edx)
			:"r" (tmp),
			 "0" (eax), "1" (edx));

		edx = USECS_PER_JIFFY;
		tmp = eax;
		eax = 0;

		__asm__("divl %2"
			:"=a" (eax), "=d" (edx)
			:"r" (tmp),
			 "0" (eax), "1" (edx));
		cached_quotient = eax;
		quotient = eax;
	}

	/* Read the time counter */
	__asm__("rdtsc" : "=a" (eax), "=d" (edx));

	/* .. relative to previous jiffy (32 bits is enough) */
	edx = 0;
	eax -= low_timer;

	/*
	 * Time offset = (USECS_PER_JIFFY * time_low) * quotient.
	 */

	__asm__("mull %2"
		:"=a" (eax), "=d" (edx)
		:"r" (quotient),
		 "0" (eax), "1" (edx));

	/*
 	 * Due to possible jiffies inconsistencies, we need to check 
	 * the result so that we'll get a timer that is monotonic.
	 */
	if (edx >= USECS_PER_JIFFY)
		edx = USECS_PER_JIFFY-1;

	return edx;
}
#endif

/* This function must be called with interrupts disabled 
 * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
 * 
 * However, the pc-audio speaker driver changes the divisor so that
 * it gets interrupted rather more often - it loads 64 into the
 * counter rather than 11932! This has an adverse impact on
 * do_gettimeoffset() -- it stops working! What is also not
 * good is that the interval that our timer function gets called
 * is no longer 10.0002 ms, but 9.9767 ms. To get around this
 * would require using a different timing source. Maybe someone
 * could use the RTC - I know that this can interrupt at frequencies
 * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
 * it so that at startup, the timer code in sched.c would select
 * using either the RTC or the 8253 timer. The decision would be
 * based on whether there was any other device around that needed
 * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
 * and then do some jiggery to have a version of do_timer that 
 * advanced the clock by 1/1024 s. Every time that reached over 1/100
 * of a second, then do all the old code. If the time was kept correct
 * then do_gettimeoffset could just return 0 - there is no low order
 * divider that can be accessed.
 *
 * Ideally, you would be able to use the RTC for the speaker driver,
 * but it appears that the speaker driver really needs interrupt more
 * often than every 120 us or so.
 *
 * Anyway, this needs more thought....		pjsg (1993-08-28)
 * 
 * If you are really that interested, you should be reading
 * comp.protocols.time.ntp!
 */

#define TICK_SIZE tick

static unsigned long do_slow_gettimeoffset(void)
{
	int count;

	static int count_p = LATCH;    /* for the first call after boot */
	static unsigned long jiffies_p = 0;

	/*
	 * cache volatile jiffies temporarily; we have IRQs turned off. 
	 */
	unsigned long jiffies_t;

	/* timer count may underflow right here */
	outb_p(0x00, 0x43);	/* latch the count ASAP */

	count = inb_p(0x40);	/* read the latched count */

	/*
	 * We do this guaranteed double memory access instead of a _p 
	 * postfix in the previous port access. Wheee, hackady hack
	 */
 	jiffies_t = jiffies;

	count |= inb_p(0x40) << 8;

	/*
	 * avoiding timer inconsistencies (they are rare, but they happen)...
	 * there are two kinds of problems that must be avoided here:
	 *  1. the timer counter underflows
	 *  2. hardware problem with the timer, not giving us continuous time,
	 *     the counter does small "jumps" upwards on some Pentium systems,
	 *     (see c't 95/10 page 335 for Neptun bug.)
	 */

/* you can safely undefine this if you dont have the Neptun chipset */

#define BUGGY_NEPTUN_TIMER

	if( jiffies_t == jiffies_p ) {
		if( count > count_p ) {
			/* the nutcase */

			outb_p(0x0A, 0x20);

			/* assumption about timer being IRQ1 */
			if( inb(0x20) & 0x01 ) {
				/*
				 * We cannot detect lost timer interrupts ... 
				 * well, thats why we call them lost, dont we? :)
				 * [hmm, on the Pentium and Alpha we can ... sort of]
				 */
				count -= LATCH;
			} else {
#ifdef BUGGY_NEPTUN_TIMER
				/*
				 * for the Neptun bug we know that the 'latch'
				 * command doesnt latch the high and low value
				 * of the counter atomically. Thus we have to 
				 * substract 256 from the counter 
				 * ... funny, isnt it? :)
				 */

				count -= 256;
#else
				printk("do_slow_gettimeoffset(): hardware timer problem?\n");
#endif
			}
		}
	} else
		jiffies_p = jiffies_t;

	count_p = count;

	count = ((LATCH-1) - count) * TICK_SIZE;
	count = (count + LATCH/2) / LATCH;

	return count;
}

#ifndef CONFIG_APM
/*
 * this is only used if we have fast gettimeoffset:
 */
static void do_x86_get_fast_time(struct timeval * tv)
{
	do_gettimeofday(tv);
}
#endif

static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;

/*
 * This version of gettimeofday has near microsecond resolution.
 */
void do_gettimeofday(struct timeval *tv)
{
	unsigned long flags;

	save_flags(flags);
	cli();
	*tv = xtime;
	tv->tv_usec += do_gettimeoffset();

	/*
	 * xtime is atomically updated in timer_bh. lost_ticks is
	 * nonzero if the timer bottom half hasnt executed yet.
	 */
	if (lost_ticks)
		tv->tv_usec += USECS_PER_JIFFY;

	restore_flags(flags);

	if (tv->tv_usec >= 1000000) {
		tv->tv_usec -= 1000000;
		tv->tv_sec++;
	}
}

void do_settimeofday(struct timeval *tv)
{
	cli();
	/* This is revolting. We need to set the xtime.tv_usec
	 * correctly. However, the value in this location is
	 * is value at the last tick.
	 * Discover what correction gettimeofday
	 * would have done, and then undo it!
	 */
	tv->tv_usec -= do_gettimeoffset();

	if (tv->tv_usec < 0) {
		tv->tv_usec += 1000000;
		tv->tv_sec--;
	}

	xtime = *tv;
	time_state = TIME_BAD;
	time_maxerror = MAXPHASE;
	time_esterror = MAXPHASE;
	sti();
}


/*
 * In order to set the CMOS clock precisely, set_rtc_mmss has to be
 * called 500 ms after the second nowtime has started, because when
 * nowtime is written into the registers of the CMOS clock, it will
 * jump to the next second precisely 500 ms later. Check the Motorola
 * MC146818A or Dallas DS12887 data sheet for details.
 */
static int set_rtc_mmss(unsigned long nowtime)
{
	int retval = 0;
	int real_seconds, real_minutes, cmos_minutes;
	unsigned char save_control, save_freq_select;

	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);

	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

	cmos_minutes = CMOS_READ(RTC_MINUTES);
	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
		BCD_TO_BIN(cmos_minutes);

	/*
	 * since we're only adjusting minutes and seconds,
	 * don't interfere with hour overflow. This avoids
	 * messing with unknown time zones but requires your
	 * RTC not to be off by more than 15 minutes
	 */
	real_seconds = nowtime % 60;
	real_minutes = nowtime / 60;
	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
		real_minutes += 30;		/* correct for half hour time zone */
	real_minutes %= 60;

	if (abs(real_minutes - cmos_minutes) < 30) {
		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
			BIN_TO_BCD(real_seconds);
			BIN_TO_BCD(real_minutes);
		}
		CMOS_WRITE(real_seconds,RTC_SECONDS);
		CMOS_WRITE(real_minutes,RTC_MINUTES);
	} else
		retval = -1;

	/* The following flags have to be released exactly in this order,
	 * otherwise the DS12887 (popular MC146818A clone with integrated
	 * battery and quartz) will not reset the oscillator and will not
	 * update precisely 500 ms later. You won't find this mentioned in
	 * the Dallas Semiconductor data sheets, but who believes data
	 * sheets anyway ...                           -- Markus Kuhn
	 */
	CMOS_WRITE(save_control, RTC_CONTROL);
	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);

	return retval;
}

/* last time the cmos clock got updated */
static long last_rtc_update = 0;

/*
 * timer_interrupt() needs to keep up the real-time clock,
 * as well as call the "do_timer()" routine every clocktick
 */
static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	do_timer(regs);
/*
 * In the SMP case we use the local APIC timer interrupt to do the
 * profiling, except when we simulate SMP mode on a uniprocessor
 * system, in that case we have to call the local interrupt handler.
 */
#ifndef __SMP__
	if (!user_mode(regs))
		x86_do_profile(regs->eip);
#else
	if (!smp_found_config)
		smp_local_timer_interrupt(regs);
#endif

	/*
	 * If we have an externally synchronized Linux clock, then update
	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
	 * called as close as possible to 500 ms before the new second starts.
	 */
	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
	    xtime.tv_usec > 500000 - (tick >> 1) &&
	    xtime.tv_usec < 500000 + (tick >> 1)) {
	  if (set_rtc_mmss(xtime.tv_sec) == 0)
	    last_rtc_update = xtime.tv_sec;
	  else
	    last_rtc_update = xtime.tv_sec - 600; 
}            /* do it again in 60 s */
#if 0
	/* As we return to user mode fire off the other CPU schedulers.. this is 
	   basically because we don't yet share IRQ's around. This message is
	   rigged to be safe on the 386 - basically it's a hack, so don't look
	   closely for now.. */
	smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
#endif
	    
#ifdef CONFIG_MCA
	if( MCA_bus ) {
		/* The PS/2 uses level-triggered interrupts.  You can't
		turn them off, nor would you want to (any attempt to
		enable edge-triggered interrupts usually gets intercepted by a
		special hardware circuit).  Hence we have to acknowledge
		the timer interrupt.  Through some incredibly stupid
		design idea, the reset for IRQ 0 is done by setting the
		high bit of the PPI port B (0x61).  Note that some PS/2s,
		notably the 55SX, work fine if this is removed.  */

		irq = inb_p( 0x61 );	/* read the current state */
		outb_p( irq|0x80, 0x61 );	/* reset the IRQ */
	}
#endif
}

#ifndef	CONFIG_APM	/* cycle counter may be unreliable */
/*
 * This is the same as the above, except we _also_ save the current
 * cycle counter value at the time of the timer interrupt, so that
 * we later on can estimate the time of day more exactly.
 */
static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	/* read Pentium cycle counter */
	__asm__("rdtsc"
		:"=a" (last_timer_cc.low),
		 "=d" (last_timer_cc.high));
	timer_interrupt(irq, NULL, regs);
}
#endif

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 *
 * [For the Julian calendar (which was used in Russia before 1917,
 * Britain & colonies before 1752, anywhere else before 1582,
 * and is still in use by some communities) leave out the
 * -year/100+year/400 terms, and add 10.]
 *
 * This algorithm was first published by Gauss (I think).
 *
 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
 * machines were long is 32-bit! (However, as time_t is signed, we
 * will already get problems at other places on 2038-01-19 03:14:08)
 */
static inline unsigned long mktime(unsigned int year, unsigned int mon,
	unsigned int day, unsigned int hour,
	unsigned int min, unsigned int sec)
{
	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
		mon += 12;	/* Puts Feb last since it has leap day */
		year -= 1;
	}
	return (((
	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
	      year*365 - 719499
	    )*24 + hour /* now have hours */
	   )*60 + min /* now have minutes */
	  )*60 + sec; /* finally seconds */
}

/* not static: needed by APM */
unsigned long get_cmos_time(void)
{
	unsigned int year, mon, day, hour, min, sec;
	int i;

	/* The Linux interpretation of the CMOS clock register contents:
	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
	 * RTC registers show the second which has precisely just started.
	 * Let's hope other operating systems interpret the RTC the same way.
	 */
	/* read RTC exactly on falling edge of update flag */
	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
			break;
	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
			break;
	do { /* Isn't this overkill ? UIP above should guarantee consistency */
		sec = CMOS_READ(RTC_SECONDS);
		min = CMOS_READ(RTC_MINUTES);
		hour = CMOS_READ(RTC_HOURS);
		day = CMOS_READ(RTC_DAY_OF_MONTH);
		mon = CMOS_READ(RTC_MONTH);
		year = CMOS_READ(RTC_YEAR);
	} while (sec != CMOS_READ(RTC_SECONDS));
	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
	  {
	    BCD_TO_BIN(sec);
	    BCD_TO_BIN(min);
	    BCD_TO_BIN(hour);
	    BCD_TO_BIN(day);
	    BCD_TO_BIN(mon);
	    BCD_TO_BIN(year);
	  }
	if ((year += 1900) < 1970)
		year += 100;
	return mktime(year, mon, day, hour, min, sec);
}

static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};


__initfunc(void time_init(void))
{
	xtime.tv_sec = get_cmos_time();
	xtime.tv_usec = 0;

	/* If we have the CPU hardware time counters, use them */
#if 0
	if (boot_cpu_data.x86_capability & 16) {
		do_gettimeoffset = do_fast_gettimeoffset;
		do_get_fast_time = do_x86_get_fast_time;

		if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
		    boot_cpu_data.x86 == 5 &&
		    boot_cpu_data.x86_model == 0) {
			/* turn on cycle counters during power down */
			__asm__ __volatile__ (" movl $0x83, %%ecx \n \
				rdmsr \n \
				orl $1,%%eax \n \
				wrmsr \n " 
                                      : : : "ax", "cx", "dx" );
				udelay(500);
		}

		/* read Pentium cycle counter */
		__asm__("rdtsc"
			:"=a" (init_timer_cc.low),
			 "=d" (init_timer_cc.high));
		irq0.handler = pentium_timer_interrupt;
	}
#endif
	setup_x86_irq(0, &irq0);
}

--- linux/fs/coda/cache.c.orig	Mon May  4 20:09:22 1998
+++ linux/fs/coda/cache.c	Thu May 21 17:34:51 1998
@@ -267,8 +267,7 @@
 	while ( alias != &inode->i_dentry ) {
 		alias_de = list_entry(alias, struct dentry, d_alias);
 		if ( !alias_de ) {
-			printk("Corrupt alias list for %*s\n",
-			       alias_de->d_name.len, alias_de->d_name.name);
+			printk("Null alias list for inode %ld\n", inode->i_ino);
 			return;
 		}
 		coda_flag_children(alias_de, flag);
--- linux/fs/coda/cnode.c.orig	Wed Mar 18 00:19:05 1998
+++ linux/fs/coda/cnode.c	Thu May 21 17:34:51 1998
@@ -15,7 +15,7 @@
 
 /* cnode.c */
 
-static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
+static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
 {
         CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
 
@@ -54,8 +54,8 @@
         ENTRY;
 
         /* 
-        * We get inode numbers from Venus -- see venus source
-	*/
+	 * We get inode numbers from Venus -- see venus source
+	 */
 
 	error = venus_getattr(sb, fid, &attr);
 	if ( error ) {
@@ -82,16 +82,26 @@
 		INIT_LIST_HEAD(&(cnp->c_cnhead));
 		INIT_LIST_HEAD(&(cnp->c_volrootlist));
 	} else {
-		printk("coda_cnode make on initialized inode %ld, %s!\n",
+	        cnp->c_flags = 0;
+		CDEBUG(D_CNODE, "coda_cnode make on initialized"
+		       "inode %ld, %s!\n",
 		       (*inode)->i_ino, coda_f2s(&cnp->c_fid));
 	}
 
 	/* fill in the inode attributes */
-	if ( coda_fid_is_volroot(fid) ) 
+	if ( coda_f2i(fid) != ino ) {
+	        if ( !coda_fid_is_weird(fid) ) 
+		        printk("Coda: unknown weird fid: ino %ld, fid %s."
+			       "Tell Peter.", ino, coda_f2s(&cnp->c_fid));
 		list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
+		CDEBUG(D_CNODE, "Added %ld ,%s to volroothead\n",
+		       ino, coda_f2s(&cnp->c_fid));
+	}
 
         coda_fill_inode(*inode, &attr);
-	CDEBUG(D_CNODE, "Done linking: ino %ld,  at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
+	CDEBUG(D_CNODE, "Done linking: ino %ld,  at 0x%x with cnp 0x%x,"
+	       "cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), 
+	       (int) cnp, (int)cnp->c_vnode);
 
         EXIT;
         return 0;
@@ -132,7 +142,7 @@
 	}
 
 
-	if ( coda_fid_is_volroot(fid) ) {
+	if ( coda_fid_is_weird(fid) ) {
 		struct coda_inode_info *cii;
 		struct list_head *lh, *le;
 		struct coda_sb_info *sbi = coda_sbp(sb);
@@ -141,7 +151,7 @@
 		while ( (le = le->next) != lh ) {
 			cii = list_entry(le, struct coda_inode_info, 
 					 c_volrootlist);
-			if ( cii->c_fid.Volume == fid->Volume) {
+			if ( coda_fideq(&cii->c_fid, fid) ) {
 				inode = cii->c_vnode;
 				CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
 				return cii->c_vnode;
@@ -151,7 +161,7 @@
 		return NULL;
 	}
 
-	/* fid is not volume root, hence ino is computable */
+	/* fid is not weird: ino should be computable */
 	nr = coda_f2i(fid);
 	inode = iget(sb, nr);
 	if ( !inode ) {
@@ -173,9 +183,9 @@
 	   These have the same inode as the root of the volume they
 	   mount, but the fid will be wrong. 
 	*/
-	if ( !coda_fideq(fid, &(cnp->c_fid)) && 
-	     !coda_fid_is_volroot(&(cnp->c_fid))) {
-		printk("coda_fid2inode: bad cnode! Tell Peter.\n");
+	if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+		printk("coda_fid2inode: bad cnode (ino %ld, fid %s)"
+		       "Tell Peter.\n", nr, coda_f2s(fid));
 		iput(inode);
 		return NULL;
 	}
--- linux/fs/coda/coda_linux.c.orig	Mon May  4 20:09:22 1998
+++ linux/fs/coda/coda_linux.c	Thu May 21 17:34:51 1998
@@ -65,6 +65,36 @@
 {
 	return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
 }
+  
+int coda_fid_is_weird(struct ViceFid *fid)
+{
+        /* volume roots */
+        if ( (fid->Vnode == 1) && (fid->Unique == 1 ) )
+	        return 1;
+        /* tmpfid unique (simulate.cc) */
+	if ( fid->Unique == 0xffffffff )
+	        return 1;
+	/* LocalFakeVnode (local.h)  */
+	if ( fid->Vnode == 0xfffffffd )
+	        return 1;
+	/* LocalFileVnode (venus.private.h) */
+	if ( fid->Vnode == 0xfffffffe )
+	        return 1;
+	/* local fake vid (local.h) */
+	if ( fid->Volume == 0xffffffff )
+	        return 1;
+	/* local DirVnode (venus.private.h) */
+	if ( fid->Vnode == 0xffffffff )
+	        return 1;
+	/* FakeVnode (venus.private.h) */
+	if ( fid->Vnode == 0xfffffffc )
+	        return 1;
+
+	return 0;
+
+}
+
+
 
 /* put the current process credentials in the cred */
 void coda_load_creds(struct coda_cred *cred)
@@ -94,14 +124,23 @@
 {
 	unsigned short coda_flags = 0;
 
-	if ( flags & (O_RDONLY | O_RDWR) )
+	if ( (flags & 0xf) == O_RDONLY )
+		coda_flags |= C_O_READ;
+
+	if ( flags &  O_RDWR )
 		coda_flags |= C_O_READ;
 
 	if ( flags & (O_WRONLY | O_RDWR) )
 		coda_flags |= C_O_WRITE;
 
-	if ( flags & O_TRUNC ) 
+	if ( flags & O_TRUNC )  { 
+		CDEBUG(D_FILE, "--> C_O_TRUNC added\n");
 		coda_flags |= C_O_TRUNC;
+	}
+	if ( flags & O_EXCL ) {
+		coda_flags |= C_O_EXCL;
+		CDEBUG(D_FILE, "--> C_O_EXCL added\n");
+	}
 
 	return coda_flags;
 }
--- linux/fs/coda/dir.c.orig	Mon May  4 20:09:22 1998
+++ linux/fs/coda/dir.c	Thu May 21 17:34:51 1998
@@ -167,8 +167,10 @@
 	entry->d_time = 0;
 	entry->d_op = &coda_dentry_operations;
 	d_add(entry, res_inode);
-	if ( dropme ) 
+	if ( dropme ) {
 		d_drop(entry);
+		ITOC(res_inode)->c_flags |= C_VATTR;
+	}
         EXIT;
         return 0;
 }
@@ -264,7 +266,7 @@
 	}
 
 	/* invalidate the directory cnode's attributes */
-	dircnp->c_flags &= ~C_VATTR;
+	dircnp->c_flags |= C_VATTR;
 	d_instantiate(de, result);
         return 0;
 }			     
@@ -320,7 +322,7 @@
 	}
 	
 	/* invalidate the directory cnode's attributes */
-	dircnp->c_flags &= ~C_VATTR;
+	dircnp->c_flags |= C_VATTR;
 	dir->i_nlink++;
 	d_instantiate(de, inode);
         return 0;
@@ -359,7 +361,7 @@
 			   (const char *)name, len);
 
 	if (  ! error ) { 
-		dir_cnp->c_flags &= ~C_VATTR;
+		dir_cnp->c_flags |= C_VATTR;
 		inode->i_nlink++;
 		d_instantiate(de, inode);
 	} else {
@@ -442,7 +444,7 @@
         }
 
         /* cache management */
-	dircnp->c_flags &= ~C_VATTR;
+	dircnp->c_flags |= C_VATTR;
 	
 	de->d_inode->i_nlink--;
 	d_delete(de);
@@ -814,7 +816,7 @@
 		if (is_bad_inode(inode))
 			return 0;
 		cii = ITOC(de->d_inode);
-		if (cii->c_flags & C_PURGE) 
+		if (cii->c_flags & (C_PURGE | C_VATTR)) 
 			valid = 0;
 	}
 	return valid ||  coda_isroot(de->d_inode);
@@ -838,7 +840,7 @@
 	}
 
 	/* this baby may be lost if:
-	   - it's type changed
+            - it's type changed
             - it's ino changed 
 	*/
 	old_mode = inode->i_mode;
@@ -852,7 +854,7 @@
 		return -EIO;
 	}
 	
-	cii->c_flags &= ~C_VATTR;
+	cii->c_flags &= ~(C_VATTR | C_PURGE);
 	return 0;
 }
 
--- linux/fs/coda/file.c.orig	Mon May  4 20:09:22 1998
+++ linux/fs/coda/file.c	Thu May 21 17:34:51 1998
@@ -192,13 +192,14 @@
                 return -1;
         }
 
-        cnp->c_flags &= ~C_VATTR;
-
 	down(&cont_inode->i_sem);
         result = cont_file.f_op->write(&cont_file , buff, count, 
 				       &(cont_file.f_pos));
 	up(&cont_inode->i_sem);
         coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+	
+	if (result)
+		cnp->c_flags |= C_VATTR;
 
         return result;
 }
--- linux/fs/coda/inode.c.orig	Sat Apr  4 12:45:14 1998
+++ linux/fs/coda/inode.c	Thu May 21 17:34:51 1998
@@ -161,6 +161,8 @@
 
         ENTRY;
 
+
+        sb->s_dev = 0;
 	coda_cache_clear_all(sb);
 	sb_info = coda_sbp(sb);
 	sb_info->sbi_vcomm->vc_inuse = 0;
--- linux/fs/coda/stats.c.orig	Tue May  5 13:52:17 1998
+++ linux/fs/coda/stats.c	Thu May 21 17:34:51 1998
@@ -7,6 +7,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
--- linux/fs/coda/upcall.c.orig	Mon May  4 20:09:22 1998
+++ linux/fs/coda/upcall.c	Thu May 21 17:34:51 1998
@@ -792,81 +792,85 @@
 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 {
 
-    /* Handle invalidate requests. */
-    switch (opcode) {
-    case CFS_FLUSH : {
-	    clstats(CFS_FLUSH);
-	    CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
-	    coda_cache_clear_all(sb);
-	    shrink_dcache_sb(sb);
-	    return(0);
-    }
-    case CFS_PURGEUSER : {
-	    struct coda_cred *cred = &out->cfs_purgeuser.cred;
-	    CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
-	    if ( !cred ) {
-		    printk("PURGEUSER: null cred!\n");
-		    return 0;
-	    }
-	    clstats(CFS_PURGEUSER);
-	    coda_cache_clear_cred(sb, cred);
-	    return(0);
-    }
-    case CFS_ZAPDIR : {
-	    struct inode *inode;
-	    ViceFid *fid = &out->cfs_zapdir.CodaFid;
-	    if ( !fid ) {
-		    printk("ZAPDIR: Null fid\n");
-		    return 0;
-	    }
-	    CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
-	    clstats(CFS_ZAPDIR);
-	    inode = coda_fid_to_inode(fid, sb);
-	    coda_flag_inode(inode, C_VATTR);
-	    coda_cache_clear_inode(inode);
-	    coda_flag_alias_children(inode, C_PURGE);
-	    return(0);
-    }
-
-    case CFS_ZAPVNODE : 
-    case CFS_ZAPFILE : {
-	    struct inode *inode;
-	    struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
-	    clstats(CFS_ZAPFILE);
-	    if ( !fid ) {
-		    printk("ZAPFILE: Null fid\n");
-		    return 0;
-	    }
-	    CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
-	    inode = coda_fid_to_inode(fid, sb);
-	    coda_flag_inode(inode, C_VATTR);
-	    coda_cache_clear_inode(inode);
-	    return 0;
-    }
-    case CFS_PURGEFID : {
-	    struct inode *inode;
-	    ViceFid *fid = &out->cfs_purgefid.CodaFid;
-	    if ( !fid ) {
-		    printk("PURGEFID: Null fid\n");
-		    return 0;
-	    }
-	    CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
-	    clstats(CFS_PURGEFID);
-	    inode = coda_fid_to_inode(fid, sb);
-	    coda_flag_inode(inode, C_PURGE);
-	    coda_cache_clear_inode(inode);
-	    return 0;
-    }
-    case CFS_REPLACE : {
-	    printk("CFS_REPLACCE\n");
-	    clstats(CFS_REPLACE);
-	    CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
-	    coda_cache_clear_all(sb);
-	    shrink_dcache_sb(sb);
-	    return (0);
-    }			   
-    }
-      return 0;
+    /* Handle invalidation requests. */
+          if ( !sb ) { 
+	          printk("coda_downcall: opcode %d, no sb!\n", opcode);
+		  return 0; 
+	  }
+
+	  switch (opcode) {
+
+	  case CFS_FLUSH : {
+	           clstats(CFS_FLUSH);
+		   CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
+		   coda_cache_clear_all(sb);
+		   shrink_dcache_sb(sb);
+		   return(0);
+	  }
+
+	  case CFS_PURGEUSER : {
+	           struct coda_cred *cred = &out->cfs_purgeuser.cred;
+		   CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
+		   if ( !cred ) {
+		           printk("PURGEUSER: null cred!\n");
+			   return 0;
+		   }
+		   clstats(CFS_PURGEUSER);
+		   coda_cache_clear_cred(sb, cred);
+		   return(0);
+	  }
+
+	  case CFS_ZAPDIR : {
+	          struct inode *inode;
+		  ViceFid *fid = &out->cfs_zapdir.CodaFid;
+		  CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
+		  clstats(CFS_ZAPDIR);
+
+		  inode = coda_fid_to_inode(fid, sb);
+		  if ( inode ) {
+	                  coda_flag_inode(inode, C_VATTR);
+			  coda_cache_clear_inode(inode);
+			  coda_flag_alias_children(inode, C_PURGE);
+		  }
+		  return(0);
+	  }
+
+	  case CFS_ZAPFILE : {
+	          struct inode *inode;
+		  struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
+		  clstats(CFS_ZAPFILE);
+		  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
+		  inode = coda_fid_to_inode(fid, sb);
+		  if ( inode ) {
+	                  coda_flag_inode(inode, C_VATTR);
+			  coda_cache_clear_inode(inode);
+		  }
+		  return 0;
+	  }
+
+	  case CFS_PURGEFID : {
+	          struct inode *inode;
+		  ViceFid *fid = &out->cfs_purgefid.CodaFid;
+		  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
+		  clstats(CFS_PURGEFID);
+		  inode = coda_fid_to_inode(fid, sb);
+		  if ( inode ) { 
+                          coda_flag_inode(inode, C_PURGE);
+			  coda_cache_clear_inode(inode);
+		  }
+		  return 0;
+	  }
+
+	  case CFS_REPLACE : {
+	          printk("CFS_REPLACCE\n");
+		  clstats(CFS_REPLACE);
+		  CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+		  coda_cache_clear_all(sb);
+		  shrink_dcache_sb(sb);
+		  return (0);
+	  }			   
+	  }
+	  return 0;
 }
 
 
--- linux/include/linux/coda.h.orig	Wed Mar 18 00:19:05 1998
+++ linux/include/linux/coda.h	Thu May 21 17:34:51 1998
@@ -148,8 +148,8 @@
 
 #ifndef _VUID_T_
 #define _VUID_T_
-typedef u_long vuid_t;
-typedef u_long vgid_t;
+typedef unsigned int vuid_t;
+typedef unsigned int vgid_t;
 #endif /*_VUID_T_ */
 
 #ifndef _CODACRED_T_
@@ -223,7 +223,7 @@
 #define CFS_PURGEUSER   ((u_long) 26)
 #define CFS_ZAPFILE     ((u_long) 27)
 #define CFS_ZAPDIR      ((u_long) 28)
-#define CFS_ZAPVNODE    ((u_long) 29)
+/* #define CFS_ZAPVNODE    ((u_long) 29)   obsolete */ 
 #define CFS_PURGEFID    ((u_long) 30)
 #define CFS_OPEN_BY_PATH ((u_long) 31)
 #define CFS_NCALLS 32
--- linux/include/linux/coda_linux.h.orig	Wed Mar 18 00:19:05 1998
+++ linux/include/linux/coda_linux.h	Thu May 21 17:34:51 1998
@@ -48,6 +48,7 @@
 char *coda_f2s(ViceFid *f);
 int coda_isroot(struct inode *i);
 int coda_fid_is_volroot(struct ViceFid *);
+int coda_fid_is_weird(struct ViceFid *fid);
 int coda_iscontrol(const char *name, size_t length);
 
 
Received on 1998-05-21 17:46:02