diff -u --recursive --new-file dist-2.1.25/Documentation/filesystems/vfs.txt linux/Documentation/filesystems/vfs.txt --- dist-2.1.25/Documentation/filesystems/vfs.txt Sun Feb 2 15:25:59 1997 +++ linux/Documentation/filesystems/vfs.txt Tue Feb 4 06:06:16 1997 @@ -2,6 +2,8 @@ =========================================== by Benjamin LaHaise (blah@dot.superaje.com) +Note: This document will be completed over time - I haven't forgotten! + Noone else seems to be writing this, so here's a quick description of what I've learned while writing lofs... @@ -30,7 +32,7 @@ in mounting itself, sb should be returned, otherwise NULL. options is a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero terminated string passed from mount. This page is freed after read_super - returns, so do not use any pointers into it. + returns, so do not keep any pointers into it. This routine _must_ set the s_op member of sb to point to a valid super_operations structure. @@ -157,9 +159,9 @@ struct file_operations ====================== - int (*lseek) (struct inode *, struct file *, off_t, int); - int (*read) (struct inode *, struct file *, char *, int); - int (*write) (struct inode *, struct file *, const char *, int); + long long (*llseek) (struct inode *, struct file *, long long, int); + long (*read) (struct inode *, struct file *, char *, unsigned long); + long (*write) (struct inode *, struct file *, const char *, unsigned long); int (*readdir) (struct inode *, struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, poll_table *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); diff -u --recursive --new-file dist-2.1.25/Makefile linux/Makefile --- dist-2.1.25/Makefile Sun Feb 2 15:25:59 1997 +++ linux/Makefile Sun Feb 2 16:17:10 1997 @@ -38,7 +38,7 @@ AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip -MAKE =make +MAKE =make -j8 GENKSYMS=/sbin/genksyms all: do-it-all diff -u --recursive --new-file dist-2.1.25/Rules.make linux/Rules.make --- dist-2.1.25/Rules.make Sun Jan 26 12:38:23 1997 +++ linux/Rules.make Sun Jan 26 12:40:07 1997 @@ -45,7 +45,16 @@ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o $@ %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -o tmp.$@ $< + pick_host "cd /tmp && cat >tmp.$@.c && $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c tmp.$@.c -o tmp.$@ 1>&2 && cat tmp.$@ && rm tmp.$@.c tmp.$@" $@ + rm tmp.$@ + +# pick_host "cd `pwd` && $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<" + +# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -o - $< | \ +# pick_host "cd /tmp && cat >tmp.$@.c && $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c tmp.$@.c -o tmp.$@ 1>&2 && cat tmp.$@ && rm tmp.$@.c tmp.$@" >$@ + +# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< %.o: %.s $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< diff -u --recursive --new-file dist-2.1.25/arch/i386/kernel/asm_irq linux/arch/i386/kernel/asm_irq --- dist-2.1.25/arch/i386/kernel/asm_irq Wed Dec 31 19:00:00 1969 +++ linux/arch/i386/kernel/asm_irq Tue Feb 4 15:45:11 1997 @@ -0,0 +1 @@ +gcc -D__KERNEL__ -I/home/dot1/blah/kernel/2.1/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -S irq.c diff -u --recursive --new-file dist-2.1.25/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- dist-2.1.25/arch/i386/kernel/irq.c Sun Jan 26 12:38:25 1997 +++ linux/arch/i386/kernel/irq.c Wed Feb 5 01:35:49 1997 @@ -8,11 +8,11 @@ * instead of just grabbing them. Thus setups with different IRQ numbers * shouldn't result in any weird surprises, and installing new handlers * should be easier. - */ - -/* + * * IRQ's are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. + * + * Software interrupt masking added 3-Feb-1997 by Benjamin LaHaise */ #include @@ -43,6 +43,17 @@ static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; #endif +__volatile__ +unsigned long sw_irq_mask = 1, /* interrupts are initially disabled */ + sw_irq_runs = 0; + +__volatile__ +unsigned long sw_irqs_slow = 0, + sw_irqs_masked = 0, /* interrupts that are *specifically* disabled */ + sw_irqs_running = 0, + sw_irqs_pending = 0; +atomic_t sw_irqs_lost[16]; + static inline void mask_irq(unsigned int irq_nr) { unsigned char mask; @@ -75,19 +86,19 @@ { unsigned long flags; - save_flags(flags); - cli(); + hw_save_flags(flags); + hw_cli(); mask_irq(irq_nr); - restore_flags(flags); + hw_restore_flags(flags); } void enable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + hw_save_flags(flags); + hw_cli(); unmask_irq(irq_nr); - restore_flags(flags); + hw_restore_flags(flags); } /* @@ -234,11 +245,11 @@ action = irq_action[i]; if (!action) continue; - len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, "%2d: %10u %10u %c %s", + i, kstat.interrupts[i], kstat.lost_interrupts[i], + (action && (action->flags & SA_INTERRUPT)) ? '+' : ' ', + action ? action->name : "not in use"); + for (action=action?action->next:NULL; action; action = action->next) { len += sprintf(buf+len, ",%s %s", (action->flags & SA_INTERRUPT) ? " +" : "", action->name); @@ -334,22 +345,11 @@ } #endif - - -/* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. - */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +static void run_irq ( int irq, struct pt_regs * regs ) { struct irqaction * action = *(irq + irq_action); int do_random = 0; - lock_kernel(); - intr_count++; #ifdef __SMP__ if(smp_threads_ready && active_kernel_processor!=smp_processor_id()) panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); @@ -366,41 +366,127 @@ } if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - intr_count--; - unlock_kernel(); } /* - * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return - * stuff - the handler is also running with interrupts disabled unless - * it explicitly enables them later. - */ -asmlinkage void do_fast_IRQ(int irq) -{ - struct irqaction * action = *(irq + irq_action); - int do_random = 0; - - lock_kernel(); + * Notes about the Software IRQ masking: + * - it should be SMP safe ;-) + * - it's horribly clever, and not easily understood + */ +static void run_sw_irq ( int irq, struct pt_regs * regs ) +{ + goto masked; + do { + /* if this fails, someone else has taken responsibility for running the irq */ + if (set_bit(irq, &sw_irqs_running)) + return; +masked: + lock_kernel(); + intr_count++; + + /* so long as there are interrupts pending, run the handler */ + while (clear_bit(irq, &sw_irqs_pending)) + run_irq(irq, regs); + + intr_count--; + unlock_kernel(); + + clear_bit(irq, &sw_irqs_running); + + /* repeat if an irq occurred as we were unmasking it */ + } while (test_bit(irq, &sw_irqs_pending)) ; +} + +asmlinkage void fudge_slow ( int irq ); +__asm__( +SYMBOL_NAME_STR(fudge_slow) ":\n\t" + "pushl %eax\n\t" + "pushl %edx\n\t" + "movl %esp,%eax\n\t" + "pushfl\n\t" + "xorl %edx,%edx\n\t" + "mov %cs,%dx\n\t" + "pushl %edx\n\t" + "movl 20(%esp),%ecx\n\t" + "call 1f\n\t" + "popl %edx\n\t" + "popl %eax\n\t" + "ret\n\t" + + "1:\tpushl %eax\n\t" + SAVE_ALL /* this trashes %edx!!! */ + "movl %esp,%eax\n\t" + "pushl %eax\n\t" + "pushl %ecx\n\t" + "call "SYMBOL_NAME_STR(run_sw_irq)"\n\t" + "addl $8,%esp\n\t" + "jmp ret_from_sys_call\n" + ); + +void run_sw_irqs ( void ) +{ + int irq; + sw_irq_runs++; + if (sw_irq_mask) + return; intr_count++; -#ifdef __SMP__ - /* IRQ 13 is allowed - that's a flush tlb */ - if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13) - panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); -#endif - - kstat.interrupts[irq]++; -#ifdef __SMP_PROF__ - int_count[smp_processor_id()][irq]++; -#endif - while (action) { - do_random |= action->flags; - action->handler(irq, action->dev_id, NULL); - action = action->next; + for (irq=0; (irq<16) && sw_irqs_pending; irq++) { + if (!set_bit(irq, &sw_irqs_running)) { + if (test_bit(irq, &sw_irqs_slow)) + fudge_slow(irq); + else + run_sw_irq(irq, NULL); + } } - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); intr_count--; - unlock_kernel(); +} + +static void ack_irq ( int irq ) +{ + if (irq >= 8) + outb(0x20,0xA0); + outb(0x20,0x20); +} + +static int try_mask_irq ( int irq ) +{ + /* check if the interrupt was masked */ + if (set_bit(irq, &sw_irqs_running)) { + /* mark the irq as pending, recording lost interrupts */ + if (set_bit(irq, &sw_irqs_pending)) + atomic_inc(&sw_irqs_lost[irq]); + + /* if someone still has irq masked off, we're done. */ + if (set_bit(irq, &sw_irqs_running)) + return 1; + } + return 0; +} +/* + * do_IRQ handles IRQ's that have been installed both with and + * with the + * SA_INTERRUPT flag: it uses the full signal-handling return + * and runs with other interrupts enabled. All relatively slow + * IRQ's should use this format: notably the keyboard/timer + * routines. + * + * A 'fast' IRQ is indicated by being passed regs == NULL + * Right now there is not much difference between a 'fast' + * and a 'slow' IRQ handler. + */ +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + if (set_bit(irq, &sw_irqs_pending)) + atomic_inc(&sw_irqs_lost[irq]); + ack_irq(irq); + hw_sti(); + /* if interrupts are already disabled */ + if (set_bit(0, &sw_irq_mask)) + return; + if (set_bit(irq, &sw_irqs_running)) + return; + run_sw_irq(irq, regs); + clear_bit(0, &sw_irq_mask); } int setup_x86_irq(int irq, struct irqaction * new) @@ -430,18 +516,21 @@ if (new->flags & SA_SAMPLE_RANDOM) rand_initialize_irq(irq); - save_flags(flags); - cli(); + hw_save_flags(flags); + hw_cli(); *p = new; if (!shared) { - if (new->flags & SA_INTERRUPT) + if (new->flags & SA_INTERRUPT) { + clear_bit(irq, &sw_irqs_slow); set_intr_gate(0x20+irq,fast_interrupt[irq]); - else + } else { + set_bit(irq, &sw_irqs_slow); set_intr_gate(0x20+irq,interrupt[irq]); + } unmask_irq(irq); } - restore_flags(flags); + hw_restore_flags(flags); return 0; } @@ -491,14 +580,14 @@ continue; /* Found it - now free it */ - save_flags(flags); - cli(); + hw_save_flags(flags); + hw_cli(); *p = action->next; if (!irq[irq_action]) { mask_irq(irq); set_intr_gate(0x20+irq,bad_interrupt[irq]); } - restore_flags(flags); + hw_restore_flags(flags); kfree(action); return; } @@ -567,4 +656,7 @@ request_region(0xa0,0x20,"pic2"); setup_x86_irq(2, &irq2); setup_x86_irq(13, &irq13); + + /* let hardware irqs happen - we've our 'buffer' now. */ + hw_sti(); } diff -u --recursive --new-file dist-2.1.25/arch/i386/kernel/test.c linux/arch/i386/kernel/test.c --- dist-2.1.25/arch/i386/kernel/test.c Wed Dec 31 19:00:00 1969 +++ linux/arch/i386/kernel/test.c Wed Feb 5 00:50:53 1997 @@ -0,0 +1,22 @@ +#include +#include + +extern void bar ( void ); + +void foo ( void ) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + bar(); + + restore_flags(flags); +} + +void zoik ( void ) +{ + bar(); + sti(); +} diff -u --recursive --new-file dist-2.1.25/drivers/block/md.c linux/drivers/block/md.c --- dist-2.1.25/drivers/block/md.c Tue Jan 21 01:19:51 1997 +++ linux/drivers/block/md.c Wed Jan 29 00:25:54 1997 @@ -216,9 +216,12 @@ } /* Remove locks. */ - for (i=0; ii_sb,old_ino,0); + old_inode = iget(old_dir->i_sb,old_ino); if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) goto end_rename; new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); if (new_bh) { - new_inode = __iget(new_dir->i_sb,new_ino,0); + new_inode = iget(new_dir->i_sb,new_ino); if (!new_inode) { /* What does this mean? */ affs_brelse(new_bh); new_bh = NULL; diff -u --recursive --new-file dist-2.1.25/fs/exec.c linux/fs/exec.c --- dist-2.1.25/fs/exec.c Sun Jan 26 12:38:50 1997 +++ linux/fs/exec.c Wed Jan 29 00:25:54 1997 @@ -135,16 +135,17 @@ f->f_pos = 0; f->f_reada = 0; f->f_op = inode->i_op->default_file_ops; + inode->i_count++; if (f->f_op->open) { int error = f->f_op->open(inode,f); if (error) { f->f_count--; put_unused_fd(fd); + iput(inode); return error; } } current->files->fd[fd] = f; - inode->i_count++; } return fd; } diff -u --recursive --new-file dist-2.1.25/fs/ext2/namei.c linux/fs/ext2/namei.c --- dist-2.1.25/fs/ext2/namei.c Tue Dec 17 07:05:41 1996 +++ linux/fs/ext2/namei.c Sun Feb 2 18:22:27 1997 @@ -978,7 +978,7 @@ retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */ + old_inode = iget (old_dir->i_sb, le32_to_cpu(old_de->inode)); if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) @@ -992,7 +992,7 @@ goto end_rename; new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de); if (new_bh) { - new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */ + new_inode = iget (new_dir->i_sb, le32_to_cpu(new_de->inode)); if (!new_inode) { brelse (new_bh); new_bh = NULL; diff -u --recursive --new-file dist-2.1.25/fs/filesystems.c linux/fs/filesystems.c --- dist-2.1.25/fs/filesystems.c Sun Jan 26 12:38:51 1997 +++ linux/fs/filesystems.c Sun Feb 2 19:11:08 1997 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,10 @@ #ifdef CONFIG_UFS_FS init_ufs_fs(); +#endif + +#ifdef CONFIG_LO_FS + init_lo_fs(); #endif #ifdef CONFIG_ROMFS_FS diff -u --recursive --new-file dist-2.1.25/fs/inode.c linux/fs/inode.c --- dist-2.1.25/fs/inode.c Tue Jan 21 01:19:51 1997 +++ linux/fs/inode.c Sun Feb 2 16:54:00 1997 @@ -145,13 +145,13 @@ __wait_on_inode(inode); } -static inline void lock_inode(struct inode * inode) +void lock_inode(struct inode * inode) { wait_on_inode(inode); inode->i_lock = 1; } -static inline void unlock_inode(struct inode * inode) +void unlock_inode(struct inode * inode) { inode->i_lock = 0; wake_up(&inode->i_wait); @@ -159,7 +159,8 @@ /* * Note that we don't want to disturb any wait-queues when we discard - * an inode. + * an inode. Note also that the inode must be locked when clear_inode + * is called. * * Argghh. Got bitten by a gcc problem with inlining: no way to tell * the compiler that the inline asm function 'memset' changes 'inode'. @@ -168,13 +169,18 @@ * * The solution is the weird use of 'volatile'. Ho humm. Have to report * it to the gcc lists, and hope we can do this more cleanly some day.. + * + * Doh!!! This has been another one of those places where races are + * bound to occur. Just remember that the inode must remain locked + * whenever we can sleep... Please!!! --blah */ void clear_inode(struct inode * inode) { struct wait_queue * wait; - truncate_inode_pages(inode, 0); - wait_on_inode(inode); + if (!inode->i_lock) + printk(KERN_DEBUG "VFS: clear_inode called with !i_lock\n"); + truncate_inode_pages(inode, 0); /* may sleep */ if (IS_WRITABLE(inode)) { if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->drop(inode); @@ -185,6 +191,7 @@ if (inode->i_count) nr_free_inodes++; memset(inode,0,sizeof(*inode)); + inode->i_lock = 1; ((volatile struct inode *) inode)->i_wait = wait; insert_inode_free(inode); } @@ -202,7 +209,9 @@ continue; if (inode->i_count || inode->i_dirt || inode->i_lock) return 0; + lock_inode(inode); clear_inode(inode); + unlock_inode(inode); } return 1; } @@ -395,7 +404,9 @@ kdevname(dev)); continue; } + lock_inode(inode); clear_inode(inode); + unlock_inode(inode); } } @@ -441,7 +452,9 @@ } if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) { - inode->i_sb->s_op->put_inode(inode); + inode->i_lock = 1; + inode->i_sb->s_op->put_inode(inode); /* sleeps here were once bad */ + unlock_inode(inode); if (!inode->i_nlink) return; } @@ -523,6 +536,7 @@ if (best->i_count) goto repeat; found_good: + lock_inode(best); clear_inode(best); best->i_count = 1; best->i_nlink = 1; @@ -530,6 +544,7 @@ best->i_sem.count = 1; best->i_ino = ++ino; best->i_dev = 0; + unlock_inode(best); nr_free_inodes--; if (nr_free_inodes < 0) { printk ("VFS: get_empty_inode: bad free inode count.\n"); @@ -565,7 +580,7 @@ return inode; } -struct inode *__iget(struct super_block * sb, int nr, int crossmntp) +struct inode *iget(struct super_block * sb, int nr) { static struct wait_queue * update_wait = NULL; struct inode_hash_entry * h; @@ -615,19 +630,24 @@ iput(inode); goto repeat; } - if (crossmntp && inode->i_mount) { - struct inode * tmp = inode->i_mount; - tmp->i_count++; - iput(inode); - inode = tmp; - wait_on_inode(inode); - } if (empty) iput(empty); return_it: while (h->updating) sleep_on(&update_wait); + return inode; +} + +struct inode *traverse_mntp ( struct inode *inode ) +{ + while (inode->i_mount) { + struct inode * tmp = inode->i_mount; + tmp->i_count++; + iput(inode); + inode = tmp; + wait_on_inode(inode); + } return inode; } diff -u --recursive --new-file dist-2.1.25/fs/lo/Makefile linux/fs/lo/Makefile --- dist-2.1.25/fs/lo/Makefile Wed Dec 31 19:00:00 1969 +++ linux/fs/lo/Makefile Sun Feb 2 16:39:11 1997 @@ -0,0 +1,15 @@ +# +# Makefile for the linux lofs-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := lo.o +O_OBJS := inode.o + +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file dist-2.1.25/fs/lo/inode.c linux/fs/lo/inode.c --- dist-2.1.25/fs/lo/inode.c Wed Dec 31 19:00:00 1969 +++ linux/fs/lo/inode.c Tue Feb 4 06:09:23 1997 @@ -0,0 +1,718 @@ +/* + * linux/fs/lo/inode.c + * + * Copyright (C) 1996, 1997 Benjamin LaHaise + * + * lofs v0.8 - a loopback filesystem for linux 2.1.25 + * + * Based on linux/fs/nfs/inode.c and others. + * + * This is FREE software with NO WARRANTY. See the file COPYING for details. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct file_system_type lo_fs_type; +static struct super_operations lo_sops; +static struct inode_operations lo_iops; + +static void lo_put_super(struct super_block *); + +#define DEBUG +#ifdef DEBUG +#define dprintk printk +#else +#define dprintk (void) +#endif + +static void checkinode ( struct inode *ino, char *msg) +{ + if (ino) { + if (ino->i_count <= 0) + printk(KERN_WARNING "lo: checkinode(%ld) - i_count is %d - %s\n", ino->i_ino, ino->i_count, msg); + if (!ino->u.lo_i.inode) + printk(KERN_WARNING "lo: checkinode(%ld) - underlying is NULL! (%s)\n", ino->i_ino, msg); + else if (ino->u.lo_i.inode->i_count <= 0) + printk(KERN_WARNING "lo: checkinode(%ld) - underlying i_count is %d (%s)\n", ino->i_ino, ino->u.lo_i.inode->i_count, msg); + } + else + printk(KERN_WARNING "lo: checkinode - inode is NULL! (%s)\n", msg); +} + +static void lo_update_inode ( struct inode *dest, struct inode *src ) +{ + /*dest->i_dev = src->i_dev;*/ /* methinks so? */ + + dest->i_mode = src->i_mode; + dest->i_nlink = src->i_nlink; + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_size = src->i_size; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blksize = src->i_blksize; + dest->i_blocks = src->i_blocks; +} + +/* + * lo needs to be able to 'automount' filesystems that are underlying whatever + * is being looped back... i.e. my /home has /home/dot1 and /home/dot2 mounted + * beneath it, so using lo to loopback mount /home has to deal with the filesystem + * from /, /home/dot1 and /home/dot2. This whole mess is dealt with by automagically + * creating a new superblock for the superblocks found as we're traversing the fs. + * It would be nice to use different inodes for the underlying inodes, but that would + * be difficult. + */ +static struct super_block *lo_automount ( struct super_block *sb ) +{ + struct super_block *s; + kdev_t dev; + + if (!(dev = get_unnamed_dev())) { + printk(KERN_ERR "lo: no unnamed devices\n"); + return NULL; + } + for (s = 0+super_blocks ;; s++) { + if (s >= NR_SUPER+super_blocks) { + printk(KERN_ERR "lo: no free super blocks\n"); + return NULL; + } + if (!(s->s_dev)) + break; + } + + s->s_dev = dev; + s->s_flags = sb->s_flags; + s->s_covered = NULL; + s->s_rd_only = 0; + s->s_dirt = 0; + s->s_type = &lo_fs_type; + + return s; +} + +static struct super_block *lo_find_automount_sb ( struct super_block *sb, struct super_block *target ) +{ + struct super_block *cur_sb = sb; + for ( cur_sb = sb; cur_sb->u.lo_sb.s_sb != target; cur_sb = cur_sb->u.lo_sb.s_lo_next) + ; + + if (!cur_sb && sb->u.lo_sb.s_automount_enabled) + cur_sb = lo_automount(target); + + return cur_sb; +} + +static int lo_notify_change ( struct inode *ino, struct iattr *ia ) +{ + int ret; + + checkinode(ino, "lo_notify_change"); + dprintk("lo_notify_change\n"); + if (ino->u.lo_i.inode->i_sb && + ino->u.lo_i.inode->i_sb->s_op && + ino->u.lo_i.inode->i_sb->s_op->notify_change) { + ret = ino->u.lo_i.inode->i_sb->s_op->notify_change(ino->u.lo_i.inode, ia); + if (ret) + return ret; + } else { + if ((ret = inode_change_ok(ino->u.lo_i.inode, ia)) != 0) + return ret; + + inode_setattr(ino->u.lo_i.inode, ia); + } + + lo_update_inode(ino, ino->u.lo_i.inode); + checkinode(ino, "post lo_notify_change"); + return 0; +} + +static int lo_create ( struct inode *dir, const char *name, int namelen, int mode, struct inode **result ) +{ + int err = -EACCES; + checkinode(dir, "lo_create"); + dprintk("lo_create\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->create) { + dir->u.lo_i.inode->i_count++; + down(&dir->u.lo_i.inode->i_sem); + err = dir->u.lo_i.inode->i_op->create(dir->u.lo_i.inode, name, namelen, mode, result); + up(&dir->u.lo_i.inode->i_sem); + if (!err && ((*result)->i_sb == dir->u.lo_i.inode->i_sb) && (S_ISDIR((*result)->i_mode) || S_ISLNK((*result)->i_mode))) { + struct inode *inode = *result; + if (!(*result = iget(dir->i_sb, inode->i_ino))) + err = -EACCES; /* should be impossible??? */ + iput(inode); + checkinode(*result, "lo_create - res"); + } + } + checkinode(dir, "post lo_create"); + iput(dir); + return err; +} + +static int lo_link ( struct inode *oldinode, struct inode *dir, const char *name, int namelen ) +{ + int err = -EPERM; + checkinode(dir, "lo_link-dir"); + checkinode(oldinode, "lo_link-oldinode"); + dprintk("lo_link\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->link) { + dir->u.lo_i.inode->i_count++; + oldinode->u.lo_i.inode->i_count++; + down(&dir->u.lo_i.inode->i_sem); + err = dir->u.lo_i.inode->i_op->link(oldinode->u.lo_i.inode, dir->u.lo_i.inode, name, namelen); + up(&dir->u.lo_i.inode->i_sem); + } + checkinode(dir, "post lo_link-dir"); + checkinode(oldinode, "post lo_link-oldinode"); + iput(oldinode); + iput(dir); + return err; +} + +static int lo_unlink ( struct inode *dir, const char *name, int namelen ) +{ + int err = -EPERM; + checkinode(dir, "lo_unlink-dir"); + dprintk("lo_unlink\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->unlink) { + dir->u.lo_i.inode->i_count++; + err = dir->u.lo_i.inode->i_op->unlink(dir->u.lo_i.inode, name, namelen); + } + checkinode(dir, "post lo_unlink-dir"); + iput(dir); + return err; +} + +static int lo_symlink ( struct inode *dir, const char *name, int namelen, const char *oldname ) +{ + int err = -EPERM; + checkinode(dir, "lo_symlink-dir"); + dprintk("lo_symlink\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->symlink) { + dir->u.lo_i.inode->i_count++; + err = dir->u.lo_i.inode->i_op->symlink(dir->u.lo_i.inode, name, namelen, oldname); + } + checkinode(dir, "post lo_symlink-dir"); + iput(dir); + return err; +} + +static int lo_mkdir ( struct inode *dir, const char *name, int namelen, int mode ) +{ + int err = -EPERM; + checkinode(dir, "lo_mkdir-dir"); + dprintk("lo_notify_mkdir\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->mkdir) { + dir->u.lo_i.inode->i_count++; + down(&dir->u.lo_i.inode->i_sem); + err = dir->u.lo_i.inode->i_op->mkdir(dir->u.lo_i.inode, name, namelen, mode); + up(&dir->u.lo_i.inode->i_sem); + } + checkinode(dir, "post lo_mkdir-dir"); + iput(dir); + return err; +} + +static int lo_rmdir ( struct inode *dir, const char *name, int namelen ) +{ + int err = -EPERM; + checkinode(dir, "lo_rmdir-dir"); + dprintk("lo_rmdir\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->rmdir) { + dir->u.lo_i.inode->i_count++; + err = dir->u.lo_i.inode->i_op->rmdir(dir->u.lo_i.inode, name, namelen); + } + checkinode(dir, "post lo_rmdir-dir"); + iput(dir); + return err; +} + +static int lo_mknod ( struct inode *dir, const char *name, int namelen, int mode, int dev ) +{ + int err = -EPERM; + checkinode(dir, "lo_mknod-dir"); + dprintk("lo_mknod\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->mknod) { + dir->u.lo_i.inode->i_count++; + down(&dir->u.lo_i.inode->i_sem); + err = dir->u.lo_i.inode->i_op->mknod(dir->u.lo_i.inode, name, namelen, mode, dev); + up(&dir->u.lo_i.inode->i_sem); + } + checkinode(dir, "post lo_mknod-dir"); + iput(dir); + return err; +} + +static int lo_rename ( struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len, int must_be_dir ) +{ + int err = -EPERM; + checkinode(old_dir, "lo_rename-old_dir"); + checkinode(new_dir, "lo_rename-new_dir"); + dprintk("lo_rename\n"); + if (old_dir->u.lo_i.inode->i_op && + old_dir->u.lo_i.inode->i_op->rename) { + old_dir->u.lo_i.inode->i_count++; + new_dir->u.lo_i.inode->i_count++; + down(&new_dir->u.lo_i.inode->i_sem); + err = old_dir->u.lo_i.inode->i_op->rename( + old_dir->u.lo_i.inode, old_name, old_len, + new_dir->u.lo_i.inode, new_name, new_len, must_be_dir); + up(&new_dir->u.lo_i.inode->i_sem); + } + checkinode(old_dir, "post lo_rename-old_dir"); + checkinode(new_dir, "post lo_rename-new_dir"); + iput(old_dir); + iput(new_dir); + return err; +} + +static int lo_readlink ( struct inode *dir, char *buf, int bufsiz ) +{ + int err = -EINVAL; + checkinode(dir, "lo_readlink-dir"); + dprintk("lo_readlink\n"); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->readlink) { + dir->u.lo_i.inode->i_count++; + err = dir->u.lo_i.inode->i_op->readlink(dir->u.lo_i.inode, buf, bufsiz); + } + checkinode(dir, "post lo_readlink-dir"); + iput(dir); + return err; +} + +/* kludgey - replace when up/down problem fixed */ +static void lo_truncate ( struct inode *inode ) +{ + checkinode(inode, "lo_truncate"); + printk(KERN_WARNING "lo_truncate - AAARRRGGGHHH!!!\n"); +#if 0 + struct iattr newattrs; + + dprintk("lo_truncate\n"); + down(&inode->u.lo_i.inode->i_sem); + newattrs.ia_size = inode->i_size; + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + notify_change(inode->u.lo_i.inode, &newattrs); + vmtruncate(inode->u.lo_i.inode, inode->i_size); + if (inode->u.lo_i.inode->i_op && + inode->u.lo_i.inode->i_op->truncate) + inode->u.lo_i.inode->i_op->truncate(inode->u.lo_i.inode); + up(&inode->u.lo_i.inode->i_sem); +#endif + iput(inode); +} + +static int lo_lookup ( struct inode *dir, const char *name, int len, struct inode **result ) +{ + int err = -ENOTDIR; + checkinode(dir, "lo_lookup"); + dprintk("lo_lookup(%ld)\n", dir->i_ino); + if (dir->u.lo_i.inode->i_op && + dir->u.lo_i.inode->i_op->lookup) { + dir->u.lo_i.inode->i_count++; + err = dir->u.lo_i.inode->i_op->lookup(dir->u.lo_i.inode, name, len, result); + if (!err && ((*result)->i_sb == dir->u.lo_i.inode->i_sb) && (S_ISDIR((*result)->i_mode)/* || S_ISLNK((*result)->i_mode)*/)) { + struct inode *inode = *result; + int before = inode->i_count; + if (!(*result = iget(dir->i_sb, inode->i_ino))) + err = -EACCES; /* should be impossible??? */ + if ((*result)->i_lock) + printk(KERN_WARNING "lo_lookup: DOH! inode (%ld use %d) is locked (uh-oh)\n", (*result)->i_ino, (*result)->i_count); + checkinode(*result, "lo_lookup - result"); + if( (((*result)->i_count == 1) && (inode->i_count != (before+1))) || + (((*result)->i_count > 1) && (inode->i_count != before)) ) + printk("lo_lookup - i_count %d - under is %d, was %d\n", (*result)->i_count, inode->i_count, before); + iput(inode); + if (!inode->i_count) + printk("lo_lookup - i_count now zero, was %d\n", before); + checkinode(*result, "lo_lookup - result2"); + } + } +#ifdef DEBUG + if (!err) + dprintk("lo_lookup: got %ld\n", (*result)->i_ino); +#endif + checkinode(dir, "post lo_lookup"); + iput(dir); + return err; +} + +/* inode is from lo, dir could be anything */ +int lo_follow_link ( struct inode *dir, struct inode *inode, int flag, int mode, struct inode **result ) +{ + int err = 0; + checkinode(inode, "lo_follow_link - inode"); + if (inode->u.lo_i.inode->i_op && + inode->u.lo_i.inode->i_op->follow_link) { + dir->i_count++; + inode->u.lo_i.inode->i_count++; + err = inode->u.lo_i.inode->i_op->follow_link(dir, inode->u.lo_i.inode, flag, mode, result); + if (!err && ((*result)->i_sb == inode->u.lo_i.inode->i_sb) && (S_ISDIR((*result)->i_mode) || S_ISLNK((*result)->i_mode))) { + struct inode *ino = *result; + if (!(*result = iget(inode->i_sb, ino->i_ino))) + err = -EACCES; /* should be impossible??? */ + if ((*result)->i_lock) + printk(KERN_WARNING "lo_follow_link: DOH! inode (%ld use %d) is locked (uh-oh)\n", (*result)->i_ino, (*result)->i_count); + iput(ino); + checkinode(*result, "lo_follow_link - result"); + } + } + else { + *result = inode; + inode->i_count ++; + } + checkinode(inode, "post lo_follow_link - inode"); + iput(dir); + iput(inode); + return err; +} + +static int lo_open ( struct inode *inode, struct file *file ) +{ + int error = 0; + checkinode(inode, "lo_open"); + if (!file) { + printk(KERN_WARNING "lo_open: Doh! file is NULL...\n"); + return -EINVAL; + } + file->private_data = NULL; + if (S_ISDIR(inode->i_mode)) { + struct file *filp; + dprintk("lo_open: - is a directory.... (hmmm)\n"); + filp = get_empty_filp(); + if (filp) { + dprintk("lo_open: got filp\n"); + file->private_data = filp; + if (!file->f_inode) + printk(KERN_WARNING "lo_open: what is happenning? - f_inode is NULL!!!\n"); + if (file->f_inode != inode) + printk(KERN_WARNING "lo_open: what is happenning? - f_inode is not the same as inode!!!\n"); + filp->f_inode = file->f_inode->u.lo_i.inode; + filp->f_inode->i_count ++; + + dprintk("lo_open: got f_inode\n"); + filp->f_mode = file->f_mode; + filp->f_flags = file->f_flags; + filp->f_pos = file->f_pos; + filp->f_reada = file->f_reada; + if (filp->f_inode->i_op) + filp->f_op = filp->f_inode->i_op->default_file_ops; + else + filp->f_op = NULL; + dprintk("lo_open: pre open\n"); + if (filp->f_op && filp->f_op->open) + error = filp->f_op->open(filp->f_inode, filp); + filp->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + dprintk("lo_open: post open\n"); + if (error) { + filp->f_count--; + printk(KERN_WARNING "lo_open: error(%d)\n", error); + } + } + else + error = -ENFILE; + } + else { + printk(KERN_WARNING "lo_open: - is a file... DOH!!!!!\n"); + error = -EOPNOTSUPP; + } + checkinode(inode, "post lo_open"); + dprintk("lo_open: done (%d)\n", error); + return error; +} + +static void lo_release ( struct inode *inode, struct file *file ) +{ + checkinode(inode, "lo_release"); + dprintk("lo_release\n"); + if (file) { +#if 0 + printk(KERN_WARNING "lo_release (%d):%ld (%d,%d)\n", inode->u.lo_i.inode->i_dev, inode->i_ino, file->f_count, + ((struct file *)file->private_data)->f_count); +#endif + fput(file->private_data, inode->u.lo_i.inode); + } + dprintk("lo_release done\n"); + checkinode(inode, "post lo_release"); +} + +static void lo_read_inode(struct inode * inode) +{ + dprintk("lo_read_inode(%ld)\n", inode->i_ino); + inode->u.lo_i.inode = iget(inode->i_sb->u.lo_sb.s_sb, inode->i_ino); + if (!inode->u.lo_i.inode) + printk(KERN_ERR "lo: Doh! - lo_read_inode couldn't iget something happy\n"); + lo_update_inode(inode, inode->u.lo_i.inode); + inode->i_op = &lo_iops; + if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + else if (!S_ISDIR(inode->i_mode) && !S_ISLNK(inode->i_mode)) + printk(KERN_ERR "lo: lo_read_inode: Doh! - not a directory!!!\n"); + + checkinode(inode, "lo_read_inode"); +} + +static void lo_put_inode(struct inode * inode) +{ + struct inode *ino = inode->u.lo_i.inode; +#if 0 + inode->i_lock = 1; +#endif +#if 0 + printk("lo_put_inode(%ld): %d %d\n", inode->i_ino, inode->i_count, inode->u.lo_i.inode->i_count); +#endif + checkinode(inode, "lo_put_inode"); + if (inode->i_count != 1) + printk(KERN_WARNING "lo_put_inode(%ld): i_count is %d\n", inode->i_ino, inode->i_count); + if (ino) + iput(ino); +#if 0 + clear_inode(inode); + inode->i_lock = 1; /* clear_inode wipes i_lock */ +#endif + unlock_inode(inode); +} + +void lo_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + dprintk("lo_statfs\n"); + if (sb->u.lo_sb.s_sb->s_op && sb->u.lo_sb.s_sb->s_op->statfs) + sb->u.lo_sb.s_sb->s_op->statfs(sb->u.lo_sb.s_sb, buf, bufsiz); +} + +int lo_readpage ( struct inode *inode, struct page *page ) +{ + printk(KERN_WARNING "lo_readpage\n"); + if (inode->u.lo_i.inode->i_op) + return inode->u.lo_i.inode->i_op->readpage(inode->u.lo_i.inode, page); + return -EOPNOTSUPP; +} + +int lo_writepage ( struct inode *inode, struct page *page ) +{ + printk(KERN_WARNING "lo_writepage\n"); + if (inode->u.lo_i.inode->i_op) + return inode->u.lo_i.inode->i_op->writepage(inode->u.lo_i.inode, page); + return -EOPNOTSUPP; +} + +int lo_bmap ( struct inode *inode, int block ) +{ + printk(KERN_WARNING "lo_bmap\n"); +#if 0 + if ((inode->u.lo_i.inode->i_op) && (inode->u.lo_i.inode->i_op->bmap)) + return inode->u.lo_i.inode->i_op->bmap(inode->u.lo_i.inode, block); +#endif + return -EINVAL; +} + +static long lo_dir_read ( struct inode *inode, struct file *file, char *buf, unsigned long count ) +{ + printk(KERN_WARNING "lo_read - on a dir???\n"); + return -EISDIR; +} + +static int lo_readdir ( struct inode *inode, struct file *file, void *dirent, filldir_t filldir ) +{ + int err = -EOPNOTSUPP; + + checkinode(inode, "lo_readdir"); + dprintk("lo_readdir\n"); + if (!file) + printk(KERN_WARNING "lo_readdir: What???? file is NULL!!!\n"); + else if (file->private_data && + ((struct file *)file->private_data)->f_op && + ((struct file *)file->private_data)->f_op->readdir) + err = ((struct file * )file->private_data)->f_op->readdir(inode->u.lo_i.inode, file->private_data, dirent, filldir); + checkinode(inode, "post lo_readdir"); + + return err; +} + +static int lo_parse_options ( struct super_block *sb, char *options ) +{ + int ret; + while ( *options ) { +#if 0 + if ( !strncmp( "dir=", options, 4 ) ) { + dprintk("lo: using directory: %s\n", options+4); + ret = _namei(options+4, NULL, 1, &sb->u.lo_sb.s_rootinode); + return ret; + } + else +#endif + { + printk(KERN_WARNING "lo: unrecognized options '%s'\n", options); + return -1; + } + } + return 0; +} + +/* + * The way this works is that the mount process passes a structure + * in the data argument which contains an open socket to the NFS + * server and the root file handle obtained from the server's mount + * daemon. We stash these away in the private superblock fields. + * Later we can add other mount parameters like caching values. + */ + +struct super_block *lo_read_super(struct super_block *sb, + void *raw_data, int silent, + const char *dev_name) +{ + int ret; + + sb->u.lo_sb.s_sb = NULL; + sb->u.lo_sb.s_rootinode = NULL; + MOD_INC_USE_COUNT; + lock_super(sb); + if (!raw_data) { + printk(KERN_WARNING "lo_read_super: missing data argument\n"); + sb->s_dev = 0; + MOD_DEC_USE_COUNT; + return NULL; + } + + ret = lo_parse_options(sb, raw_data); + if (!ret) + ret = namei(dev_name, &sb->u.lo_sb.s_rootinode); + if (ret) { + unlock_super(sb); + printk(KERN_WARNING "lo_read_super: namei failed? (ret = %d)\n", ret); + MOD_DEC_USE_COUNT; + return NULL; + } + sb->u.lo_sb.s_sb = sb->u.lo_sb.s_rootinode->i_sb; + + unlock_super(sb); + sb->s_op = &lo_sops; + sb->s_mounted = iget(sb, sb->u.lo_sb.s_rootinode->i_ino); + if (!sb->s_mounted) { + printk(KERN_WARNING "lo_read_super: iget failed\n"); + iput(sb->u.lo_sb.s_rootinode); + MOD_DEC_USE_COUNT; + return NULL; + } + return sb; +} + +void lo_put_super ( struct super_block *sb ) +{ + dprintk("lo_put_super\n"); + lock_super(sb); + iput(sb->u.lo_sb.s_rootinode); + sb->s_dev = 0; + unlock_super(sb); + dprintk("lo: released super\n"); + MOD_DEC_USE_COUNT; +} + +/*----*/ +static struct super_operations lo_sops = { + lo_read_inode, /* read inode */ + lo_notify_change, /* notify change */ + NULL, /* write inode */ + lo_put_inode, /* put inode */ + lo_put_super, /* put superblock */ + NULL, /* write superblock */ + lo_statfs, /* stat filesystem */ + NULL +}; + +static struct file_operations lo_fops = { + NULL, /* llseek */ + lo_dir_read, /* read */ + NULL, /* write */ + lo_readdir, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + lo_open, /* open */ + lo_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + +static struct inode_operations lo_iops = { + &lo_fops, /* default file operations */ + lo_create, /* create */ + lo_lookup, /* lookup */ + lo_link, /* link */ + lo_unlink, /* unlink */ + lo_symlink, /* symlink */ + lo_mkdir, /* mkdir */ + lo_rmdir, /* rmdir */ + lo_mknod, /* mknod */ + lo_rename, /* rename */ + lo_readlink, /* readlink */ + lo_follow_link, /* follow_link */ + lo_readpage, /* readpage */ + lo_writepage, /* writepage */ + lo_bmap, /* bmap */ + lo_truncate, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +/* Every kernel module contains stuff like this. */ + +static struct file_system_type lo_fs_type = { + lo_read_super, "lo", 0, NULL +}; + +int init_lo_fs(void) +{ + return register_filesystem(&lo_fs_type); +} + +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_lo_fs()) == 0) + register_symtab(0); + return status; +} + +void cleanup_module(void) +{ + unregister_filesystem(&lo_fs_type); +} + +#endif diff -u --recursive --new-file dist-2.1.25/fs/minix/namei.c linux/fs/minix/namei.c --- dist-2.1.25/fs/minix/namei.c Tue Dec 17 07:02:51 1996 +++ linux/fs/minix/namei.c Sun Feb 2 18:23:01 1997 @@ -697,7 +697,7 @@ retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ + old_inode = iget(old_dir->i_sb, old_de->inode); if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) @@ -709,7 +709,7 @@ goto end_rename; new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); if (new_bh) { - new_inode = __iget(new_dir->i_sb, new_de->inode, 0); + new_inode = iget(new_dir->i_sb, new_de->inode); if (!new_inode) { brelse(new_bh); new_bh = NULL; diff -u --recursive --new-file dist-2.1.25/fs/namei.c linux/fs/namei.c --- dist-2.1.25/fs/namei.c Sun Jan 26 12:38:52 1997 +++ linux/fs/namei.c Wed Feb 5 01:13:27 1997 @@ -160,7 +160,7 @@ struct inode ** result) { struct super_block * sb; - int perm; + int perm, err = 0; *result = NULL; if (!dir) @@ -168,15 +168,20 @@ /* check permissions before traversing mount-points */ perm = permission(dir,MAY_EXEC); if (len==2 && get_unaligned((u16 *) name) == 0x2e2e) { - if (dir == current->fs->root) { - *result = dir; - return 0; - } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) { - iput(dir); - dir = sb->s_covered; - if (!dir) - return -ENOENT; - dir->i_count++; + /* this is ugly - we have to check for current's root dir as another fs may be mounted on top of it -blah */ + for (;;) { + if (dir == current->fs->root) { + *result = traverse_mntp(dir); + return 0; + } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) { + if (sb->s_covered) + sb->s_covered->i_count++; /* avoid the race */ + iput(dir); + dir = sb->s_covered; + if (!dir) + return -ENOENT; + } else + break; } } if (!dir->i_op || !dir->i_op->lookup) { @@ -191,7 +196,10 @@ *result = dir; return 0; } - return dir->i_op->lookup(dir, name, len, result); + err = dir->i_op->lookup(dir, name, len, result); + if (!err) + *result = traverse_mntp(*result); + return err; } int follow_link(struct inode * dir, struct inode * inode, @@ -232,7 +240,7 @@ } if ((c = *pathname) == '/') { iput(base); - base = current->fs->root; + base = traverse_mntp(current->fs->root); /* root may be mounted on top of */ pathname++; base->i_count++; } diff -u --recursive --new-file dist-2.1.25/fs/open.c linux/fs/open.c --- dist-2.1.25/fs/open.c Sun Jan 26 12:38:53 1997 +++ linux/fs/open.c Wed Jan 29 00:30:11 1997 @@ -290,7 +290,7 @@ asmlinkage int sys_chdir(const char * filename) { - struct inode * inode; + struct inode * inode, *tmp; int error; lock_kernel(); @@ -306,8 +306,9 @@ iput(inode); goto out; } - iput(current->fs->pwd); + tmp = current->fs->pwd; current->fs->pwd = inode; + iput(tmp); error = 0; out: unlock_kernel(); @@ -316,7 +317,7 @@ asmlinkage int sys_fchdir(unsigned int fd) { - struct inode * inode; + struct inode * inode, *tmp; struct file * file; int error = -EBADF; @@ -331,9 +332,10 @@ goto out; if ((error = permission(inode,MAY_EXEC)) != 0) goto out; - iput(current->fs->pwd); + tmp = current->fs->pwd; current->fs->pwd = inode; inode->i_count++; + iput(tmp); error = 0; out: unlock_kernel(); diff -u --recursive --new-file dist-2.1.25/fs/proc/array.c linux/fs/proc/array.c --- dist-2.1.25/fs/proc/array.c Wed Jan 29 00:11:41 1997 +++ linux/fs/proc/array.c Wed Feb 5 01:08:15 1997 @@ -230,8 +230,11 @@ kstat.pswpin, kstat.pswpout, sum); - for (i = 0 ; i < NR_IRQS ; i++) + sum = 0; + for (i = 0 ; i < NR_IRQS ; i++) { len += sprintf(buffer + len, " %u", kstat.interrupts[i]); + sum += kstat.lost_interrupts[i]; + } len += sprintf(buffer + len, "\nctxt %u\n" "btime %lu\n" @@ -239,6 +242,10 @@ kstat.context_swtch, xtime.tv_sec - jiffies / HZ, total_forks); + len += sprintf(buffer + len, "lost_intr %u", sum); + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(buffer + len, " %u", kstat.lost_interrupts[i]); + buffer[len++] = '\n' return len; } diff -u --recursive --new-file dist-2.1.25/fs/super.c linux/fs/super.c --- dist-2.1.25/fs/super.c Sun Jan 26 12:38:54 1997 +++ linux/fs/super.c Tue Feb 4 04:33:30 1997 @@ -502,7 +502,8 @@ return err; } -static struct super_block * read_super(kdev_t dev,const char *name,int flags, +static struct super_block * read_super(kdev_t dev,const char *dev_name, + const char *name,int flags, void *data, int silent) { struct super_block * s; @@ -527,7 +528,7 @@ } s->s_dev = dev; s->s_flags = flags; - if (!type->read_super(s,data, silent)) { + if (!type->read_super(s, data, silent, dev_name)) { s->s_dev = 0; return NULL; } @@ -722,7 +723,7 @@ iput(dir_i); return -EBUSY; } - sb = read_super(dev,type,flags,data,0); + sb = read_super(dev,dev_name,type,flags,data,0); if (!sb) { iput(dir_i); return -EINVAL; @@ -1020,7 +1021,7 @@ else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { if (!fs_type->requires_dev) continue; - sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); + sb = read_super(ROOT_DEV,NULL,fs_type->name,root_mountflags,NULL,1); if (sb) { inode = sb->s_mounted; inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ diff -u --recursive --new-file dist-2.1.25/fs/sysv/namei.c linux/fs/sysv/namei.c --- dist-2.1.25/fs/sysv/namei.c Wed Jul 3 05:06:03 1996 +++ linux/fs/sysv/namei.c Sun Feb 2 18:23:11 1997 @@ -691,7 +691,7 @@ retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ + old_inode = iget(old_dir->i_sb, old_de->inode); if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) @@ -703,7 +703,7 @@ goto end_rename; new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de); if (new_bh) { - new_inode = __iget(new_dir->i_sb, new_de->inode, 0); + new_inode = iget(new_dir->i_sb, new_de->inode); if (!new_inode) { brelse(new_bh); new_bh = NULL; diff -u --recursive --new-file dist-2.1.25/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- dist-2.1.25/include/asm-i386/bitops.h Sun Jan 5 14:05:16 1997 +++ linux/include/asm-i386/bitops.h Tue Feb 4 23:10:01 1997 @@ -66,7 +66,13 @@ */ extern __inline__ int test_bit(int nr, const SMPVOL void * addr) { - return ((1UL << (nr & 31)) & (((const unsigned int *) addr)[nr >> 5])) != 0; + int oldbit; + + __asm__ __volatile__( + "btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"ir" (nr)); + return oldbit; } /* diff -u --recursive --new-file dist-2.1.25/include/asm-i386/irq.h linux/include/asm-i386/irq.h --- dist-2.1.25/include/asm-i386/irq.h Sun Jan 26 12:38:56 1997 +++ linux/include/asm-i386/irq.h Wed Feb 5 01:34:10 1997 @@ -7,6 +7,7 @@ * (C) 1992, 1993 Linus Torvalds * * IRQ/IPI changes taken from work by Thomas Radke + * Software IRQ masking by Benjamin LaHaise */ #include @@ -22,6 +23,11 @@ #define __STR(x) #x #define STR(x) __STR(x) +#if 0 +#define CLI "movl $~0,"SYMBOL_NAME_STR(sw_irq_mask)"\n\t" +#else +#define CLI /* */ +#endif #define SAVE_ALL \ "cld\n\t" \ @@ -155,25 +161,21 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "sti\n\t" \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ + CLI \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ - "addl $4,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ + "pushl $0\n\t" \ + "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ + "addl $8,%esp\n\t" \ + CLI \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ @@ -194,7 +196,7 @@ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \ "addl $8,%esp\n\t" \ - "cli\n\t" \ + CLI \ "jmp ret_from_sys_call\n"); #endif /* __SMP__ */ @@ -208,25 +210,21 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "sti\n\t" \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ + CLI \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ + "pushl $0\n\t" \ "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ - "addl $4,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ + "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ + "addl $8,%esp\n\t" \ + CLI \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ @@ -245,14 +243,12 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ + CLI \ "jmp ret_from_sys_call\n"); #endif /* _ASM_IRQ_H */ diff -u --recursive --new-file dist-2.1.25/include/asm-i386/system.h linux/include/asm-i386/system.h --- dist-2.1.25/include/asm-i386/system.h Sun Jan 26 12:38:56 1997 +++ linux/include/asm-i386/system.h Wed Feb 5 00:18:53 1997 @@ -1,7 +1,9 @@ #ifndef __ASM_SYSTEM_H #define __ASM_SYSTEM_H +#include #include +#include /* * Entry into gdt where to find first TSS. GDT layout: @@ -82,10 +84,10 @@ "movl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \ "popl %%edx\n\t" \ "ljmp %0\n\t" \ - "sti\n\t" \ : /* no output */ \ :"m" (*(((char *)&next->tss.tr)-4)), \ "c" (next)); \ + sti();\ /* Now maybe reload the debug registers */ \ if(prev->debugreg[7]){ \ loaddebug(prev,0); \ @@ -220,13 +222,44 @@ } #define mb() __asm__ __volatile__ ("" : : :"memory") -#define sti() __asm__ __volatile__ ("sti": : :"memory") -#define cli() __asm__ __volatile__ ("cli": : :"memory") + +/* new singing, dancing software interrupt flags */ +extern SMPVOL unsigned long sw_irq_mask, sw_irqs_pending; +extern void run_sw_irqs ( void ); + +#define cli() __asm__ __volatile__(LOCK_PREFIX "btsl $0,"SYMBOL_NAME_STR(sw_irq_mask) : : :"memory") +#define sti() __asm__ __volatile__(LOCK_PREFIX \ + "btrl $0,"SYMBOL_NAME_STR(sw_irq_mask)"\n\t" \ + "jz 1f\n\t" \ + "call "SYMBOL_NAME_STR(run_sw_irqs) \ + "\n1:\n" \ + : : :"memory") #define save_flags(x) \ + do { x = sw_irq_mask & 1; } while (0) +#define restore_flags(x) __asm__ __volatile__( \ + "testl %0,%0\n\t" \ + "jz 2f\n\t" \ + LOCK_PREFIX "btsl $0,"SYMBOL_NAME_STR(sw_irq_mask)"\n\t" \ + "jmp 1f\n" \ + "2:\n\t" \ + "btrl $0,"SYMBOL_NAME_STR(sw_irq_mask)"\n\t" \ + "jz 1f\n\t" \ + "call "SYMBOL_NAME_STR(run_sw_irqs) \ + "\n1:\n" \ + : :"ir" (x) :"memory") +#if 0 +#define restore_flags(x) \ + do { if (x) cli(); else sti(); } while (0) +#endif + +#define hw_sti() __asm__ __volatile__ ("sti": : :"memory") +#define hw_cli() __asm__ __volatile__ ("cli": : :"memory") + +#define hw_save_flags(x) \ __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") -#define restore_flags(x) \ +#define hw_restore_flags(x) \ __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define iret() __asm__ __volatile__ ("iret": : :"memory") diff -u --recursive --new-file dist-2.1.25/include/linux/fs.h linux/include/linux/fs.h --- dist-2.1.25/include/linux/fs.h Sun Jan 26 12:38:58 1997 +++ linux/include/linux/fs.h Tue Feb 4 04:33:57 1997 @@ -230,6 +230,7 @@ #include #include #include +#include #include /* @@ -318,6 +319,7 @@ struct sysv_inode_info sysv_i; struct affs_inode_info affs_i; struct ufs_inode_info ufs_i; + struct lo_inode_info lo_i; struct romfs_inode_info romfs_i; struct socket socket_i; void * generic_ip; @@ -417,6 +419,7 @@ #include #include #include +#include #include struct super_block { @@ -445,6 +448,7 @@ struct sysv_sb_info sysv_sb; struct affs_sb_info affs_sb; struct ufs_sb_info ufs_sb; + struct lo_sb_info lo_sb; struct romfs_sb_info romfs_sb; void *generic_sbp; } u; @@ -517,7 +521,7 @@ }; struct file_system_type { - struct super_block *(*read_super) (struct super_block *, void *, int); + struct super_block *(*read_super) (struct super_block *, void *, int, const char *); const char *name; int requires_dev; struct file_system_type * next; @@ -611,6 +615,8 @@ extern void sync_supers(kdev_t dev); extern int bmap(struct inode * inode,int block); extern int notify_change(struct inode *, struct iattr *); +extern int _namei(const char * pathname, struct inode * base, + int follow_links, struct inode ** res_inode); extern int namei(const char * pathname, struct inode ** res_inode); extern int lnamei(const char * pathname, struct inode ** res_inode); extern int permission(struct inode * inode,int mask); @@ -620,8 +626,11 @@ struct inode ** res_inode, struct inode * base); extern int do_mknod(const char * filename, int mode, dev_t dev); extern int do_pipe(int *); +extern void lock_inode(struct inode * inode); +extern void unlock_inode(struct inode * inode); extern void iput(struct inode * inode); -extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt); +extern struct inode * iget(struct super_block * sb,int nr); +extern struct inode *traverse_mntp(struct inode *inode); extern struct inode * get_empty_inode(void); extern void insert_inode_hash(struct inode *); extern void clear_inode(struct inode *); @@ -660,6 +669,8 @@ extern long generic_file_read(struct inode *, struct file *, char *, unsigned long); extern void put_super(kdev_t dev); +extern kdev_t get_unnamed_dev(void); +extern void put_unnamed_dev(kdev_t dev); unsigned long generate_cluster(kdev_t dev, int b[], int size); unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size); extern kdev_t ROOT_DEV; @@ -687,11 +698,6 @@ extern int inode_change_ok(struct inode *, struct iattr *); extern void inode_setattr(struct inode *, struct iattr *); - -extern inline struct inode * iget(struct super_block * sb,int nr) -{ - return __iget(sb, nr, 1); -} /* kludge to get SCSI modules working */ #include diff -u --recursive --new-file dist-2.1.25/include/linux/kernel_stat.h linux/include/linux/kernel_stat.h --- dist-2.1.25/include/linux/kernel_stat.h Tue Sep 24 05:21:30 1996 +++ linux/include/linux/kernel_stat.h Wed Feb 5 00:34:23 1997 @@ -25,6 +25,7 @@ unsigned int ierrors, oerrors; unsigned int collisions; unsigned int context_swtch; + unsigned int lost_interrupts[NR_IRQS]; }; extern struct kernel_stat kstat; diff -u --recursive --new-file dist-2.1.25/include/linux/lo_fs.h linux/include/linux/lo_fs.h --- dist-2.1.25/include/linux/lo_fs.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/lo_fs.h Sun Feb 2 19:15:13 1997 @@ -0,0 +1,7 @@ +#ifndef _LINUX_LO_FS_H +#define _LINUX_LO_FS_H + +#ifdef __KERNEL__ +extern int init_lo_fs(void); +#endif +#endif diff -u --recursive --new-file dist-2.1.25/include/linux/lo_fs_i.h linux/include/linux/lo_fs_i.h --- dist-2.1.25/include/linux/lo_fs_i.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/lo_fs_i.h Sun Feb 2 16:38:11 1997 @@ -0,0 +1,11 @@ +#ifndef _LO_FS_I +#define _LO_FS_I + +/* + * lo fs inode data in memory + */ +struct lo_inode_info { + struct inode *inode; +}; + +#endif diff -u --recursive --new-file dist-2.1.25/include/linux/lo_fs_sb.h linux/include/linux/lo_fs_sb.h --- dist-2.1.25/include/linux/lo_fs_sb.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/lo_fs_sb.h Sun Feb 2 21:34:47 1997 @@ -0,0 +1,17 @@ +#ifndef _LO_FS_SB +#define _LO_FS_SB + +/* + * lo super-block data + */ +struct lo_sb_info { + struct super_block *s_sb; + struct inode *s_rootinode; + struct super_block *s_lo_next; /* next loopback superblock */ + + unsigned long s_inodes_used; /* number of inodes in use */ + + int s_automount_enabled; +}; + +#endif diff -u --recursive --new-file dist-2.1.25/init/main.c linux/init/main.c --- dist-2.1.25/init/main.c Sun Feb 2 15:26:20 1997 +++ linux/init/main.c Wed Feb 5 01:21:50 1997 @@ -534,6 +534,9 @@ better than 1% */ #define LPS_PREC 8 +extern unsigned long sw_irq_mask, sw_irqs_slow, sw_irqs_running, sw_irq_runs; +extern unsigned long sw_irq_fudges, sw_irq_fudge_tries; + void calibrate_delay(void) { unsigned long ticks, loopbit; @@ -541,6 +544,11 @@ loops_per_sec = (1<<12); + printk( "mask: %08lx slow: %08lx pending: %08lx running: %08lx\n" + "lastrun: %08lx %08lx %08lx %08lx %lu %lu %lu %lu\n" + "fudges: %lu tries: %lu runs: %lu\n", + sw_irq_mask, sw_irqs_slow, sw_irqs_pending, sw_irqs_running, + sw_irq_fudges, sw_irq_fudge_tries, sw_irq_runs); printk("Calibrating delay loop.. "); while (loops_per_sec <<= 1) { /* wait for "start of" clock tick */ diff -u --recursive --new-file dist-2.1.25/kernel/ksyms.c linux/kernel/ksyms.c --- dist-2.1.25/kernel/ksyms.c Sun Jan 26 12:39:01 1997 +++ linux/kernel/ksyms.c Mon Feb 3 11:07:21 1997 @@ -133,7 +133,7 @@ /* filesystem internal functions */ EXPORT_SYMBOL(getname); EXPORT_SYMBOL(putname); -EXPORT_SYMBOL(__iget); +EXPORT_SYMBOL(iget); EXPORT_SYMBOL(iput); EXPORT_SYMBOL(namei); EXPORT_SYMBOL(lnamei); @@ -342,6 +342,8 @@ EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__up); EXPORT_SYMBOL(securelevel); +EXPORT_SYMBOL(get_unnamed_dev); +EXPORT_SYMBOL(put_unnamed_dev); /* all busmice */ EXPORT_SYMBOL(add_mouse_randomness);