diff -ru --new-file linux-1.2.12/arch/i386/config.in linux/arch/i386/config.in
--- linux-1.2.12/arch/i386/config.in	Sat Apr 29 10:48:51 1995
+++ linux/arch/i386/config.in	Tue Aug  1 12:17:54 1995
@@ -221,6 +221,7 @@
 fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
+bool 'Disk QUOTA support' CONFIG_QUOTA y
 
 comment 'character devices'
 
diff -ru --new-file linux-1.2.12/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-1.2.12/fs/binfmt_elf.c	Tue Jun 13 09:06:22 1995
+++ linux/fs/binfmt_elf.c	Tue Aug  1 12:03:51 1995
@@ -405,7 +405,7 @@
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
 			if(retval >= 0)
-				retval = namei(elf_interpreter, &interpreter_inode);
+				retval = namei(elf_interpreter, S_NONE, &interpreter_inode);
 			if(retval >= 0)
 				retval = read_exec(interpreter_inode,0,bprm->buf,128);
 			
@@ -486,6 +486,8 @@
 	current->mm->end_code = 0;
 	current->mm->start_mmap = ELF_START_MMAP;
 	current->mm->mmap = NULL;
+	current->flags &= ~PF_FORKNOEXEC; /* accounting flags */
+        current->io_usage = 0;
 	elf_entry = (unsigned int) elf_ex.e_entry;
 	
 	/* Do this so that we can load the interpreter, if need be.  We will
diff -ru --new-file linux-1.2.12/fs/buffer.c linux/fs/buffer.c
--- linux-1.2.12/fs/buffer.c	Thu Jun  1 12:41:28 1995
+++ linux/fs/buffer.c	Tue Aug  1 12:03:51 1995
@@ -216,6 +216,9 @@
 	sync_supers(dev);
 	sync_inodes(dev);
 	sync_buffers(dev, 0);
+#ifdef CONFIG_QUOTA
+	sync_dquots(dev, -1);
+#endif
 }
 
 int fsync_dev(dev_t dev)
@@ -223,6 +226,9 @@
 	sync_buffers(dev, 0);
 	sync_supers(dev);
 	sync_inodes(dev);
+#ifdef CONFIG_QUOTA
+	sync_dquots(dev, -1);
+#endif
 	return sync_buffers(dev, 1);
 }
 
diff -ru --new-file linux-1.2.12/fs/dquot.c linux/fs/dquot.c
--- linux-1.2.12/fs/dquot.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/dquot.c	Tue Aug  1 12:20:40 1995
@@ -0,0 +1,1020 @@
+/*
+ * QUOTA    implementation of the diskquota system for the LINUX operating
+ *          system. QUOTA is implemented using the BSD systemcall interface as
+ *          the means of communication with the user level. Should work for all
+ *          filesystems because of integration into the VFS layer of the
+ *          operating system. This is based on the Melbourne quota system wich
+ *          uses both user and group quota files.
+ * 
+ *          Main layer of quota management
+ * 
+ * Version: $Id: dquot.c,v 5.1 1995/07/27 12:03:19 mvw Exp mvw $
+ * 
+ * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net> <mvw@cistron.nl>
+ * 
+ *          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.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_QUOTA
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/mount.h>
+
+#include <asm/segment.h>
+#include <sys/sysmacros.h>
+
+#define __DQUOT_VERSION__	"dquot_5.1.0"
+
+static char quotamessage[MAX_QUOTA_MESSAGE];
+static char *quotatypes[] = INITQFNAMES;
+
+static int nr_dquots = 0, nr_free_dquots = 0;
+static struct dquot *hash_table[NR_DQHASH];
+static struct dquot *first_dquot;
+
+static struct wait_queue *dquot_wait = (struct wait_queue *)NULL;
+
+extern void add_dquot_ref(dev_t dev, short type);
+extern void reset_dquot_ptrs(dev_t dev, short type);
+extern void close_fp(struct file *filp);
+
+#ifndef min
+#define min(a,b) ((a) < (b)) ? (a) : (b)
+#endif
+
+/*
+ * Functions for management of the hashlist.
+ */
+static inline int const hashfn(dev_t dev, unsigned int id, short type)
+{
+	return((dev ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
+}
+
+static inline struct dquot **const hash(dev_t dev, unsigned int id, short type)
+{
+	return(hash_table + hashfn(dev, id, type));
+}
+
+static inline int has_quota_enabled(dev_t dev, short type)
+{
+	struct vfsmount *vfsmnt;
+
+	return((vfsmnt = lookup_vfsmnt(dev)) != (struct vfsmount *)NULL &&
+	       (vfsmnt->mnt_quotas[type] != (struct file *)NULL));
+}
+
+static void insert_dquot_free(struct dquot *dquot)
+{
+	dquot->dq_next = first_dquot;
+	dquot->dq_prev = first_dquot->dq_prev;
+	dquot->dq_next->dq_prev = dquot;
+	dquot->dq_prev->dq_next = dquot;
+	first_dquot = dquot;
+}
+
+static void remove_dquot_free(struct dquot *dquot)
+{
+	if (first_dquot == dquot)
+		first_dquot = first_dquot->dq_next;
+	if (dquot->dq_next)
+		dquot->dq_next->dq_prev = dquot->dq_prev;
+	if (dquot->dq_prev)
+		dquot->dq_prev->dq_next = dquot->dq_next;
+	dquot->dq_next = dquot->dq_prev = NODQUOT;
+}
+
+static void insert_dquot_hash(struct dquot *dquot)
+{
+	struct dquot **hash_ent;
+
+	hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+	dquot->dq_hash_next = *hash_ent;
+	dquot->dq_hash_prev = NODQUOT;
+	if (dquot->dq_hash_next)
+		dquot->dq_hash_next->dq_hash_prev = dquot;
+	*hash_ent = dquot;
+}
+
+static void remove_dquot_hash(struct dquot *dquot)
+{
+	struct dquot **hash_ent;
+
+	hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+	if (*hash_ent == dquot)
+		*hash_ent = dquot->dq_hash_next;
+	if (dquot->dq_hash_next)
+		dquot->dq_hash_next->dq_hash_prev = dquot->dq_hash_prev;
+	if (dquot->dq_hash_prev)
+		dquot->dq_hash_prev->dq_hash_next = dquot->dq_hash_next;
+	dquot->dq_hash_prev = dquot->dq_hash_next = NODQUOT;
+}
+
+static void put_last_free(struct dquot *dquot)
+{
+	remove_dquot_free(dquot);
+	dquot->dq_prev = first_dquot->dq_prev;
+	dquot->dq_prev->dq_next = dquot;
+	dquot->dq_next = first_dquot;
+	dquot->dq_next->dq_prev = dquot;
+}
+
+static void grow_dquots(void)
+{
+	struct dquot *dquot;
+	int cnt;
+
+	if (!(dquot = (struct dquot*) get_free_page(GFP_KERNEL)))
+		return;
+	cnt = PAGE_SIZE / sizeof(struct dquot);
+	nr_dquots += cnt;
+	nr_free_dquots += cnt;
+	if (!first_dquot) {
+		dquot->dq_next = dquot->dq_prev = first_dquot = dquot++;
+		cnt--;
+	}
+	for (; cnt; cnt--)
+		insert_dquot_free(dquot++);
+}
+
+/*
+ * Functions for locking and waiting on dquots.
+ */
+static void __wait_on_dquot(struct dquot *dquot)
+{
+	struct wait_queue wait = {current, NULL};
+
+	add_wait_queue(&dquot->dq_wait, &wait);
+repeat:
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (dquot->dq_flags & DQ_LOCKED) {
+		dquot->dq_flags |= DQ_WANT;
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&dquot->dq_wait, &wait);
+	current->state = TASK_RUNNING;
+}
+
+static inline void wait_on_dquot(struct dquot *dquot)
+{
+	if (dquot->dq_flags & DQ_LOCKED)
+		__wait_on_dquot(dquot);
+}
+
+static inline void lock_dquot(struct dquot *dquot)
+{
+	wait_on_dquot(dquot);
+	dquot->dq_flags |= DQ_LOCKED;
+}
+
+static inline void unlock_dquot(struct dquot *dquot)
+{
+	dquot->dq_flags &= ~DQ_LOCKED;
+	if (dquot->dq_flags & DQ_WANT) {
+		dquot->dq_flags &= ~DQ_WANT;
+		wake_up(&dquot->dq_wait);
+	}
+}
+/*
+ * Note that we don't want to disturb any wait-queues when we discard
+ * an dquot.
+ *
+ * FIXME: As soon as we have a nice solution for the inode problem we
+ *		  can also fix this one. I.e. the volatile part.
+ */
+static void clear_dquot(struct dquot * dquot)
+{
+	struct wait_queue *wait;
+
+	wait_on_dquot(dquot);
+	remove_dquot_hash(dquot);
+	remove_dquot_free(dquot);
+	wait = ((volatile struct dquot *) dquot)->dq_wait;
+	if (dquot->dq_count)
+		nr_free_dquots++;
+	memset(dquot, 0, sizeof(*dquot));
+	((volatile struct dquot *) dquot)->dq_wait = wait;
+	insert_dquot_free(dquot);
+}
+
+static void write_dquot(struct dquot *dquot)
+{
+	short type = dquot->dq_type;
+	struct file *filp = dquot->dq_mnt->mnt_quotas[type];
+	unsigned short fs;
+
+	if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
+		return;
+	lock_dquot(dquot);
+	down(&dquot->dq_mnt->mnt_sem);
+	if (filp->f_op->lseek) {
+		if (filp->f_op->lseek(filp->f_inode, filp,
+		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
+			up(&dquot->dq_mnt->mnt_sem);
+			unlock_dquot(dquot);
+			return;
+		}
+	} else
+		filp->f_pos = dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (filp->f_op->write(filp->f_inode, filp,
+	   (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
+		dquot->dq_flags &= ~DQ_MOD;
+	up(&dquot->dq_mnt->mnt_sem);
+	set_fs(fs);
+	unlock_dquot(dquot);
+}
+
+static void read_dquot(struct dquot *dquot)
+{
+	short type = dquot->dq_type;
+	struct file *filp = dquot->dq_mnt->mnt_quotas[type];
+	unsigned short fs;
+
+	if (filp == (struct file *)NULL)
+		return;
+	lock_dquot(dquot);
+	down(&dquot->dq_mnt->mnt_sem);
+	if (filp->f_op->lseek) {
+		if (filp->f_op->lseek(filp->f_inode, filp,
+		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
+			up(&dquot->dq_mnt->mnt_sem);
+			unlock_dquot(dquot);
+			return;
+		}
+	} else
+		filp->f_pos = dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+	up(&dquot->dq_mnt->mnt_sem);
+	set_fs(fs);
+	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
+	    dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)
+		dquot->dq_flags |= DQ_FAKE;
+	unlock_dquot(dquot);
+}
+
+int sync_dquots(dev_t dev, short type)
+{
+	struct dquot *dquot = first_dquot;
+	int i;
+
+	for (i = 0; i < nr_dquots * 2; i++, dquot = dquot->dq_next) {
+		if (!dquot->dq_count || (dev && dquot->dq_dev != dev))
+			continue;
+		if (type != -1 && dquot->dq_type != type)
+			continue;
+		wait_on_dquot(dquot);
+		if (dquot->dq_flags & DQ_MOD)
+			write_dquot(dquot);
+	}
+	return(0);
+}
+
+/*
+ * Trash the cache for a certain type on a device.
+ */
+void invalidate_dquots(dev_t dev, short type)
+{
+	struct dquot *dquot, *next;
+	int cnt;
+
+	next = first_dquot;
+	for (cnt = nr_dquots ; cnt > 0 ; cnt--) {
+		dquot = next;
+		next = dquot->dq_next;
+		if (dquot->dq_dev != dev || dquot->dq_type != type)
+			continue;
+		if (dquot->dq_flags & DQ_LOCKED) {
+			printk("VFS: dquot busy on removed device %d/%d\n", MAJOR(dev), MINOR(dev));
+			continue;
+		}
+		if (dquot->dq_flags & DQ_MOD)
+			write_dquot(dquot);
+		clear_dquot(dquot);
+	}
+}
+
+static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
+{
+	lock_dquot(dquot);
+	dquot->dq_curinodes += number;
+	dquot->dq_flags |= DQ_MOD;
+	unlock_dquot(dquot);
+}
+
+static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number)
+{
+	lock_dquot(dquot);
+	dquot->dq_curblocks += number;
+	dquot->dq_flags |= DQ_MOD;
+	unlock_dquot(dquot);
+}
+
+static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
+{
+	lock_dquot(dquot);
+	if (dquot->dq_curinodes > number)
+		dquot->dq_curinodes -= number;
+	else
+		dquot->dq_curinodes = 0;
+	if (dquot->dq_curinodes < dquot->dq_isoftlimit)
+		dquot->dq_itime = (time_t) 0;
+	dquot->dq_flags &= ~DQ_INODES;
+	dquot->dq_flags |= DQ_MOD;
+	unlock_dquot(dquot);
+}
+
+static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number)
+{
+	lock_dquot(dquot);
+	if (dquot->dq_curblocks > number)
+		dquot->dq_curblocks -= number;
+	else
+		dquot->dq_curblocks = 0;
+	if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
+		dquot->dq_btime = (time_t) 0;
+	dquot->dq_flags &= ~DQ_BLKS;
+	dquot->dq_flags |= DQ_MOD;
+	unlock_dquot(dquot);
+}
+
+static int check_idq(struct dquot *dquot, short type, u_long short inodes)
+{
+	if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
+		return(QUOTA_OK);
+	if (dquot->dq_ihardlimit &&
+	   (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit) {
+		if (!(dquot->dq_flags & DQ_INODES)) {
+			sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n",
+			        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+			tty_write_message(current->tty, quotamessage);
+			dquot->dq_flags |= DQ_INODES;
+		}
+		return(NO_QUOTA);
+	}
+	if (dquot->dq_isoftlimit &&
+	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
+	    dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime) {
+		sprintf(quotamessage, "%s: warning, %s file quota exceeded to long.\r\n",
+		        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+		tty_write_message(current->tty, quotamessage);
+		return(NO_QUOTA);
+	}
+	if (dquot->dq_isoftlimit &&
+	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
+	    dquot->dq_itime == 0) {
+		sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n",
+		        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+		tty_write_message(current->tty, quotamessage);
+		dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type];
+	}
+	return(QUOTA_OK);
+}
+
+static int check_bdq(struct dquot *dquot, short type, u_long blocks)
+{
+	if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
+		return(QUOTA_OK);
+	if (dquot->dq_bhardlimit &&
+	   (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit) {
+		if ((dquot->dq_flags & DQ_BLKS) == 0) {
+			sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n",
+			        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+			tty_write_message(current->tty, quotamessage);
+			dquot->dq_flags |= DQ_BLKS;
+		}
+		return(NO_QUOTA);
+	}
+	if (dquot->dq_bsoftlimit &&
+	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
+	    dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime) {
+		sprintf(quotamessage, "%s: write failed, %s disk quota exceeded to long.\r\n",
+		        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+		tty_write_message(current->tty, quotamessage);
+		return(NO_QUOTA);
+	}
+	if (dquot->dq_bsoftlimit &&
+	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
+	    dquot->dq_btime == 0) {
+		sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n",
+		        dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+		tty_write_message(current->tty, quotamessage);
+		dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type];
+	}
+	return(QUOTA_OK);
+}
+
+static void dqput(struct dquot *dquot)
+{
+	if (!dquot)
+		return;
+	/*
+	 * If the dq_mnt pointer isn't initialized this entry needs no
+	 * checking and doesn't need to be written. It just an empty
+	 * dquot that is put back into the freelist.
+	 */
+	if (dquot->dq_mnt != (struct vfsmount *)NULL) {
+		wait_on_dquot(dquot);
+		if (!dquot->dq_count) {
+			printk("VFS: dqput: trying to free free dquot\n");
+			printk("VFS: device %d/%d, dquot of %s %d\n",
+					 MAJOR(dquot->dq_dev), MINOR(dquot->dq_dev),
+					 quotatypes[dquot->dq_type], dquot->dq_id);
+			return;
+		}
+repeat:
+		if (dquot->dq_count > 1) {
+			dquot->dq_count--;
+			return;
+		}
+		wake_up(&dquot_wait);
+		if (dquot->dq_flags & DQ_MOD) {
+			write_dquot(dquot);	/* we can sleep - so do again */
+			wait_on_dquot(dquot);
+			goto repeat;
+		}
+	}
+	if (dquot->dq_count) {
+		dquot->dq_count--;
+		nr_free_dquots++;
+	}
+	return;
+}
+
+static struct dquot *get_empty_dquot(void)
+{
+	struct dquot *dquot, *best;
+	int cnt;
+
+	if (nr_dquots < NR_DQUOTS && nr_free_dquots < (nr_dquots >> 2))
+		grow_dquots();
+
+repeat:
+	dquot = first_dquot;
+	best = NODQUOT;
+	for (cnt = 0; cnt < nr_dquots; dquot = dquot->dq_next, cnt++) {
+		if (!dquot->dq_count) {
+			if (!best)
+				best = dquot;
+			if (!(dquot->dq_flags & DQ_MOD) && !(dquot->dq_flags & DQ_LOCKED)) {
+				best = dquot;
+				break;
+			}
+		}
+	}
+	if (!best || best->dq_flags & DQ_MOD || best->dq_flags & DQ_LOCKED)
+		if (nr_dquots < NR_DQUOTS) {
+			grow_dquots();
+			goto repeat;
+		}
+	dquot = best;
+	if (!dquot) {
+		printk("VFS: No free dquots - contact mvw@mcs.ow.org\n");
+		sleep_on(&dquot_wait);
+		goto repeat;
+	}
+	if (dquot->dq_flags & DQ_LOCKED) {
+		wait_on_dquot(dquot);
+		goto repeat;
+	}
+	if (dquot->dq_flags & DQ_MOD) {
+		write_dquot(dquot);
+		goto repeat;
+	}
+	if (dquot->dq_count)
+		goto repeat;
+	clear_dquot(dquot);
+	dquot->dq_count = 1;
+	nr_free_dquots--;
+	if (nr_free_dquots < 0) {
+		printk ("VFS: get_empty_dquot: bad free dquot count.\n");
+		nr_free_dquots = 0;
+	}
+	return(dquot);
+}
+
+static struct dquot *dqget(dev_t dev, unsigned int id, short type)
+{
+	struct dquot *dquot, *empty;
+	struct vfsmount *vfsmnt;
+
+	if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL ||
+	    (vfsmnt->mnt_quotas[type] == (struct file *)0))
+		return(NODQUOT);
+	empty = get_empty_dquot();
+repeat:
+	dquot = *(hash(dev, id, type));
+	while (dquot) {
+		if (dquot->dq_dev != dev || dquot->dq_id != id) {
+			dquot = dquot->dq_hash_next;
+			continue;
+		}
+		wait_on_dquot(dquot);
+		if (dquot->dq_dev != dev || dquot->dq_id != id)
+			goto repeat;
+		if (!dquot->dq_count)
+			nr_free_dquots--;
+		dquot->dq_count++;
+		if (empty)
+			dqput(empty);
+		return(dquot);
+	}
+	if (!empty)
+		return(NODQUOT);
+	dquot = empty;
+	dquot->dq_id = id;
+	dquot->dq_type = type;
+	dquot->dq_dev = dev;
+	dquot->dq_mnt = vfsmnt;
+	put_last_free(dquot);
+	insert_dquot_hash(dquot);
+	read_dquot(dquot);
+	return(dquot);
+}
+
+/*
+ * Initialize a dquot-struct with new quota info. This is used by the
+ * systemcall interface functions.
+ */ 
+static int set_dqblk(dev_t dev, int id, short type, int flags, struct dqblk *dqblk)
+{
+	struct dquot *dquot;
+	struct dqblk dq_dqblk;
+	int error;
+
+	if (dqblk == (struct dqblk *)NULL)
+		return(-EFAULT);
+
+	if (flags & QUOTA_SYSCALL) {
+		if ((error = verify_area(VERIFY_READ, dqblk, sizeof(struct dqblk))) != 0)
+			return(error);
+		memcpy_fromfs(&dq_dqblk, dqblk, sizeof(struct dqblk));
+	} else {
+		memcpy(&dq_dqblk, dqblk, sizeof(struct dqblk));
+	}
+	if ((dquot = dqget(dev, id, type)) != NODQUOT) {
+		lock_dquot(dquot);
+		if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) {
+			dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
+			dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
+			dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
+			dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
+		}
+		if ((flags & SET_QUOTA) || (flags & SET_USE)) {
+			if (dquot->dq_isoftlimit &&
+			    dquot->dq_curinodes < dquot->dq_isoftlimit &&
+			    dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
+				dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type];
+			dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
+			if (dquot->dq_curinodes < dquot->dq_isoftlimit)
+				dquot->dq_flags &= ~DQ_INODES;
+			if (dquot->dq_bsoftlimit &&
+			    dquot->dq_curblocks < dquot->dq_bsoftlimit &&
+			    dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit)
+				dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type];
+			dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
+			if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
+				dquot->dq_flags &= ~DQ_BLKS;
+		}
+		if (id == 0) {
+			/* 
+			 * Change in expiretimes, change them in dq_mnt.
+			 */
+			dquot->dq_mnt->mnt_bexp[type] = dquot->dq_btime = dq_dqblk.dqb_btime;
+			dquot->dq_mnt->mnt_iexp[type] = dquot->dq_itime = dq_dqblk.dqb_itime;
+		}
+		if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
+		    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
+			dquot->dq_flags |= DQ_FAKE;
+		else
+			dquot->dq_flags &= ~DQ_FAKE;
+		dquot->dq_flags |= DQ_MOD;
+		unlock_dquot(dquot);
+		dqput(dquot);
+	}
+	return(0);
+}
+
+static int get_quota(dev_t dev, int id, short type, struct dqblk * dqblk)
+{
+	struct dquot *dquot;
+	int error;
+
+	if (has_quota_enabled(dev, type)) {
+		if (dqblk == (struct dqblk *)NULL)
+			return(-EFAULT);
+
+		if ((error = verify_area(VERIFY_WRITE, dqblk, sizeof(struct dqblk))) != 0)
+			return(error);
+
+		if ((dquot = dqget(dev, id, type)) != NODQUOT) {
+			memcpy_tofs(dqblk, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+			dqput(dquot);
+			return(0);
+		}
+	}
+	return(-ESRCH);
+}
+
+/*
+ * Initialize pointer in a inode to the right dquots.
+ */
+void dquot_initialize(struct inode *inode, short type)
+{
+	unsigned int id = 0;
+	short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (type != -1 && cnt != type)
+			continue;
+		if (S_ISSOCK(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+			continue;
+		if (inode->i_dquot[cnt] == NODQUOT) {
+			switch (cnt) {
+				case USRQUOTA:
+					id = inode->i_uid;
+					break;
+				case GRPQUOTA:
+					id = inode->i_gid;
+					break;
+			}
+			inode->i_dquot[cnt] = dqget(inode->i_dev, id, cnt);
+		}
+	}
+}
+
+void dquot_drop(struct inode *inode)
+{
+	short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		dqput(inode->i_dquot[cnt]);
+		inode->i_dquot[cnt] = NODQUOT;
+	}
+}
+
+/*
+ * This is a simple algorithm that calculates the size of a file in blocks.
+ * This is only used on filesystems that do not have a i_blocks count.
+ */
+static u_long isize_to_blocks(size_t isize, size_t blksize)
+{
+	u_long blocks;
+	u_long indirect;
+
+	if (!blksize)
+		blksize = BLOCK_SIZE;
+	blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0);
+	if (blocks > 10) {
+		indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
+		if (blocks > (10 + 256)) {
+			indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
+			if (blocks > (10 + 256 + (256 << 8)))
+				indirect++; /* triple indirect blocks */
+		}
+		blocks += indirect;
+	}
+	return(blocks);
+}
+
+/*
+ * Externaly referenced funtions trough dq_operations.
+ */
+int dquot_alloc_block(const struct inode *inode, unsigned long number)
+{
+	unsigned short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		if (check_bdq(inode->i_dquot[cnt], cnt, number))
+			return(NO_QUOTA);
+	}
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		dquot_incr_blocks(inode->i_dquot[cnt], number);
+	}
+	return(QUOTA_OK);
+}
+
+int dquot_alloc_inode(const struct inode *inode, unsigned long number)
+{
+	unsigned short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		if (check_idq(inode->i_dquot[cnt], cnt, number))
+			return(NO_QUOTA);
+	}
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		dquot_incr_inodes(inode->i_dquot[cnt], number);
+	}
+	return(QUOTA_OK);
+}
+
+void dquot_free_block(const struct inode *inode, unsigned long number)
+{
+	unsigned short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		dquot_decr_blocks(inode->i_dquot[cnt], number);
+	}
+}
+
+void dquot_free_inode(const struct inode *inode, unsigned long number)
+{
+	unsigned short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] == NODQUOT)
+			continue;
+		dquot_decr_inodes(inode->i_dquot[cnt], number);
+	}
+}
+
+/*
+ * Transfer the number of inode and blocks from one diskquota to an other.
+ */
+int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction)
+{
+	unsigned long blocks;
+	struct dquot *transfer_from[MAXQUOTAS];
+	struct dquot *transfer_to[MAXQUOTAS];
+	short cnt, disc;
+
+	/*
+	 * Find out if this filesystems uses i_blocks.
+	 */
+	if (inode->i_blksize == 0)
+		blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE);
+	else
+		blocks = (inode->i_blocks / 2);
+
+	/*
+	 * Build the transfer_from and transfer_to lists and check quotas to see
+	 * if operation is permitted.
+	 */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		transfer_from[cnt] = NODQUOT;
+		transfer_to[cnt] = NODQUOT;
+
+		if (!has_quota_enabled(inode->i_dev, cnt))
+			continue;
+
+		switch(cnt) {
+			case USRQUOTA:
+				if (inode->i_uid == iattr->ia_uid)
+					continue;
+				transfer_from[cnt] = dqget(inode->i_dev, (direction) ? inode->i_uid : iattr->ia_uid, cnt);
+				transfer_to[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_uid : inode->i_uid, cnt);
+				break;
+			case GRPQUOTA:
+				if (inode->i_gid == iattr->ia_gid)
+					continue;
+				transfer_from[cnt] = dqget(inode->i_dev, (direction) ? inode->i_gid : iattr->ia_gid, cnt);
+				transfer_to[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_gid : inode->i_gid, cnt);
+				break;
+		}
+
+		if (check_idq(transfer_to[cnt], cnt, 1) == NO_QUOTA ||
+		    check_bdq(transfer_to[cnt], cnt, blocks) == NO_QUOTA) {
+			for (disc = 0; disc <= cnt; disc++) {
+				dqput(transfer_from[disc]);
+				dqput(transfer_to[disc]);
+			}
+			return(NO_QUOTA);
+		}
+	}
+
+	/*
+	 * Finaly perform the needed transfer from transfer_from to transfer_to.
+	 * And release any pointer to dquots not needed anymore.
+	 */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		/*
+		 * Skip changes for same uid or gid or for non-existing quota-type.
+		 */
+		if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT)
+			continue;
+
+		if (transfer_from[cnt] != NODQUOT) {
+			dquot_decr_inodes(transfer_from[cnt], 1);
+			dquot_decr_blocks(transfer_from[cnt], blocks);
+		}
+		if (transfer_to[cnt] != NODQUOT) {
+			dquot_incr_inodes(transfer_to[cnt], 1);
+			dquot_incr_blocks(transfer_to[cnt], blocks);
+		}
+		if (inode->i_dquot[cnt] != NODQUOT) {
+			dqput(transfer_from[cnt]);
+			dqput(inode->i_dquot[cnt]);
+			inode->i_dquot[cnt] = transfer_to[cnt];
+		} else {
+			dqput(transfer_from[cnt]);
+			dqput(transfer_to[cnt]);
+		}
+	}
+	return(QUOTA_OK);
+}
+
+void dquot_init(void)
+{
+	printk("VFS: Diskquotas version %s initialized\r\n", __DQUOT_VERSION__);
+	memset(hash_table, 0, sizeof(hash_table));
+	first_dquot = NODQUOT;
+}
+
+/*
+ * Definitions of diskquota operations.
+ */
+struct dquot_operations dquot_operations = {
+	dquot_initialize,
+	dquot_drop,
+	dquot_alloc_block,
+	dquot_alloc_inode,
+	dquot_free_block,
+	dquot_free_inode,
+	dquot_transfer
+};
+
+/*
+ * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
+ */
+int quota_off(dev_t dev, short type)
+{
+	struct vfsmount *vfsmnt;
+	short cnt;
+
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (type != -1 && cnt != type)
+			continue;
+		if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL ||
+	     	     vfsmnt->mnt_quotas[cnt] == (struct file *)NULL)
+			continue;
+		vfsmnt->mnt_sb->dq_op = (struct dquot_operations *)NULL;
+		reset_dquot_ptrs(dev, cnt);
+		invalidate_dquots(dev, cnt);
+		close_fp(vfsmnt->mnt_quotas[cnt]);
+		vfsmnt->mnt_quotas[cnt] = (struct file *)NULL;
+		vfsmnt->mnt_iexp[cnt] = vfsmnt->mnt_bexp[cnt] = (time_t)NULL;
+	}
+	return(0);
+}
+
+int quota_on(dev_t dev, short type, char *path)
+{
+	struct file *filp = (struct file *)NULL;
+	struct vfsmount *vfsmnt;
+	struct inode *inode;
+	struct dquot *dquot;
+	char *tmp;
+	int error;
+
+	if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL)
+		return(-ENODEV);
+	if (vfsmnt->mnt_quotas[type] != (struct file *)NULL)
+		return(-EBUSY);
+	if ((error = getname(path, &tmp)) != 0)
+		return(error);
+	error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+	putname(tmp);
+	if (error)
+		return(error);
+	if (!S_ISREG(inode->i_mode)) {
+		iput(inode);
+		return(-EACCES);
+	}
+	if ((filp = get_empty_filp()) != (struct file *)NULL) {
+		filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
+		filp->f_flags = O_RDWR;
+		filp->f_inode = inode;
+		filp->f_pos = 0;
+		filp->f_reada = 0;
+		filp->f_op = inode->i_op->default_file_ops;
+		if (filp->f_op->read || filp->f_op->write) {
+			if ((error = get_write_access(inode)) == 0) {
+				if (filp->f_op && filp->f_op->open)
+					error = filp->f_op->open(inode, filp);
+				if (error == 0) {
+					vfsmnt->mnt_quotas[type] = filp;
+					dquot = dqget(dev, 0, type);
+					vfsmnt->mnt_iexp[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
+					vfsmnt->mnt_bexp[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
+					dqput(dquot);
+					vfsmnt->mnt_sb->dq_op = &dquot_operations;
+					add_dquot_ref(dev, type);
+					return(0);
+				}
+				put_write_access(inode);
+			}
+		} else
+			error = -EIO;
+	  filp->f_count--;
+	} else
+		error = -EMFILE;
+	iput(inode);
+	return(error);
+}
+
+/*
+ * Ok this is the systemcall interface, this communicates with
+ * the userlevel programs. Currently this only supports diskquota
+ * calls. Maybe we need to add the process quotas etc in the future.
+ * But we probably better use rlimits for that.
+ */
+asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+	int cmds = 0, type = 0, flags = 0;
+	struct inode *ino;
+	dev_t dev;
+
+	cmds = cmd >> SUBCMDSHIFT;
+	type = cmd & SUBCMDMASK;
+
+	if ((u_int) type >= MAXQUOTAS)
+		return(-EINVAL);
+	switch (cmds) {
+		case Q_SYNC:
+			break;
+		case Q_GETQUOTA:
+			if (((type == USRQUOTA && current->uid != id) ||
+			     (type == GRPQUOTA && current->gid != id)) && !suser())
+				return(-EPERM);
+			break;
+		default:
+			if (!suser())
+				return(-EPERM);
+	}
+
+	if (special == (char *)NULL && cmds == Q_SYNC)
+		dev = 0;
+	else {
+		if (namei(special, S_WRITE, &ino))
+			return(-EINVAL);
+		dev = ino->i_rdev;
+		if (!S_ISBLK(ino->i_mode)) {
+			iput(ino);
+			return(-ENOTBLK);
+		}
+		iput(ino);
+	}
+
+	switch (cmds) {
+		case Q_QUOTAON:
+			return(quota_on(dev, type, (char *) addr));
+		case Q_QUOTAOFF:
+			return(quota_off(dev, type));
+		case Q_GETQUOTA:
+			return(get_quota(dev, id, type, (struct dqblk *) addr));
+		case Q_SETQUOTA:
+			flags |= SET_QUOTA;
+			break;
+		case Q_SETUSE:
+			flags |= SET_USE;
+			break;
+		case Q_SETQLIM:
+			flags |= SET_QLIMIT;
+			break;
+		case Q_SYNC:
+			return(sync_dquots(dev, type));
+		default:
+			return(-EINVAL);
+	}
+
+	flags |= QUOTA_SYSCALL;
+	if (has_quota_enabled(dev, type))
+		return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr));
+	return(-ESRCH);
+}
+
+#else
+
+asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+	return(-ENOSYS);
+}
+
+#endif /* CONFIG_QUOTA */
diff -ru --new-file linux-1.2.12/fs/exec.c linux/fs/exec.c
--- linux-1.2.12/fs/exec.c	Thu Jul 27 17:31:13 1995
+++ linux/fs/exec.c	Tue Aug  1 12:03:52 1995
@@ -155,6 +155,8 @@
  		goto close_coredump; \
 } else file.f_pos = (offset)		
 
+extern int close_fp(struct file *filp, unsigned int fd);
+
 /*
  * Routine writes a core dump image in the current directory.
  * Currently only a stub-function.
@@ -212,6 +214,7 @@
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
+	current->flags |= PF_DUMPCORE;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 	dump.u_ar0 = (struct pt_regs *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
 	dump.signal = signr;
@@ -604,7 +607,7 @@
 		goto exec_error2;
 	}
 	/* better not execute files which are being written to */
-	if (bprm.inode->i_wcount > 0) {
+	if (bprm.inode->i_writecount > 0) {
 		retval = -ETXTBSY;
 		goto exec_error2;
 	}
@@ -776,6 +779,8 @@
 	current->mm->mmap = NULL;
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
+	current->flags &= ~PF_FORKNOEXEC; /* accounting flags */
+	current->io_usage = 0;
 	if (N_MAGIC(ex) == OMAGIC) {
 		do_mmap(NULL, 0, ex.a_text+ex.a_data,
 			PROT_READ|PROT_WRITE|PROT_EXEC,
diff -ru --new-file linux-1.2.12/fs/ext/inode.c linux/fs/ext/inode.c
--- linux-1.2.12/fs/ext/inode.c	Mon Aug 15 14:53:47 1994
+++ linux/fs/ext/inode.c	Tue Aug  1 12:03:52 1995
@@ -117,7 +117,7 @@
 	/* set up enough so that it can read an inode */
 	s->s_dev = dev;
 	s->s_op = &ext_sops;
-	if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) {
+	if (!(s->s_mounted = iget(s, EXT_ROOT_INO, S_NONE))) {
 		s->s_dev=0;
 		printk("EXT-fs: get root inode failed\n");
 		return NULL;
diff -ru --new-file linux-1.2.12/fs/ext/namei.c linux/fs/ext/namei.c
--- linux-1.2.12/fs/ext/namei.c	Wed Jan 18 08:51:48 1995
+++ linux/fs/ext/namei.c	Tue Aug  1 12:03:52 1995
@@ -146,8 +146,8 @@
 	return NULL;
 }
 
-int ext_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+int ext_lookup(struct inode * dir,const char * name, int len, int i_flags,
+               struct inode ** result)
 {
 	int ino;
 	struct ext_dir_entry * de;
@@ -166,7 +166,7 @@
 	}
 	ino = de->inode;
 	brelse(bh);
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, i_flags))) {
 		iput(dir);
 		return -EACCES;
 	}
@@ -534,7 +534,7 @@
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_rmdir;
         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
@@ -587,7 +587,7 @@
 	bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_unlink;
 	retval = -EPERM;
 	if ((dir->i_mode & S_ISVTX) && !fsuser() &&
@@ -727,7 +727,7 @@
 		if (new_inode->i_dev != old_inode->i_dev)
 			break;
 		ino = new_inode->i_ino;
-		if (ext_lookup(new_inode,"..",2,&new_inode))
+		if (ext_lookup(new_inode, "..", 2, S_WRITE, &new_inode))
 			break;
 		if (new_inode->i_ino == ino)
 			break;
@@ -778,7 +778,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, 0, S_NONE); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -788,7 +788,7 @@
 		goto end_rename;
 	new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
 	if (new_bh) {
-		new_inode = __iget(new_dir->i_sb, new_de->inode,0); /* don't cross mnt-points */
+		new_inode = __iget(new_dir->i_sb, new_de->inode, 0, S_NONE); /* don't cross mnt-points */
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
diff -ru --new-file linux-1.2.12/fs/ext/symlink.c linux/fs/ext/symlink.c
--- linux-1.2.12/fs/ext/symlink.c	Mon May  2 17:34:26 1994
+++ linux/fs/ext/symlink.c	Tue Aug  1 12:03:52 1995
@@ -76,7 +76,7 @@
 	}
 	iput(inode);
 	current->link_count++;
-	error = open_namei(bh->b_data,flag,mode,res_inode,dir);
+	error = open_namei(bh->b_data, flag, mode, res_inode, dir);
 	current->link_count--;
 	brelse(bh);
 	return error;
diff -ru --new-file linux-1.2.12/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- linux-1.2.12/fs/ext2/balloc.c	Wed Mar 22 09:33:59 1995
+++ linux/fs/ext2/balloc.c	Tue Aug  1 12:19:43 1995
@@ -165,7 +165,7 @@
 	return load__block_bitmap (sb, block_group);
 }
 
-void ext2_free_blocks (struct super_block * sb, unsigned long block,
+void ext2_free_blocks (const struct inode * inode, unsigned long block,
 		       unsigned long count)
 {
 	struct buffer_head * bh;
@@ -177,68 +177,70 @@
 	struct ext2_group_desc * gdp;
 	struct ext2_super_block * es;
 
-	if (!sb) {
+	if (!inode->i_sb) {
 		printk ("ext2_free_blocks: nonexistent device");
 		return;
 	}
-	lock_super (sb);
-	es = sb->u.ext2_sb.s_es;
+	lock_super (inode->i_sb);
+	es = inode->i_sb->u.ext2_sb.s_es;
 	if (block < es->s_first_data_block || 
 	    (block + count) > es->s_blocks_count) {
-		ext2_error (sb, "ext2_free_blocks",
+		ext2_error (inode->i_sb, "ext2_free_blocks",
 			    "Freeing blocks not in datazone - "
 			    "block = %lu, count = %lu", block, count);
-		unlock_super (sb);
+		unlock_super (inode->i_sb);
 		return;
 	}
 
 	ext2_debug ("freeing block %lu\n", block);
 
 	block_group = (block - es->s_first_data_block) /
-		      EXT2_BLOCKS_PER_GROUP(sb);
-	bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
-	if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
-		ext2_panic (sb, "ext2_free_blocks",
+		      EXT2_BLOCKS_PER_GROUP(inode->i_sb);
+	bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(inode->i_sb);
+	if (bit + count > EXT2_BLOCKS_PER_GROUP(inode->i_sb))
+		ext2_panic (inode->i_sb, "ext2_free_blocks",
 			    "Freeing blocks across group boundary - "
 			    "Block = %lu, count = %lu",
 			    block, count);
-	bitmap_nr = load_block_bitmap (sb, block_group);
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-	gdp = get_group_desc (sb, block_group, &bh2);
+	bitmap_nr = load_block_bitmap (inode->i_sb, block_group);
+	bh = inode->i_sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
+	gdp = get_group_desc (inode->i_sb, block_group, &bh2);
 
-	if (test_opt (sb, CHECK_STRICT) &&
+	if (test_opt (inode->i_sb, CHECK_STRICT) &&
 	    (in_range (gdp->bg_block_bitmap, block, count) ||
 	     in_range (gdp->bg_inode_bitmap, block, count) ||
 	     in_range (block, gdp->bg_inode_table,
-		       sb->u.ext2_sb.s_itb_per_group) ||
+		       inode->i_sb->u.ext2_sb.s_itb_per_group) ||
 	     in_range (block + count - 1, gdp->bg_inode_table,
-		       sb->u.ext2_sb.s_itb_per_group)))
-		ext2_panic (sb, "ext2_free_blocks",
+		       inode->i_sb->u.ext2_sb.s_itb_per_group)))
+		ext2_panic (inode->i_sb, "ext2_free_blocks",
 			    "Freeing blocks in system zones - "
 			    "Block = %lu, count = %lu",
 			    block, count);
 
 	for (i = 0; i < count; i++) {
 		if (!clear_bit (bit + i, bh->b_data))
-			ext2_warning (sb, "ext2_free_blocks",
+			ext2_warning (inode->i_sb, "ext2_free_blocks",
 				      "bit already cleared for block %lu", 
 				      block);
 		else {
+			if (inode->i_sb->dq_op && inode->i_sb->dq_op->free_block)
+				inode->i_sb->dq_op->free_block(inode, 1);
 			gdp->bg_free_blocks_count++;
 			es->s_free_blocks_count++;
 		}
 	}
 	
 	mark_buffer_dirty(bh2, 1);
-	mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+	mark_buffer_dirty(inode->i_sb->u.ext2_sb.s_sbh, 1);
 
 	mark_buffer_dirty(bh, 1);
-	if (sb->s_flags & MS_SYNCHRONOUS) {
+	if (inode->i_sb->s_flags & MS_SYNCHRONOUS) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
 	}
-	sb->s_dirt = 1;
-	unlock_super (sb);
+	inode->i_sb->s_dirt = 1;
+	unlock_super (inode->i_sb);
 	return;
 }
 
@@ -249,7 +251,7 @@
  * each block group the search first looks for an entire free byte in the block
  * bitmap, and then for any free bit if that fails.
  */
-int ext2_new_block (struct super_block * sb, unsigned long goal,
+int ext2_new_block (const struct inode * inode, unsigned long goal,
 		    u32 * prealloc_count,
 		    u32 * prealloc_block)
 {
@@ -265,17 +267,17 @@
 #ifdef EXT2FS_DEBUG
 	static int goal_hits = 0, goal_attempts = 0;
 #endif
-	if (!sb) {
+	if (!inode->i_sb) {
 		printk ("ext2_new_block: nonexistent device");
 		return 0;
 	}
-	lock_super (sb);
-	es = sb->u.ext2_sb.s_es;
+	lock_super (inode->i_sb);
+	es = inode->i_sb->u.ext2_sb.s_es;
 	if (es->s_free_blocks_count <= es->s_r_blocks_count &&
-	    (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) &&
-	     (sb->u.ext2_sb.s_resgid == 0 ||
-	      !in_group_p (sb->u.ext2_sb.s_resgid)))) {
-		unlock_super (sb);
+	    (!fsuser() && (inode->i_sb->u.ext2_sb.s_resuid != current->fsuid) &&
+	     (inode->i_sb->u.ext2_sb.s_resgid == 0 ||
+	      !in_group_p (inode->i_sb->u.ext2_sb.s_resgid)))) {
+		unlock_super (inode->i_sb);
 		return 0;
 	}
 
@@ -287,16 +289,16 @@
 	 */
 	if (goal < es->s_first_data_block || goal >= es->s_blocks_count)
 		goal = es->s_first_data_block;
-	i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb);
-	gdp = get_group_desc (sb, i, &bh2);
+	i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(inode->i_sb);
+	gdp = get_group_desc (inode->i_sb, i, &bh2);
 	if (gdp->bg_free_blocks_count > 0) {
-		j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
+		j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(inode->i_sb));
 #ifdef EXT2FS_DEBUG
 		if (j)
 			goal_attempts++;
 #endif
-		bitmap_nr = load_block_bitmap (sb, i);
-		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
+		bitmap_nr = load_block_bitmap (inode->i_sb, i);
+		bh = inode->i_sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
@@ -314,14 +316,14 @@
 			 */
 			lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >>
 				((j & 31) + 1));
-			if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32)
+			if (j < EXT2_BLOCKS_PER_GROUP(inode->i_sb) - 32)
 				lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) <<
 				 (31 - (j & 31));
 			else
 				lmap |= 0xffffffff << (31 - (j & 31));
 			if (lmap != 0xffffffffl) {
 				k = ffz(lmap) + 1;
-				if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
+				if ((j + k) < EXT2_BLOCKS_PER_GROUP(inode->i_sb)) {
 					j += k;
 					goto got_block;
 				}
@@ -340,16 +342,16 @@
 		 * cyclicly search through the rest of the groups.
 		 */
 		p = ((char *) bh->b_data) + (j >> 3);
-		r = memscan(p, 0, (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
+		r = memscan(p, 0, (EXT2_BLOCKS_PER_GROUP(inode->i_sb) - j + 7) >> 3);
 		k = (r - ((char *) bh->b_data)) << 3;
-		if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
+		if (k < EXT2_BLOCKS_PER_GROUP(inode->i_sb)) {
 			j = k;
 			goto search_back;
 		}
 		k = find_next_zero_bit ((unsigned long *) bh->b_data, 
-					EXT2_BLOCKS_PER_GROUP(sb),
+					EXT2_BLOCKS_PER_GROUP(inode->i_sb),
 					j);
-		if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
+		if (k < EXT2_BLOCKS_PER_GROUP(inode->i_sb)) {
 			j = k;
 			goto got_block;
 		}
@@ -361,31 +363,31 @@
 	 * Now search the rest of the groups.  We assume that 
 	 * i and gdp correctly point to the last group visited.
 	 */
-	for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) {
+	for (k = 0; k < inode->i_sb->u.ext2_sb.s_groups_count; k++) {
 		i++;
-		if (i >= sb->u.ext2_sb.s_groups_count)
+		if (i >= inode->i_sb->u.ext2_sb.s_groups_count)
 			i = 0;
-		gdp = get_group_desc (sb, i, &bh2);
+		gdp = get_group_desc (inode->i_sb, i, &bh2);
 		if (gdp->bg_free_blocks_count > 0)
 			break;
 	}
-	if (k >= sb->u.ext2_sb.s_groups_count) {
-		unlock_super (sb);
+	if (k >= inode->i_sb->u.ext2_sb.s_groups_count) {
+		unlock_super (inode->i_sb);
 		return 0;
 	}
-	bitmap_nr = load_block_bitmap (sb, i);
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-	r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
+	bitmap_nr = load_block_bitmap (inode->i_sb, i);
+	bh = inode->i_sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
+	r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(inode->i_sb) >> 3);
 	j = (r - bh->b_data) << 3;
-	if (j < EXT2_BLOCKS_PER_GROUP(sb))
+	if (j < EXT2_BLOCKS_PER_GROUP(inode->i_sb))
 		goto search_back;
 	else
 		j = find_first_zero_bit ((unsigned long *) bh->b_data,
-					 EXT2_BLOCKS_PER_GROUP(sb));
-	if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
-		ext2_error (sb, "ext2_new_block",
+					 EXT2_BLOCKS_PER_GROUP(inode->i_sb));
+	if (j >= EXT2_BLOCKS_PER_GROUP(inode->i_sb)) {
+		ext2_error (inode->i_sb, "ext2_new_block",
 			    "Free blocks count corrupted for block group %d", i);
-		unlock_super (sb);
+		unlock_super (inode->i_sb);
 		return 0;
 	}
 
@@ -401,19 +403,30 @@
 
 	ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
 
-	tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
+	/*
+	 * Check quota for allocation of this block.
+	 */
+	if (inode->i_sb->dq_op && inode->i_sb->dq_op->alloc_block)
+		if (inode->i_sb->dq_op->alloc_block(inode, 1)) {
+			unlock_super (inode->i_sb);
+			return 0;
+		}
 
-	if (test_opt (sb, CHECK_STRICT) &&
+	tmp = j + i * EXT2_BLOCKS_PER_GROUP(inode->i_sb) + es->s_first_data_block;
+
+	if (test_opt (inode->i_sb, CHECK_STRICT) &&
 	    (tmp == gdp->bg_block_bitmap ||
 	     tmp == gdp->bg_inode_bitmap ||
-	     in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
-		ext2_panic (sb, "ext2_new_block",
+	     in_range (tmp, gdp->bg_inode_table, inode->i_sb->u.ext2_sb.s_itb_per_group)))
+		ext2_panic (inode->i_sb, "ext2_new_block",
 			    "Allocating block in system zone - "
 			    "block = %u", tmp);
 
 	if (set_bit (j, bh->b_data)) {
-		ext2_warning (sb, "ext2_new_block",
+		ext2_warning (inode->i_sb, "ext2_new_block",
 			      "bit already set for block %d", j);
+		if (inode->i_sb->dq_op && inode->i_sb->dq_op->free_block)
+			inode->i_sb->dq_op->free_block(inode, 1);
 		goto repeat;
 	}
 
@@ -427,9 +440,15 @@
 		*prealloc_count = 0;
 		*prealloc_block = tmp + 1;
 		for (k = 1;
-		     k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
-			if (set_bit (j + k, bh->b_data))
+		     k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(inode->i_sb); k++) {
+			if (inode->i_sb->dq_op && inode->i_sb->dq_op->alloc_block)
+				if (inode->i_sb->dq_op->alloc_block(inode, 1))
+					break;
+			if (set_bit (j + k, bh->b_data)) {
+				if (inode->i_sb->dq_op && inode->i_sb->dq_op->free_block)
+					inode->i_sb->dq_op->free_block(inode, 1);
 				break;
+			}
 			(*prealloc_count)++;
 		}	
 		gdp->bg_free_blocks_count -= *prealloc_count;
@@ -442,24 +461,24 @@
 	j = tmp;
 
 	mark_buffer_dirty(bh, 1);
-	if (sb->s_flags & MS_SYNCHRONOUS) {
+	if (inode->i_sb->s_flags & MS_SYNCHRONOUS) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
 	}
 
 	if (j >= es->s_blocks_count) {
-		ext2_error (sb, "ext2_new_block",
+		ext2_error (inode->i_sb, "ext2_new_block",
 			    "block >= blocks count - "
 			    "block_group = %d, block=%d", i, j);
-		unlock_super (sb);
+		unlock_super (inode->i_sb);
 		return 0;
 	}
-	if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) {
-		ext2_error (sb, "ext2_new_block", "cannot get block %d", j);
-		unlock_super (sb);
+	if (!(bh = getblk (inode->i_sb->s_dev, j, inode->i_sb->s_blocksize))) {
+		ext2_error (inode->i_sb, "ext2_new_block", "cannot get block %d", j);
+		unlock_super (inode->i_sb);
 		return 0;
 	}
-	memset(bh->b_data, 0, sb->s_blocksize);
+	memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 	bh->b_uptodate = 1;
 	mark_buffer_dirty(bh, 1);
 	brelse (bh);
@@ -470,9 +489,9 @@
 	gdp->bg_free_blocks_count--;
 	mark_buffer_dirty(bh2, 1);
 	es->s_free_blocks_count--;
-	mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
-	sb->s_dirt = 1;
-	unlock_super (sb);
+	mark_buffer_dirty(inode->i_sb->u.ext2_sb.s_sbh, 1);
+	inode->i_sb->s_dirt = 1;
+	unlock_super (inode->i_sb);
 	return j;
 }
 
diff -ru --new-file linux-1.2.12/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- linux-1.2.12/fs/ext2/ialloc.c	Wed Mar 22 09:33:59 1995
+++ linux/fs/ext2/ialloc.c	Tue Aug  1 12:03:52 1995
@@ -252,7 +252,8 @@
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
 	}
-
+	if (sb->dq_op && sb->dq_op->free_inode)
+		sb->dq_op->free_inode(inode, 1);
 	sb->s_dirt = 1;
 	clear_inode (inode);
 	unlock_super (sb);
@@ -481,9 +482,19 @@
 	insert_inode_hash(inode);
 	inc_inode_version (inode, gdp, mode);
 
+	unlock_super (sb);
+	if (sb->dq_op) {
+		sb->dq_op->initialize(inode, -1);
+		if (sb->dq_op->alloc_inode(inode, 1)) {
+			sb->dq_op->drop(inode);
+			ext2_free_inode(inode);
+			iput (inode);
+			return NULL;
+		}
+		inode->i_flags |= S_WRITE;
+	}
 	ext2_debug ("allocating inode %lu\n", inode->i_ino);
 
-	unlock_super (sb);
 	return inode;
 }
 
diff -ru --new-file linux-1.2.12/fs/ext2/inode.c linux/fs/ext2/inode.c
--- linux-1.2.12/fs/ext2/inode.c	Wed Mar 22 09:33:59 1995
+++ linux/fs/ext2/inode.c	Tue Aug  1 12:03:52 1995
@@ -62,12 +62,12 @@
 void ext2_discard_prealloc (struct inode * inode)
 {
 #ifdef EXT2_PREALLOCATE
+	unsigned short total;
+
 	if (inode->u.ext2_i.i_prealloc_count) {
-		int i = inode->u.ext2_i.i_prealloc_count;
+		total = inode->u.ext2_i.i_prealloc_count;
 		inode->u.ext2_i.i_prealloc_count = 0;
-		ext2_free_blocks (inode->i_sb,
-				  inode->u.ext2_i.i_prealloc_block,
-				  i);
+		ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total);
 	}
 #endif
 }
@@ -110,15 +110,14 @@
 		ext2_debug ("preallocation miss (%lu/%lu).\n",
 			    alloc_hits, ++alloc_attempts);
 		if (S_ISREG(inode->i_mode))
-			result = ext2_new_block
-				(inode->i_sb, goal,
+			result = ext2_new_block (inode, goal,
 				 &inode->u.ext2_i.i_prealloc_count,
 				 &inode->u.ext2_i.i_prealloc_block);
 		else
-			result = ext2_new_block (inode->i_sb, goal, 0, 0);
+			result = ext2_new_block (inode, goal, 0, 0);
 	}
 #else
-	result = ext2_new_block (inode->i_sb, goal, 0, 0);
+	result = ext2_new_block (inode, goal, 0, 0);
 #endif
 
 	return result;
@@ -229,7 +228,7 @@
 		return NULL;
 	result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
 	if (*p) {
-		ext2_free_blocks (inode->i_sb, tmp, 1);
+		ext2_free_blocks (inode, tmp, 1);
 		brelse (result);
 		goto repeat;
 	}
@@ -303,7 +302,7 @@
 	}
 	result = getblk (bh->b_dev, tmp, blocksize);
 	if (*p) {
-		ext2_free_blocks (inode->i_sb, tmp, 1);
+		ext2_free_blocks (inode, tmp, 1);
 		brelse (result);
 		goto repeat;
 	}
diff -ru --new-file linux-1.2.12/fs/ext2/namei.c linux/fs/ext2/namei.c
--- linux-1.2.12/fs/ext2/namei.c	Wed Mar 22 09:33:59 1995
+++ linux/fs/ext2/namei.c	Tue Aug  1 12:03:52 1995
@@ -160,7 +160,7 @@
 	return NULL;
 }
 
-int ext2_lookup (struct inode * dir, const char * name, int len,
+int ext2_lookup (struct inode * dir, const char * name, int len, int i_flags,
 		 struct inode ** result)
 {
 	unsigned long ino;
@@ -179,7 +179,7 @@
 			iput(dir);
 			return -ENOENT;
 		}
-		if (!(*result = iget (dir->i_sb, ino))) {
+		if (!(*result = iget (dir->i_sb, ino, i_flags))) {
 			iput (dir);
 			return -EACCES;
 		}
@@ -196,7 +196,7 @@
 	ino = de->inode;
 	dcache_add(dir, name, len, ino);
 	brelse (bh);
-	if (!(*result = iget (dir->i_sb, ino))) {
+	if (!(*result = iget (dir->i_sb, ino, i_flags))) {
 		iput (dir);
 		return -EACCES;
 	}
@@ -613,7 +613,7 @@
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget (dir->i_sb, de->inode)))
+	if (!(inode = iget (dir->i_sb, de->inode, S_WRITE)))
 		goto end_rmdir;
 	if (inode->i_dev != dir->i_dev)
 		goto end_rmdir;
@@ -693,7 +693,7 @@
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget (dir->i_sb, de->inode)))
+	if (!(inode = iget (dir->i_sb, de->inode, S_WRITE)))
 		goto end_unlink;
 	retval = -EPERM;
 	if (S_ISDIR(inode->i_mode))
@@ -788,6 +788,7 @@
 	}
 	inode->i_size = i;
 	inode->i_dirt = 1;
+
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (bh) {
 		inode->i_nlink--;
@@ -886,7 +887,7 @@
 		if (new_inode->i_dev != old_inode->i_dev)
 			break;
 		ino = new_inode->i_ino;
-		if (ext2_lookup (new_inode, "..", 2, &new_inode))
+		if (ext2_lookup (new_inode, "..", 2, S_WRITE, &new_inode))
 			break;
 		if (new_inode->i_ino == ino)
 			break;
@@ -944,7 +945,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, 0, S_NONE); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -956,7 +957,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, new_de->inode, 0); /* no mntp cross */
+		new_inode = __iget (new_dir->i_sb, new_de->inode, 0, S_WRITE); /* no mntp cross */
 		if (!new_inode) {
 			brelse (new_bh);
 			new_bh = NULL;
diff -ru --new-file linux-1.2.12/fs/ext2/super.c linux/fs/ext2/super.c
--- linux-1.2.12/fs/ext2/super.c	Wed Mar 22 09:33:59 1995
+++ linux/fs/ext2/super.c	Tue Aug  1 12:03:52 1995
@@ -287,10 +287,8 @@
 				return 0;
 			}
 		}
-		else {
-			printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
-			return 0;
-		}
+		else
+			return 1;
 	}
 	return 1;
 }
@@ -633,7 +631,7 @@
 	 */
 	sb->s_dev = dev;
 	sb->s_op = &ext2_sops;
-	if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) {
+	if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO, S_WRITE))) {
 		sb->s_dev = 0;
 		for (i = 0; i < db_count; i++)
 			if (sb->u.ext2_sb.s_group_desc[i])
diff -ru --new-file linux-1.2.12/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- linux-1.2.12/fs/ext2/truncate.c	Thu Apr  6 17:24:37 1995
+++ linux/fs/ext2/truncate.c	Tue Aug  1 12:03:52 1995
@@ -92,14 +92,14 @@
 		} else if (free_count > 0 && block_to_free == tmp - free_count)
 			free_count++;
 		else {
-			ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+			ext2_free_blocks (inode, block_to_free, free_count);
 			block_to_free = tmp;
 			free_count = 1;
 		}
-/*		ext2_free_blocks (inode->i_sb, tmp, 1); */
+/*		ext2_free_blocks (inode, tmp, 1); */
 	}
 	if (free_count > 0)
-		ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+		ext2_free_blocks (inode, block_to_free, free_count);
 	return retry;
 }
 
@@ -167,16 +167,16 @@
 		} else if (free_count > 0 && block_to_free == tmp - free_count)
 			free_count++;
 		else {
-			ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+			ext2_free_blocks (inode, block_to_free, free_count);
 			block_to_free = tmp;
 			free_count = 1;
 		}
-/*		ext2_free_blocks (inode->i_sb, tmp, 1); */
+/*		ext2_free_blocks (inode, tmp, 1); */
 		inode->i_blocks -= blocks;
 		inode->i_dirt = 1;
 	}
 	if (free_count > 0)
-		ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+		ext2_free_blocks (inode, block_to_free, free_count);
 	ind = (u32 *) ind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
 		if (*(ind++))
@@ -189,7 +189,7 @@
 			*p = 0;
 			inode->i_blocks -= blocks;
 			inode->i_dirt = 1;
-			ext2_free_blocks (inode->i_sb, tmp, 1);
+			ext2_free_blocks (inode, tmp, 1);
 		}
 	if (IS_SYNC(inode) && ind_bh->b_dirt) {
 		ll_rw_block (WRITE, 1, &ind_bh);
@@ -249,7 +249,7 @@
 			*p = 0;
 			inode->i_blocks -= blocks;
 			inode->i_dirt = 1;
-			ext2_free_blocks (inode->i_sb, tmp, 1);
+			ext2_free_blocks (inode, tmp, 1);
 		}
 	if (IS_SYNC(inode) && dind_bh->b_dirt) {
 		ll_rw_block (WRITE, 1, &dind_bh);
@@ -308,7 +308,7 @@
 			*p = 0;
 			inode->i_blocks -= blocks;
 			inode->i_dirt = 1;
-			ext2_free_blocks (inode->i_sb, tmp, 1);
+			ext2_free_blocks (inode, tmp, 1);
 		}
 	if (IS_SYNC(inode) && tind_bh->b_dirt) {
 		ll_rw_block (WRITE, 1, &tind_bh);
diff -ru --new-file linux-1.2.12/fs/file_table.c linux/fs/file_table.c
--- linux-1.2.12/fs/file_table.c	Fri Oct 21 08:39:35 1994
+++ linux/fs/file_table.c	Tue Aug  1 12:03:52 1995
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/config.h>
 
 struct file * first_file;
 int nr_files = 0;
@@ -88,3 +89,34 @@
 	}
 	return NULL;
 }
+
+#ifdef CONFIG_QUOTA
+void add_dquot_ref(dev_t dev, short type)
+{
+	struct file *filp;
+	int cnt;
+
+	for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
+		if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+			continue;
+		if (filp->f_mode & FMODE_WRITE &&
+		    filp->f_inode->i_sb->dq_op && filp->f_inode->i_sb->dq_op->initialize) {
+			filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type);
+			filp->f_inode->i_flags |= S_WRITE;
+		}
+	}
+}
+
+void reset_dquot_ptrs(dev_t dev, short type)
+{
+	struct file *filp;
+	int cnt;
+
+	for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
+		if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+			continue;
+		if (IS_WRITABLE(filp->f_inode))
+			filp->f_inode->i_dquot[type] = NODQUOT;
+	}
+}
+#endif
diff -ru --new-file linux-1.2.12/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- linux-1.2.12/fs/hpfs/hpfs_fs.c	Sun Feb  5 13:44:32 1995
+++ linux/fs/hpfs/hpfs_fs.c	Tue Aug  1 12:03:52 1995
@@ -188,7 +188,7 @@
 			 char *buf, int count);
 static int hpfs_readdir(struct inode *inode, struct file *filp,
 			struct dirent *dirent, int count);
-static int hpfs_lookup(struct inode *, const char *, int, struct inode **);
+static int hpfs_lookup(struct inode *, const char *, int, int, struct inode **);
 
 static const struct file_operations hpfs_dir_ops =
 {
@@ -480,7 +480,7 @@
 	 * all set.  try it out.
 	 */
 
-	s->s_mounted = iget(s, s->s_hpfs_root);
+	s->s_mounted = iget(s, s->s_hpfs_root, S_NONE);
 	unlock_super(s);
 
 	if (!s->s_mounted) {
@@ -1102,7 +1102,7 @@
  * the boondocks.)
  */
 
-static int hpfs_lookup(struct inode *dir, const char *name, int len,
+static int hpfs_lookup(struct inode *dir, const char *name, int len, int i_flags,
 		       struct inode **result)
 {
 	struct quad_buffer_head qbh;
@@ -1152,7 +1152,7 @@
 	 * Go find or make an inode.
 	 */
 
-	if (!(inode = iget(dir->i_sb, ino)))
+	if (!(inode = iget(dir->i_sb, ino, i_flags)))
 		goto bail1;
 
 	/*
diff -ru --new-file linux-1.2.12/fs/inode.c linux/fs/inode.c
--- linux-1.2.12/fs/inode.c	Wed Nov 30 16:17:39 1994
+++ linux/fs/inode.c	Tue Aug  1 12:03:53 1995
@@ -405,6 +405,10 @@
 		wait_on_inode(inode);
 		goto repeat;
 	}
+	if (IS_WRITABLE(inode)) {
+		if (inode->i_sb->dq_op && inode->i_sb->dq_op->drop)
+			inode->i_sb->dq_op->drop(inode);
+	}
 	inode->i_count--;
 	if (inode->i_mmap) {
 		printk("iput: inode %lu on device %d/%d still has mappings.\n",
@@ -496,7 +500,7 @@
 	return inode;
 }
 
-struct inode * __iget(struct super_block * sb, int nr, int crossmntp)
+struct inode *__iget(struct super_block * sb, int nr, int crossmntp, int i_flags)
 {
 	static struct wait_queue * update_wait = NULL;
 	struct inode_hash_entry * h;
@@ -550,6 +554,12 @@
 		iput(empty);
 
 return_it:
+	if ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && (i_flags & S_WRITE)) {
+		if (inode->i_sb->dq_op && inode->i_sb->dq_op->initialize) {
+			inode->i_sb->dq_op->initialize(inode, -1);
+			inode->i_flags |= S_WRITE;
+		}
+	}
 	while (h->updating)
 		sleep_on(&update_wait);
 	return inode;
diff -ru --new-file linux-1.2.12/fs/isofs/dir.c linux/fs/isofs/dir.c
--- linux-1.2.12/fs/isofs/dir.c	Wed Feb 22 07:15:14 1995
+++ linux/fs/isofs/dir.c	Tue Aug  1 12:03:53 1995
@@ -48,9 +48,9 @@
  */
 struct inode_operations isofs_dir_inode_operations = {
 	&isofs_dir_operations,	/* default directory file-ops */
-	NULL,      	/* create */
+	NULL, 		     	/* create */
 	isofs_lookup,		/* lookup */
-	NULL, 		       /* link */
+	NULL, 			/* link */
 	NULL,       		/* unlink */
 	NULL,       		/* symlink */
 	NULL,       		/* mkdir */
diff -ru --new-file linux-1.2.12/fs/isofs/inode.c linux/fs/isofs/inode.c
--- linux-1.2.12/fs/isofs/inode.c	Wed Apr 12 21:57:08 1995
+++ linux/fs/isofs/inode.c	Tue Aug  1 12:03:53 1995
@@ -146,7 +146,7 @@
 		    break;
 		  }
 		}
-		else return 0;
+		else return 1;
 	}
 	return 1;
 }
@@ -344,6 +344,7 @@
 	
 	brelse(bh);
 	
+#if 0
 	printk("Max size:%ld   Log zone size:%ld\n",
 	       s->u.isofs_sb.s_max_size, 
 	       1UL << s->u.isofs_sb.s_log_zone_size);
@@ -351,6 +352,7 @@
 	       s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
 	       isonum_733 (rootp->extent) << s -> u.isofs_sb.s_log_zone_size);
 	if(high_sierra) printk("Disc in High Sierra format.\n");
+#endif
 	unlock_super(s);
 	/* set up enough so that it can read an inode */
 	
@@ -370,7 +372,7 @@
 	s->u.isofs_sb.s_mode = opt.mode & 0777;
 	s->s_blocksize = opt.blocksize;
 	s->s_blocksize_bits = blocksize_bits;
-	s->s_mounted = iget(s, isonum_733 (rootp->extent) << s -> u.isofs_sb.s_log_zone_size);
+	s->s_mounted = iget(s, isonum_733(rootp->extent) << s -> u.isofs_sb.s_log_zone_size, S_NONE);
 	unlock_super(s);
 
 	if (!(s->s_mounted)) {
diff -ru --new-file linux-1.2.12/fs/isofs/namei.c linux/fs/isofs/namei.c
--- linux-1.2.12/fs/isofs/namei.c	Wed Feb 22 07:15:14 1995
+++ linux/fs/isofs/namei.c	Tue Aug  1 12:03:53 1995
@@ -209,8 +209,7 @@
 	return NULL;
 }
 
-int isofs_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+int isofs_lookup(struct inode * dir,const char * name, int len, int i_flags, struct inode ** result)
 {
 	unsigned long ino, ino_back;
 	struct buffer_head * bh;
@@ -241,7 +240,7 @@
 	  brelse(bh);
 	};
 
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, S_NONE))) {
 		iput(dir);
 		return -EACCES;
 	}
diff -ru --new-file linux-1.2.12/fs/isofs/rock.c linux/fs/isofs/rock.c
--- linux-1.2.12/fs/isofs/rock.c	Mon Mar  6 10:26:57 1995
+++ linux/fs/isofs/rock.c	Tue Aug  1 12:03:53 1995
@@ -289,11 +289,13 @@
 	CHECK_CE;
 	break;
       case SIG('E','R'):
+#ifdef DEBUG
 	printk("ISO9660 Extensions: ");
 	{ int p;
 	  for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
 	};
 	  printk("\n");
+#endif
 	break;
       case SIG('P','X'):
 	inode->i_mode  = isonum_733(rr->u.PX.mode);
@@ -374,7 +376,7 @@
 #endif
 	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
 		inode -> i_sb -> u.isofs_sb.s_log_zone_size;
-	reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
+	reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent, S_NONE);
 	inode->i_mode = reloc->i_mode;
 	inode->i_nlink = reloc->i_nlink;
 	inode->i_uid = reloc->i_uid;
diff -ru --new-file linux-1.2.12/fs/minix/inode.c linux/fs/minix/inode.c
--- linux-1.2.12/fs/minix/inode.c	Tue Jan 10 16:02:18 1995
+++ linux/fs/minix/inode.c	Tue Aug  1 12:03:53 1995
@@ -202,7 +202,7 @@
 	/* set up enough so that it can read an inode */
 	s->s_dev = dev;
 	s->s_op = &minix_sops;
-	s->s_mounted = iget(s,MINIX_ROOT_INO);
+	s->s_mounted = iget(s, MINIX_ROOT_INO, S_NONE);
 	if (!s->s_mounted) {
 		s->s_dev = 0;
 		brelse(bh);
diff -ru --new-file linux-1.2.12/fs/minix/namei.c linux/fs/minix/namei.c
--- linux-1.2.12/fs/minix/namei.c	Mon Jan 23 09:38:29 1995
+++ linux/fs/minix/namei.c	Tue Aug  1 12:03:53 1995
@@ -108,8 +108,8 @@
 	return NULL;
 }
 
-int minix_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+int minix_lookup(struct inode * dir,const char * name, int len, int i_flags,
+	         struct inode ** result)
 {
 	int ino;
 	struct minix_dir_entry * de;
@@ -128,7 +128,7 @@
 	}
 	ino = de->inode;
 	brelse(bh);
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, i_flags))) {
 		iput(dir);
 		return -EACCES;
 	}
@@ -443,7 +443,7 @@
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_rmdir;
         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
@@ -500,7 +500,7 @@
 	bh = minix_find_entry(dir,name,len,&de);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_unlink;
 	retval = -EPERM;
 	if (S_ISDIR(inode->i_mode))
@@ -651,7 +651,7 @@
 		if (new_inode->i_dev != old_inode->i_dev)
 			break;
 		ino = new_inode->i_ino;
-		if (minix_lookup(new_inode,"..",2,&new_inode))
+		if (minix_lookup(new_inode, "..", 2, S_NONE, &new_inode))
 			break;
 		if (new_inode->i_ino == ino)
 			break;
@@ -699,7 +699,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, 0, S_NONE); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -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, 0, S_NONE);
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
diff -ru --new-file linux-1.2.12/fs/minix/symlink.c linux/fs/minix/symlink.c
--- linux-1.2.12/fs/minix/symlink.c	Mon Jan 23 09:38:29 1995
+++ linux/fs/minix/symlink.c	Tue Aug  1 12:03:53 1995
@@ -74,7 +74,7 @@
 	}
 	iput(inode);
 	current->link_count++;
-	error = open_namei(bh->b_data,flag,mode,res_inode,dir);
+	error = open_namei(bh->b_data, flag, mode, res_inode, dir);
 	current->link_count--;
 	brelse(bh);
 	return error;
diff -ru --new-file linux-1.2.12/fs/msdos/inode.c linux/fs/msdos/inode.c
--- linux-1.2.12/fs/msdos/inode.c	Sun Feb 26 17:52:02 1995
+++ linux/fs/msdos/inode.c	Tue Aug  1 12:03:53 1995
@@ -157,7 +157,7 @@
 				printk ("MSDOS FS: Invalid blocksize (512 or 1024)\n");
 			}
 		}
-		else return 0;
+		else return 1;
 	}
 	return 1;
 }
@@ -299,7 +299,7 @@
 	MSDOS_SB(sb)->fat_wait = NULL;
 	MSDOS_SB(sb)->fat_lock = 0;
 	MSDOS_SB(sb)->prev_free = 0;
-	if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+	if (!(sb->s_mounted = iget(sb, MSDOS_ROOT_INO, S_WRITE))) {
 		sb->s_dev = 0;
 		printk("get root inode failed\n");
 		MOD_DEC_USE_COUNT;
diff -ru --new-file linux-1.2.12/fs/msdos/misc.c linux/fs/msdos/misc.c
--- linux-1.2.12/fs/msdos/misc.c	Wed Mar 22 09:31:42 1995
+++ linux/fs/msdos/misc.c	Tue Aug  1 12:03:53 1995
@@ -349,7 +349,7 @@
     { \
 	done = IS_FREE(data[entry].name); \
 	if (done) { \
-	    inode = iget(sb,sector*MSDOS_DPS+entry); \
+	    inode = iget(sb, sector * MSDOS_DPS + entry, S_NONE); \
 	    if (inode) { \
 	    /* Directory slots of busy deleted files aren't available yet. */ \
 		done = !MSDOS_I(inode)->i_busy; \
diff -ru --new-file linux-1.2.12/fs/msdos/namei.c linux/fs/msdos/namei.c
--- linux-1.2.12/fs/msdos/namei.c	Mon Jan 23 09:38:29 1995
+++ linux/fs/msdos/namei.c	Tue Aug  1 12:03:53 1995
@@ -110,7 +110,7 @@
 }
 
 
-int msdos_lookup(struct inode *dir,const char *name,int len,
+int msdos_lookup(struct inode *dir,const char *name,int len, int i_flags,
     struct inode **result)
 {
 	struct super_block *sb = dir->i_sb;
@@ -136,7 +136,7 @@
 		ino = msdos_parent_ino(dir,0);
 		iput(dir);
 		if (ino < 0) return ino;
-		if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
+		if (!(*result = iget(dir->i_sb, ino, i_flags))) return -EACCES;
 		return 0;
 	}
 	PRINTK (("msdos_lookup 3\n"));
@@ -148,7 +148,7 @@
 	if (bh) brelse(bh);
 	PRINTK (("msdos_lookup 4.5\n"));
 /* printk("lookup: ino=%d\n",ino); */
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, i_flags))) {
 		iput(dir);
 		return -EACCES;
 	}
@@ -162,7 +162,7 @@
 	while (MSDOS_I(*result)->i_old) {
 		next = MSDOS_I(*result)->i_old;
 		iput(*result);
-		if (!(*result = iget(next->i_sb,next->i_ino))) {
+		if (!(*result = iget(next->i_sb, next->i_ino, i_flags))) {
 			fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
 			iput(dir);
 			return -ENOENT;
@@ -203,7 +203,7 @@
 	date_unix2dos(dir->i_mtime,&de->time,&de->date);
 	de->size = 0;
 	mark_buffer_dirty(bh, 1);
-	if ((*result = iget(dir->i_sb,ino)) != NULL)
+	if ((*result = iget(dir->i_sb, ino, S_WRITE)) != NULL)
 		msdos_read_inode(*result);
 	brelse(bh);
 	if (!*result) return -EIO;
@@ -362,7 +362,7 @@
 		goto rmdir_done;
 	if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
 	res = -ENOENT;
-	if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
+	if (!(inode = iget(dir->i_sb, ino, S_WRITE))) goto rmdir_done;
 	res = -ENOTDIR;
 	if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
 	res = -EBUSY;
@@ -401,7 +401,7 @@
 	inode = NULL;
 	if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
 		goto unlink_done;
-	if (!(inode = iget(dir->i_sb,ino))) {
+	if (!(inode = iget(dir->i_sb, ino, S_WRITE))) {
 		res = -ENOENT;
 		goto unlink_done;
 	}
@@ -451,7 +451,7 @@
 		return -ENOENT;
 	}
 	if (exists) {
-		if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
+		if (!(new_inode = iget(new_dir->i_sb, new_ino, S_NONE))) {
 			brelse(new_bh);
 			return -EIO;
 		}
@@ -478,7 +478,7 @@
 	memcpy(old_de->name,new_name,MSDOS_NAME);
 	mark_buffer_dirty(old_bh, 1);
 	if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
-		if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
+		if ((old_inode = iget(old_dir->i_sb, old_ino, S_NONE)) != NULL) {
 			msdos_read_inode(old_inode);
 			iput(old_inode);
 		}
@@ -499,13 +499,13 @@
 
 	if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
 	if (old_ino == new_dir->i_ino) return -EINVAL;
-	if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
+	if (!(walk = iget(new_dir->i_sb, new_dir->i_ino, S_NONE))) return -EIO;
 	while (walk->i_ino != MSDOS_ROOT_INO) {
 		ino = msdos_parent_ino(walk,1);
 		iput(walk);
 		if (ino < 0) return ino;
 		if (ino == old_ino) return -EINVAL;
-		if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
+		if (!(walk = iget(new_dir->i_sb, ino, S_NONE))) return -EIO;
 	}
 	iput(walk);
 	while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
@@ -515,7 +515,7 @@
 		if (error) return error;
 	}
 	exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
-	if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
+	if (!(old_inode = iget(old_dir->i_sb, old_ino, S_NONE))) {
 		brelse(free_bh);
 		if (exists) brelse(new_bh);
 		return -EIO;
@@ -528,7 +528,7 @@
 	}
 	new_inode = NULL; /* to make GCC happy */
 	if (exists) {
-		if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
+		if (!(new_inode = iget(new_dir->i_sb, new_ino, S_NONE))) {
 			iput(old_inode);
 			brelse(new_bh);
 			return -EIO;
@@ -550,7 +550,7 @@
 	}
 	memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
 	memcpy(free_de->name,new_name,MSDOS_NAME);
-	if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
+	if (!(free_inode = iget(new_dir->i_sb, free_ino, S_NONE))) {
 		free_de->name[0] = DELETED_FLAG;
 /*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
 		brelse(free_bh);
@@ -582,7 +582,7 @@
 	if (S_ISDIR(old_inode->i_mode)) {
 		if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
 		    &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
-		if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
+		if (!(dotdot_inode = iget(old_inode->i_sb, dotdot_ino, S_NONE))) {
 			brelse(dotdot_bh);
 			error = -EIO;
 			goto rename_done;
diff -ru --new-file linux-1.2.12/fs/namei.c linux/fs/namei.c
--- linux-1.2.12/fs/namei.c	Thu Apr  6 17:24:37 1995
+++ linux/fs/namei.c	Tue Aug  1 12:03:53 1995
@@ -136,13 +136,13 @@
 					return -ETXTBSY;
 			}
 		}
-	inode->i_wcount++;
+	inode->i_writecount++;
 	return 0;
 }
 
 void put_write_access(struct inode * inode)
 {
-	inode->i_wcount--;
+	inode->i_writecount--;
 }
 
 /*
@@ -151,7 +151,7 @@
  * fathers (pseudo-roots, mount-points)
  */
 int lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+           int i_flags, struct inode ** result)
 {
 	struct super_block * sb;
 	int perm;
@@ -186,7 +186,7 @@
 		*result = dir;
 		return 0;
 	}
-	return dir->i_op->lookup(dir,name,len,result);
+	return dir->i_op->lookup(dir, name, len, i_flags, result);
 }
 
 int follow_link(struct inode * dir, struct inode * inode,
@@ -212,8 +212,8 @@
  * dir_namei() returns the inode of the directory of the
  * specified name, and the name within that directory.
  */
-static int dir_namei(const char * pathname, int * namelen, const char ** name,
-	struct inode * base, struct inode ** res_inode)
+static int dir_namei(const char *pathname, int *namelen, const char **name,
+                     struct inode * base, int i_flags, struct inode **res_inode)
 {
 	char c;
 	const char * thisname;
@@ -238,7 +238,7 @@
 		if (!c)
 			break;
 		base->i_count++;
-		error = lookup(base,thisname,len,&inode);
+		error = lookup(base, thisname, len, i_flags, &inode);
 		if (error) {
 			iput(base);
 			return error;
@@ -258,24 +258,24 @@
 }
 
 static int _namei(const char * pathname, struct inode * base,
-	int follow_links, struct inode ** res_inode)
+                  int follow_links, int i_flags, struct inode ** res_inode)
 {
-	const char * basename;
+	const char *basename;
 	int namelen,error;
 	struct inode * inode;
 
 	*res_inode = NULL;
-	error = dir_namei(pathname,&namelen,&basename,base,&base);
+	error = dir_namei(pathname, &namelen, &basename, base, i_flags, &base);
 	if (error)
 		return error;
 	base->i_count++;	/* lookup uses up base */
-	error = lookup(base,basename,namelen,&inode);
+	error = lookup(base, basename, namelen, i_flags, &inode);
 	if (error) {
 		iput(base);
 		return error;
 	}
 	if (follow_links) {
-		error = follow_link(base,inode,0,0,&inode);
+		error = follow_link(base, inode, 0, 0, &inode);
 		if (error)
 			return error;
 	} else
@@ -284,14 +284,14 @@
 	return 0;
 }
 
-int lnamei(const char * pathname, struct inode ** res_inode)
+int lnamei(const char *pathname, int i_flags, struct inode **res_inode)
 {
 	int error;
 	char * tmp;
 
-	error = getname(pathname,&tmp);
+	error = getname(pathname, &tmp);
 	if (!error) {
-		error = _namei(tmp,NULL,0,res_inode);
+		error = _namei(tmp, NULL, 0, i_flags, res_inode);
 		putname(tmp);
 	}
 	return error;
@@ -304,14 +304,14 @@
  * Open, link etc use their own routines, but this is enough for things
  * like 'chmod' etc.
  */
-int namei(const char * pathname, struct inode ** res_inode)
+int namei(const char *pathname, int i_flags, struct inode **res_inode)
 {
 	int error;
 	char * tmp;
 
-	error = getname(pathname,&tmp);
+	error = getname(pathname, &tmp);
 	if (!error) {
-		error = _namei(tmp,NULL,1,res_inode);
+		error = _namei(tmp, NULL, 1, i_flags, res_inode);
 		putname(tmp);
 	}
 	return error;
@@ -331,7 +331,7 @@
  * for symlinks (where the permissions are checked later).
  */
 int open_namei(const char * pathname, int flag, int mode,
-	struct inode ** res_inode, struct inode * base)
+               struct inode ** res_inode, struct inode * base)
 {
 	const char * basename;
 	int namelen,error;
@@ -339,7 +339,7 @@
 
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
-	error = dir_namei(pathname,&namelen,&basename,base,&dir);
+	error = dir_namei(pathname, &namelen, &basename, base, S_WRITE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {			/* special case: '/usr/' etc */
@@ -358,7 +358,7 @@
 	dir->i_count++;		/* lookup eats the dir */
 	if (flag & O_CREAT) {
 		down(&dir->i_sem);
-		error = lookup(dir,basename,namelen,&inode);
+		error = lookup(dir, basename, namelen, S_WRITE, &inode);
 		if (!error) {
 			if (flag & O_EXCL) {
 				iput(inode);
@@ -372,14 +372,14 @@
 			error = -EROFS;
 		else {
 			dir->i_count++;		/* create eats the dir */
-			error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
+			error = dir->i_op->create(dir, basename, namelen, mode, res_inode);
 			up(&dir->i_sem);
 			iput(dir);
 			return error;
 		}
 		up(&dir->i_sem);
 	} else
-		error = lookup(dir,basename,namelen,&inode);
+		error = lookup(dir, basename, namelen, (flag & FMODE_WRITE) ? S_WRITE : S_NONE, &inode);
 	if (error) {
 		iput(dir);
 		return error;
@@ -445,7 +445,7 @@
 	struct inode * dir;
 
 	mode &= ~current->fs->umask;
-	error = dir_namei(filename,&namelen,&basename, NULL, &dir);
+	error = dir_namei(filename, &namelen, &basename, NULL, S_WRITE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {
@@ -502,7 +502,7 @@
 	int namelen, error;
 	struct inode * dir;
 
-	error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
+	error = dir_namei(pathname, &namelen, &basename, NULL, S_WRITE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {
@@ -548,7 +548,7 @@
 	int namelen, error;
 	struct inode * dir;
 
-	error = dir_namei(name,&namelen,&basename,NULL,&dir);
+	error = dir_namei(name, &namelen, &basename, NULL, S_WRITE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {
@@ -596,7 +596,7 @@
 	int namelen, error;
 	struct inode * dir;
 
-	error = dir_namei(name,&namelen,&basename,NULL,&dir);
+	error = dir_namei(name, &namelen, &basename, NULL, S_NONE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {
@@ -644,7 +644,7 @@
 	const char * basename;
 	int namelen, error;
 
-	error = dir_namei(newname,&namelen,&basename,NULL,&dir);
+	error = dir_namei(newname, &namelen, &basename, NULL, S_WRITE, &dir);
 	if (error)
 		return error;
 	if (!namelen) {
@@ -694,7 +694,7 @@
 	const char * basename;
 	int namelen, error;
 
-	error = dir_namei(newname,&namelen,&basename,NULL,&dir);
+	error = dir_namei(newname, &namelen, &basename, NULL, S_WRITE, &dir);
 	if (error) {
 		iput(oldinode);
 		return error;
@@ -746,7 +746,7 @@
 	char * to;
 	struct inode * oldinode;
 
-	error = namei(oldname, &oldinode);
+	error = namei(oldname, S_NONE, &oldinode);
 	if (error)
 		return error;
 	error = getname(newname,&to);
@@ -765,7 +765,7 @@
 	const char * old_base, * new_base;
 	int old_len, new_len, error;
 
-	error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
+	error = dir_namei(oldname, &old_len, &old_base, NULL, S_NONE, &old_dir);
 	if (error)
 		return error;
 	if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
@@ -778,7 +778,7 @@
 		iput(old_dir);
 		return -EPERM;
 	}
-	error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
+	error = dir_namei(newname, &new_len, &new_base, NULL, S_WRITE, &new_dir);
 	if (error) {
 		iput(old_dir);
 		return error;
diff -ru --new-file linux-1.2.12/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux-1.2.12/fs/nfs/dir.c	Mon Jan 23 09:38:29 1995
+++ linux/fs/nfs/dir.c	Tue Aug  1 12:03:53 1995
@@ -28,7 +28,7 @@
 static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
 			int count);
 static int nfs_readdir(struct inode *, struct file *, struct dirent *, int);
-static int nfs_lookup(struct inode *dir, const char *name, int len,
+static int nfs_lookup(struct inode *dir, const char *name, int len, int i_flags,
 		      struct inode **result);
 static int nfs_create(struct inode *dir, const char *name, int len, int mode,
 		      struct inode **result);
@@ -292,7 +292,7 @@
 }
 
 static int nfs_lookup(struct inode *dir, const char *__name, int len,
-		      struct inode **result)
+		      int i_flags, struct inode **result)
 {
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
diff -ru --new-file linux-1.2.12/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-1.2.12/fs/nfs/inode.c	Mon Mar  6 10:22:08 1995
+++ linux/fs/nfs/inode.c	Tue Aug  1 12:03:54 1995
@@ -194,7 +194,7 @@
 		}
 		fattr = &newfattr;
 	}
-	if (!(inode = iget(sb, fattr->fileid))) {
+	if (!(inode = iget(sb, fattr->fileid, S_NONE))) {
 		printk("nfs_fhget: iget failed\n");
 		return NULL;
 	}
diff -ru --new-file linux-1.2.12/fs/open.c linux/fs/open.c
--- linux-1.2.12/fs/open.c	Thu Jun  1 12:41:28 1995
+++ linux/fs/open.c	Tue Aug  1 12:03:54 1995
@@ -35,7 +35,7 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
 	if (error)
 		return error;
-	error = namei(path,&inode);
+	error = namei(path, S_NONE, &inode);
 	if (error)
 		return error;
 	if (!inode->i_sb->s_op->statfs) {
@@ -72,7 +72,7 @@
 	int error;
 	struct iattr newattrs;
 
-	error = namei(path,&inode);
+	error = namei(path, S_WRITE, &inode);
 	if (error)
 		return error;
 	if (S_ISDIR(inode->i_mode)) {
@@ -143,7 +143,7 @@
 	unsigned int flags = 0;
 	struct iattr newattrs;
 
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	if (IS_RDONLY(inode)) {
@@ -193,7 +193,7 @@
 	old_fsgid = current->fsgid;
 	current->fsuid = current->uid;
 	current->fsgid = current->gid;
-	res = namei(filename,&inode);
+	res = namei(filename, S_NONE, &inode);
 	if (!res) {
 		res = permission(inode, mode);
 		iput(inode);
@@ -208,7 +208,7 @@
 	struct inode * inode;
 	int error;
 
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	if (!S_ISDIR(inode->i_mode)) {
@@ -249,7 +249,7 @@
 	struct inode * inode;
 	int error;
 
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	if (!S_ISDIR(inode->i_mode)) {
@@ -294,7 +294,7 @@
 	int error;
 	struct iattr newattrs;
 
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	if (IS_RDONLY(inode)) {
@@ -321,6 +321,7 @@
 	struct inode * inode;
 	struct file * file;
 	struct iattr newattrs;
+	int error;
 
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		return -EBADF;
@@ -354,7 +355,16 @@
 		newattrs.ia_valid |= ATTR_MODE;
 	}
 	inode->i_dirt = 1;
-	return notify_change(inode, &newattrs);
+	if (inode->i_sb->dq_op && inode->i_sb->dq_op->initialize) {
+		inode->i_sb->dq_op->initialize(inode, -1);
+		if (inode->i_sb->dq_op->transfer)
+			inode->i_sb->dq_op->transfer(inode, &newattrs, 0);
+		error = notify_change(inode, &newattrs);
+		if (error && inode->i_sb->dq_op->transfer)
+			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
+		return error;
+	} else
+		return notify_change(inode, &newattrs);
 }
 
 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
@@ -363,7 +373,7 @@
 	int error;
 	struct iattr newattrs;
 
-	error = lnamei(filename,&inode);
+	error = lnamei(filename, S_WRITE, &inode);
 	if (error)
 		return error;
 	if (IS_RDONLY(inode)) {
@@ -398,7 +408,15 @@
 		newattrs.ia_valid |= ATTR_MODE;
 	}
 	inode->i_dirt = 1;
-	error = notify_change(inode, &newattrs);
+	if (inode->i_sb->dq_op && inode->i_sb->dq_op->initialize) {
+		inode->i_sb->dq_op->initialize(inode, -1);
+		if (inode->i_sb->dq_op->transfer)
+			inode->i_sb->dq_op->transfer(inode, &newattrs, 0);
+		error = notify_change(inode, &newattrs);
+		if (error && inode->i_sb->dq_op->transfer)
+			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
+	} else
+		error = notify_change(inode, &newattrs);
 	iput(inode);
 	return(error);
 }
diff -ru --new-file linux-1.2.12/fs/proc/base.c linux/fs/proc/base.c
--- linux-1.2.12/fs/proc/base.c	Sat Oct 22 15:41:18 1994
+++ linux/fs/proc/base.c	Tue Aug  1 12:03:54 1995
@@ -14,7 +14,7 @@
 #include <linux/stat.h>
 
 static int proc_readbase(struct inode *, struct file *, struct dirent *, int);
-static int proc_lookupbase(struct inode *,const char *,int,struct inode **);
+static int proc_lookupbase(struct inode *,const char *,int,int,struct inode **);
 
 static struct file_operations proc_base_operations = {
 	NULL,			/* lseek - default */
@@ -79,8 +79,8 @@
 	return !memcmp(name, de->name, len);
 }
 
-static int proc_lookupbase(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+static int proc_lookupbase(struct inode * dir,const char * name, int len, int i_flags,
+	                   struct inode ** result)
 {
 	unsigned int pid, ino;
 	int i;
@@ -112,7 +112,7 @@
 		iput(dir);
 		return -ENOENT;
 	}
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, S_NONE))) {
 		iput(dir);
 		return -ENOENT;
 	}
diff -ru --new-file linux-1.2.12/fs/proc/fd.c linux/fs/proc/fd.c
--- linux-1.2.12/fs/proc/fd.c	Tue Nov 29 20:51:58 1994
+++ linux/fs/proc/fd.c	Tue Aug  1 12:03:54 1995
@@ -14,7 +14,7 @@
 #include <linux/stat.h>
 
 static int proc_readfd(struct inode *, struct file *, struct dirent *, int);
-static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
+static int proc_lookupfd(struct inode *, const char *, int, int, struct inode **);
 
 static struct file_operations proc_fd_operations = {
 	NULL,			/* lseek - default */
@@ -51,7 +51,7 @@
 };
 
 static int proc_lookupfd(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+			 int i_flags, struct inode ** result)
 {
 	unsigned int ino, pid, fd, c;
 	struct task_struct * p;
@@ -75,7 +75,7 @@
 			*result = dir;
 			return 0;
 		}
-		if (!(*result = iget(sb,(pid << 16)+PROC_PID_INO))) {
+		if (!(*result = iget(sb, (pid << 16) + PROC_PID_INO, S_NONE))) {
 			iput(dir);
 			return -ENOENT;
 		}
@@ -109,7 +109,7 @@
 
 	ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
-	if (!(*result = iget(sb,ino)))
+	if (!(*result = iget(sb, ino, S_NONE)))
 		return -ENOENT;
 	return 0;
 }
diff -ru --new-file linux-1.2.12/fs/proc/inode.c linux/fs/proc/inode.c
--- linux-1.2.12/fs/proc/inode.c	Thu Jul 27 17:31:13 1995
+++ linux/fs/proc/inode.c	Tue Aug  1 12:03:54 1995
@@ -84,7 +84,7 @@
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
 	unlock_super(s);
-	if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) {
+	if (!(s->s_mounted = iget(s, PROC_ROOT_INO, S_NONE))) {
 		s->s_dev = 0;
 		printk("get root inode failed\n");
 		return NULL;
diff -ru --new-file linux-1.2.12/fs/proc/net.c linux/fs/proc/net.c
--- linux-1.2.12/fs/proc/net.c	Sun Feb 12 20:11:02 1995
+++ linux/fs/proc/net.c	Tue Aug  1 12:03:54 1995
@@ -41,7 +41,7 @@
 			 char * buf, int count);
 static int proc_readnetdir(struct inode *, struct file *,
 			   struct dirent *, int);
-static int proc_lookupnet(struct inode *,const char *,int,struct inode **);
+static int proc_lookupnet(struct inode *,const char *,int,int,struct inode **);
 
 /* the get_*_info() functions are in the net code, and are configured
    in via the standard mechanism... */
@@ -182,7 +182,7 @@
 #define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0])) - 1)
 
 static int proc_lookupnet(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+	                  int i_flags, struct inode ** result)
 {
 	struct proc_dir_entry *de;
 
@@ -196,7 +196,7 @@
 	for (de = net_dir ; de->name ; de++) {
 		if (!proc_match(len, name, de))
 			continue;
-		*result = iget(dir->i_sb, de->low_ino);
+		*result = iget(dir->i_sb, de->low_ino, S_NONE);
 		iput(dir);
 		if (!*result)
 			return -ENOENT;
diff -ru --new-file linux-1.2.12/fs/proc/root.c linux/fs/proc/root.c
--- linux-1.2.12/fs/proc/root.c	Wed Jan 11 07:55:07 1995
+++ linux/fs/proc/root.c	Tue Aug  1 12:03:54 1995
@@ -15,7 +15,7 @@
 #include <linux/config.h>
 
 static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
-static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
+static int proc_lookuproot(struct inode *,const char *,int,int,struct inode **);
 
 static struct file_operations proc_root_operations = {
 	NULL,			/* lseek - default */
@@ -85,7 +85,7 @@
 #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
 
 static int proc_lookuproot(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+	                   int i_flags, struct inode ** result)
 {
 	unsigned int pid, c;
 	int i, ino;
@@ -133,7 +133,7 @@
 		}
 		ino = (pid << 16) + 2;
 	}
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, S_NONE))) {
 		iput(dir);
 		return -ENOENT;
 	}
diff -ru --new-file linux-1.2.12/fs/read_write.c linux/fs/read_write.c
--- linux-1.2.12/fs/read_write.c	Mon Jan 23 22:04:10 1995
+++ linux/fs/read_write.c	Tue Aug  1 12:03:54 1995
@@ -121,7 +121,7 @@
 
 asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count)
 {
-	int error;
+	int error, nread;
 	struct file * file;
 	struct inode * inode;
 
@@ -136,7 +136,10 @@
 	error = verify_area(VERIFY_WRITE,buf,count);
 	if (error)
 		return error;
-	return file->f_op->read(inode,file,buf,count);
+	nread = file->f_op->read(inode,file,buf,count);
+	if (nread > 0)
+		current->io_usage += nread;
+	return nread;
 }
 
 asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
@@ -144,6 +147,7 @@
 	int error;
 	struct file * file;
 	struct inode * inode;
+	struct iattr newattrs;
 	int written;
 	
 	if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
@@ -163,10 +167,11 @@
 	 * the setgid bits
 	 */
 	if (written > 0 && !suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
-		struct iattr newattrs;
 		newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
 		newattrs.ia_valid = ATTR_MODE;
 		notify_change(inode, &newattrs);
 	}
+	if (written > 0)
+		current->io_usage += written;
 	return written;
 }
diff -ru --new-file linux-1.2.12/fs/stat.c linux/fs/stat.c
--- linux-1.2.12/fs/stat.c	Mon Jan 23 22:04:10 1995
+++ linux/fs/stat.c	Tue Aug  1 12:03:54 1995
@@ -102,7 +102,7 @@
 	error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf));
 	if (error)
 		return error;
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	cp_old_stat(inode,statbuf);
@@ -118,7 +118,7 @@
 	error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf));
 	if (error)
 		return error;
-	error = namei(filename,&inode);
+	error = namei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	cp_new_stat(inode,statbuf);
@@ -134,7 +134,7 @@
 	error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf));
 	if (error)
 		return error;
-	error = lnamei(filename,&inode);
+	error = lnamei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	cp_old_stat(inode,statbuf);
@@ -150,7 +150,7 @@
 	error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf));
 	if (error)
 		return error;
-	error = lnamei(filename,&inode);
+	error = lnamei(filename, S_NONE, &inode);
 	if (error)
 		return error;
 	cp_new_stat(inode,statbuf);
@@ -198,7 +198,7 @@
 	error = verify_area(VERIFY_WRITE,buf,bufsiz);
 	if (error)
 		return error;
-	error = lnamei(path,&inode);
+	error = lnamei(path, S_NONE, &inode);
 	if (error)
 		return error;
 	if (!inode->i_op || !inode->i_op->readlink) {
diff -ru --new-file linux-1.2.12/fs/super.c linux/fs/super.c
--- linux-1.2.12/fs/super.c	Wed Jan 18 08:31:40 1995
+++ linux/fs/super.c	Tue Aug  1 12:03:54 1995
@@ -2,16 +2,20 @@
  *  linux/fs/super.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  super.c contains code to handle: - mount structures
+ *                                   - super-block tables.
+ *                                   - mount systemcall
+ *                                   - umount systemcall
  */
 
-/*
- * super.c contains code to handle the super-block tables.
- */
 #include <stdarg.h>
 
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/mount.h>
+#include <linux/malloc.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
@@ -22,22 +26,111 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
- 
+
 extern struct file_operations * get_blkfops(unsigned int);
-extern struct file_operations * get_chrfops(unsigned int);
 
 extern void wait_for_keypress(void);
 
 extern int root_mountflags;
 
-struct super_block super_blocks[NR_SUPER];
-
 static int do_remount_sb(struct super_block *sb, int flags, char * data);
 
-/* this is initialized in init/main.c */
+/*
+ * This is initialized in init/main.c
+ */
 dev_t ROOT_DEV = 0;
 
-static struct file_system_type * file_systems = NULL;
+struct super_block super_blocks[NR_SUPER];
+static struct file_system_type *file_systems = (struct file_system_type *) NULL;
+static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL,
+                       *vfsmnttail = (struct vfsmount *) NULL,
+                       *mru_vfsmnt = (struct vfsmount *) NULL;
+
+/* 
+ * This part handles the management of the list of mounted filesystems.
+ * Superblock retrieval is also done with this list.
+ */
+struct vfsmount *lookup_vfsmnt(dev_t dev)
+{
+	register struct vfsmount *lptr;
+
+	if (vfsmntlist == (struct vfsmount *) 0)
+		return ((struct vfsmount *) 0);
+
+	if (mru_vfsmnt != (struct vfsmount *) 0 && mru_vfsmnt->mnt_dev == dev)
+		return (mru_vfsmnt);
+
+	for (lptr = vfsmntlist; lptr != (struct vfsmount *)0; lptr = lptr->mnt_next)
+		if (lptr->mnt_dev == dev)
+			return (lptr);
+
+	return ((struct vfsmount *) 0);
+	/* NOTREACHED */
+}
+
+static struct vfsmount *add_vfsmnt(dev_t dev, const char *dev_name,
+				   const char *dir_name)
+{
+	register struct vfsmount *lptr;
+	char *tmp;
+
+	if ((lptr = (struct vfsmount *)
+	     kmalloc(sizeof(struct vfsmount), GFP_KERNEL)) == (struct vfsmount *) 0)
+		panic("VFS: Unable to allocate memory for vfsmount devicelist");
+
+	memset(lptr, 0, sizeof(struct vfsmount));
+	lptr->mnt_dev = dev;
+	if (dev_name) {
+		if (!getname(dev_name, &tmp)) {
+			if ((lptr->mnt_devname =
+			    (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)0)
+				strcpy(lptr->mnt_devname, tmp);
+			putname(tmp);
+		}
+	}
+	if (dir_name) {
+		if (!getname(dir_name, &tmp)) {
+			if ((lptr->mnt_dirname =
+			    (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)0)
+			strcpy(lptr->mnt_dirname, tmp);
+			putname(tmp);
+		}
+	}
+
+	if (vfsmntlist == (struct vfsmount *)0)
+		vfsmntlist = vfsmnttail = lptr;
+	else {
+		vfsmnttail->mnt_next = lptr;
+		vfsmnttail = lptr;
+	}
+	return (lptr);
+}
+
+static void remove_vfsmnt(dev_t dev)
+{
+	register struct vfsmount *lptr, *tofree;
+
+	if (vfsmntlist == (struct vfsmount *) 0)
+		return;
+	lptr = vfsmntlist;
+	if (lptr->mnt_dev == dev) {
+		tofree = lptr;
+		vfsmntlist = lptr->mnt_next;
+	} else {
+		while (lptr->mnt_next != (struct vfsmount *) 0) {
+			if (lptr->mnt_next->mnt_dev == dev)
+				break;
+			lptr = lptr->mnt_next;
+		}
+		tofree = lptr->mnt_next;
+		if (vfsmnttail->mnt_dev == dev)
+			vfsmnttail = lptr;
+		lptr->mnt_next = lptr->mnt_next->mnt_next;
+	}
+	kfree(tofree->mnt_devname);
+	kfree(tofree->mnt_dirname);
+	kfree_s(tofree, sizeof(struct vfsmount));
+}
 
 int register_filesystem(struct file_system_type * fs)
 {
@@ -320,17 +413,30 @@
 			MAJOR(dev), MINOR(dev));
 }
 
+extern void acct_auto_close(dev_t dev);
+
 static int do_umount(dev_t dev)
 {
 	struct super_block * sb;
 	int retval;
 	
 	if (dev==ROOT_DEV) {
-		/* Special case for "unmounting" root.  We just try to remount
-		   it readonly, and sync() the device. */
+		/*
+		 * Special case for "unmounting" root. We just try to remount
+		 * it readonly, and sync() the device.
+		 */
 		if (!(sb=get_super(dev)))
 			return -ENOENT;
 		if (!(sb->s_flags & MS_RDONLY)) {
+#ifdef CONFIG_QUOTA
+			/*
+			 * Make sure all quotas are turned off on this device we need to mount
+			 * it readonly so no more writes by the quotasystem.
+			 * If later on the remount fails to bad there are no quotas running
+			 * anymore. Turn them on again by hand.
+			 */
+			(void) quota_off(dev, -1);
+#endif
 			fsync_dev(dev);
 			retval = do_remount_sb(sb, MS_RDONLY, 0);
 			if (retval)
@@ -343,6 +449,18 @@
 	if (!sb->s_covered->i_mount)
 		printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n",
 							MAJOR(dev), MINOR(dev));
+#ifdef CONFIG_QUOTA
+	/*
+	 * Before checking if the filesystem is still busy make sure the kernel
+	 * doesn't hold any quotafiles open on that device. If the umount fails
+	 * to bad there are no quotas running anymore. Turn them on again by hand.
+	 */
+	(void) quota_off(dev, -1);
+#endif
+	/*
+	 * The same as for quota is also true for the accounting file.
+	 */
+	acct_auto_close(dev);
 	if (!fs_may_umount(dev, sb->s_mounted))
 		return -EBUSY;
 	sb->s_covered->i_mount = NULL;
@@ -353,6 +471,7 @@
 	if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
 		sb->s_op->write_super(sb);
 	put_super(dev);
+	remove_vfsmnt(dev);
 	return 0;
 }
 
@@ -377,9 +496,9 @@
 
 	if (!suser())
 		return -EPERM;
-	retval = namei(name,&inode);
+	retval = namei(name, S_NONE, &inode);
 	if (retval) {
-		retval = lnamei(name,&inode);
+		retval = lnamei(name, S_NONE, &inode);
 		if (retval)
 			return retval;
 	}
@@ -428,13 +547,15 @@
  * We also have to flush all inode-data for this device, as the new mount
  * might need new info.
  */
-static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
+static int do_mount(dev_t dev, const char * dev_name, const char * dir_name,
+		    char * type, int flags, void * data)
 {
 	struct inode * dir_i;
 	struct super_block * sb;
+	struct vfsmount *vfsmnt;
 	int error;
 
-	error = namei(dir,&dir_i);
+	error = namei(dir_name, S_WRITE, &dir_i);
 	if (error)
 		return error;
 	if (dir_i->i_count != 1 || dir_i->i_mount) {
@@ -458,6 +579,9 @@
 		iput(dir_i);
 		return -EBUSY;
 	}
+	vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
+	vfsmnt->mnt_sb = sb;
+	vfsmnt->mnt_sem.count = 1;
 	sb->s_covered = dir_i;
 	dir_i->i_mount = sb->s_mounted;
 	return 0;		/* we don't iput(dir_i) - see umount */
@@ -496,7 +620,7 @@
 	struct inode *dir_i;
 	int retval;
 
-	retval = namei(dir,&dir_i);
+	retval = namei(dir, S_WRITE, &dir_i);
 	if (retval)
 		return retval;
 	if (dir_i != dir_i->i_sb->s_mounted) {
@@ -581,7 +705,7 @@
 	t = fstype->name;
 	fops = NULL;
 	if (fstype->requires_dev) {
-		retval = namei(dev_name,&inode);
+		retval = namei(dev_name, S_WRITE, &inode);
 		if (retval)
 			return retval;
 		if (!S_ISBLK(inode->i_mode)) {
@@ -628,7 +752,7 @@
 			return retval;
 		}
 	}
-	retval = do_mount(dev,dir_name,t,flags,(void *) page);
+	retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
 	free_page(page);
 	if (retval && fops && fops->release)
 		fops->release(inode, NULL);
@@ -640,10 +764,11 @@
 {
 	struct file_system_type * fs_type;
 	struct super_block * sb;
+	struct vfsmount *vfsmnt;
 	struct inode * inode, d_inode;
 	struct file filp;
 	int retval;
-
+  
 	memset(super_blocks, 0, sizeof(super_blocks));
 #ifdef CONFIG_BLK_DEV_FD
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
@@ -670,9 +795,9 @@
 	for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
 		if(retval)
 			break;
-		if (!fs_type->requires_dev)
-			continue;
-		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
+  		if (!fs_type->requires_dev)
+  			continue;
+  		sb = read_super(ROOT_DEV,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 */
@@ -683,6 +808,9 @@
 			printk ("VFS: Mounted root (%s filesystem)%s.\n",
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
+			vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+			vfsmnt->mnt_sb = sb;
+			vfsmnt->mnt_sem.count = 1;
 			return;
 		}
 	}
diff -ru --new-file linux-1.2.12/fs/sysv/inode.c linux/fs/sysv/inode.c
--- linux-1.2.12/fs/sysv/inode.c	Mon Jan 23 09:38:28 1995
+++ linux/fs/sysv/inode.c	Tue Aug  1 12:03:54 1995
@@ -485,7 +485,7 @@
 	/* set up enough so that it can read an inode */
 	sb->s_dev = dev;
 	sb->s_op = &sysv_sops;
-	sb->s_mounted = iget(sb,SYSV_ROOT_INO);
+	sb->s_mounted = iget(sb, SYSV_ROOT_INO, S_NONE);
 	unlock_super(sb);
 	if (!sb->s_mounted) {
 		printk("SysV FS: get root inode failed\n");
diff -ru --new-file linux-1.2.12/fs/sysv/namei.c linux/fs/sysv/namei.c
--- linux-1.2.12/fs/sysv/namei.c	Mon Jan 23 09:38:30 1995
+++ linux/fs/sysv/namei.c	Tue Aug  1 12:03:54 1995
@@ -104,8 +104,8 @@
 	return NULL;
 }
 
-int sysv_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+int sysv_lookup(struct inode * dir,const char * name, int len, int i_flags,
+                struct inode ** result)
 {
 	int ino;
 	struct sysv_dir_entry * de;
@@ -124,7 +124,7 @@
 	}
 	ino = de->inode;
 	brelse(bh);
-	if (!(*result = iget(dir->i_sb,ino))) {
+	if (!(*result = iget(dir->i_sb, ino, i_flags))) {
 		iput(dir);
 		return -EACCES;
 	}
@@ -435,7 +435,7 @@
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_rmdir;
         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
@@ -491,7 +491,7 @@
 	bh = sysv_find_entry(dir,name,len,&de);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget(dir->i_sb, de->inode)))
+	if (!(inode = iget(dir->i_sb, de->inode, S_NONE)))
 		goto end_unlink;
 	retval = -EPERM;
 	if (S_ISDIR(inode->i_mode))
@@ -647,7 +647,7 @@
 		if (new_inode->i_dev != old_inode->i_dev)
 			break;
 		ino = new_inode->i_ino;
-		if (sysv_lookup(new_inode,"..",2,&new_inode))
+		if (sysv_lookup(new_inode, "..", 2, S_NONE, &new_inode))
 			break;
 		if (new_inode->i_ino == ino) /* root dir reached ? */
 			break;
@@ -693,7 +693,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, 0, S_NONE); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -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, 0, S_NONE);
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
diff -ru --new-file linux-1.2.12/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- linux-1.2.12/fs/umsdos/dir.c	Wed Mar 22 09:31:42 1995
+++ linux/fs/umsdos/dir.c	Tue Aug  1 12:18:31 1995
@@ -158,8 +158,7 @@
 					info.f_pos = cur_f_pos;
 					*pt_f_pos = cur_f_pos;
 					umsdos_manglename (&info);
-					lret = umsdos_real_lookup (dir,info.fake.fname
-						,info.fake.len,&inode);
+					lret = umsdos_real_lookup (dir, info.fake.fname, info.fake.len, S_NONE, &inode);
 					PRINTK (("Cherche inode de %s lret %d flags %d\n"
 						,info.fake.fname,lret,entry.flags));
 					if (lret == 0
@@ -410,7 +409,7 @@
 {
 	int ret;
 	umsdos_patch_inode (dir,NULL,0);
-	ret = umsdos_real_lookup (dir,"..",2,result);
+	ret = umsdos_real_lookup (dir, "..", 2, S_NONE, result);
 	PRINTK (("result %d %x ",ret,*result));
 	if (ret == 0){
 		struct inode *adir = *result;
@@ -506,6 +505,7 @@
 	struct inode *dir,
 	const char *name,
 	int len,
+	int i_flags,
 	struct inode **result,	/* Will hold inode of the file, if successful */
 	int nopseudo)			/* Don't care about pseudo root mode */
 {
@@ -537,7 +537,7 @@
 				locate all the info on the parent, such a permissions
 				and owner.
 			*/
-			ret = umsdos_real_lookup (dir,"..",2,result);
+			ret = umsdos_real_lookup (dir, "..", 2, i_flags, result);
 			PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
 			if (ret == 0
 				&& *result != dir->i_sb->s_mounted
@@ -573,7 +573,7 @@
 				and return ENOENT.
 			*/
 			struct inode *inode;
-			ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
+			ret = umsdos_real_lookup (dir, info.fake.fname, info.fake.len, i_flags, result);
 			inode = *result;
 			if (inode == NULL){
 				printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
@@ -615,9 +615,10 @@
 	struct inode *dir,
 	const char *name,
 	int len,
+	int i_flags,
 	struct inode **result)	/* Will hold inode of the file, if successful */
 {
-	return umsdos_lookup_x(dir,name,len,result,0);
+	return umsdos_lookup_x(dir,name,len,i_flags, result,0);
 }
 /*
 	Locate the inode pointed by a (pseudo) hard link
@@ -652,9 +653,9 @@
 				if (*pt == '/') *pt++ = '\0';
 				if (dir->u.umsdos_i.i_emd_dir == 0){
 					/* This is a DOS directory */
-					ret = umsdos_rlookup_x(dir,start,len,result,1);
+					ret = umsdos_rlookup_x(dir,start,len,S_NONE, result,1);
 				}else{
-					ret = umsdos_lookup_x(dir,start,len,result,1);
+					ret = umsdos_lookup_x(dir,start,len,S_NONE, result,1);
 				}
 				PRINTK (("h2n lookup :%s: -> %d ",start,ret));
 				if (ret == 0 && *pt != '\0'){
diff -ru --new-file linux-1.2.12/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- linux-1.2.12/fs/umsdos/emd.c	Mon Jan 23 09:38:30 1995
+++ linux/fs/umsdos/emd.c	Tue Aug  1 12:03:54 1995
@@ -117,11 +117,11 @@
 {
 	struct inode *ret = NULL;
 	if (dir->u.umsdos_i.i_emd_dir != 0){
-		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
+		ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir, S_NONE);
 		PRINTK (("deja trouve %d %x [%d] "
 			,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
 	}else{
-		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
+		umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_NONE, &ret);
 		PRINTK (("emd_dir_lookup "));
 		if (ret != NULL){
 			PRINTK (("Find --linux "));
diff -ru --new-file linux-1.2.12/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- linux-1.2.12/fs/umsdos/inode.c	Wed Mar 22 09:31:43 1995
+++ linux/fs/umsdos/inode.c	Tue Aug  1 12:03:54 1995
@@ -75,11 +75,12 @@
 	struct inode *dir,
 	const char *name,
 	int len,
+	int i_flags,
 	struct inode **result)	/* Will hold inode of the file, if successful */
 {
 	int ret;
 	dir->i_count++;
-	ret = msdos_lookup (dir,name,len,result);
+	ret = msdos_lookup (dir, name, len, i_flags, result);
 	return ret;
 }
 /*
@@ -214,7 +215,7 @@
 	if (ino == 0){
 		printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
 	}else{
-		struct inode *dir = *result = iget(inode->i_sb,ino);
+		struct inode *dir = *result = iget(inode->i_sb, ino, S_NONE);
 		if (dir != NULL){
 			umsdos_patch_inode (dir,NULL,0);
 			ret = 0;
@@ -311,7 +312,7 @@
 				by MSDOS, so we can update its status.
 				See emd.c
 			*/
-			struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
+			struct inode *emd_owner = iget (inode->i_sb, i_emd_owner, S_NONE);
 			PRINTK (("notify change %p ",inode));
 			if (emd_owner == NULL){
 				printk ("UMSDOS: emd_owner = NULL ???");
@@ -448,21 +449,21 @@
 
 			struct inode *pseudo;
 			Printk (("Mounting root\n"));
-			if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
-					,UMSDOS_PSDROOT_LEN,&pseudo)==0
+			if (umsdos_real_lookup (sb->s_mounted, UMSDOS_PSDROOT_NAME
+					,UMSDOS_PSDROOT_LEN, S_NONE, &pseudo)==0
 				&& S_ISDIR(pseudo->i_mode)){
 				struct inode *etc = NULL;
 				struct inode *sbin = NULL;
 				int pseudo_ok = 0;
 				Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
-				if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
+				if (umsdos_real_lookup (pseudo, "etc", 3, S_NONE, &etc)==0
 					&& S_ISDIR(etc->i_mode)){
 					struct inode *init = NULL;
 					struct inode *rc = NULL;
 					Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
-					if ((umsdos_real_lookup (etc,"init",4,&init)==0
+					if ((umsdos_real_lookup (etc, "init", 4, S_NONE, &init)==0
 							&& S_ISREG(init->i_mode))
-						|| (umsdos_real_lookup (etc,"rc",2,&rc)==0
+						|| (umsdos_real_lookup (etc, "rc", 2, S_NONE, &rc)==0
 							&& S_ISREG(rc->i_mode))){
 						pseudo_ok = 1;
 					}
@@ -470,11 +471,11 @@
 					iput (rc);
 				}
 				if (!pseudo_ok
-					&& umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0
+					&& umsdos_real_lookup (pseudo, "sbin", 4, S_NONE, &sbin)==0
 					&& S_ISDIR(sbin->i_mode)){
 					struct inode *init = NULL;
 					Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
-					if (umsdos_real_lookup (sbin,"init",4,&init)==0
+					if (umsdos_real_lookup (sbin, "init", 4, S_NONE, &init)==0
 							&& S_ISREG(init->i_mode)){
 						pseudo_ok = 1;
 					}
diff -ru --new-file linux-1.2.12/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- linux-1.2.12/fs/umsdos/ioctl.c	Tue Jan 31 08:36:21 1995
+++ linux/fs/umsdos/ioctl.c	Tue Aug  1 12:03:54 1995
@@ -231,8 +231,8 @@
 					Return 0 if success.
 				*/
 				struct inode *inode;
-				ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
-					,data.dos_dirent.d_reclen,&inode);
+				ret = umsdos_real_lookup (dir, data.dos_dirent.d_name,
+					                  data.dos_dirent.d_reclen, S_NONE, &inode);
 				if (ret == 0){
 					data.stat.st_ino = inode->i_ino;
 					data.stat.st_mode = inode->i_mode;
diff -ru --new-file linux-1.2.12/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- linux-1.2.12/fs/umsdos/namei.c	Wed Jan 25 08:25:39 1995
+++ linux/fs/umsdos/namei.c	Tue Aug  1 12:18:31 1995
@@ -380,8 +380,8 @@
 								struct inode *inode;
 								new_dir->i_count++;
 								PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
-								ret = UMSDOS_lookup (new_dir,new_name,new_len
-										     ,&inode);
+								ret = UMSDOS_lookup (new_dir,new_name,new_len,
+										     S_NONE,&inode);
 chkstk();
 								if (ret != 0){
 									printk ("UMSDOS: partial rename for file %s\n"
@@ -719,8 +719,8 @@
 						sub-directory so it inherit UMSDOS semantic.
 					*/
 					struct inode *subdir;
-					ret = umsdos_real_lookup (dir,info.fake.fname
-						,info.fake.len,&subdir);
+					ret = umsdos_real_lookup (dir,info.fake.fname,
+						                  info.fake.len, S_NONE, &subdir);
 					if (ret == 0){
 						struct inode *result;
 						ret = msdos_create (subdir,UMSDOS_EMD_FILE
@@ -870,7 +870,7 @@
 	if (ret == 0){
 		struct inode *sdir;
 		dir->i_count++;
-		ret = UMSDOS_lookup (dir,name,len,&sdir);
+		ret = UMSDOS_lookup (dir,name,len,S_NONE,&sdir);
 		PRINTK (("rmdir lookup %d ",ret));
 		if (ret == 0){
 			int empty;
@@ -961,13 +961,13 @@
 						   */
 						struct inode *inode;
 						dir->i_count++;
-						ret = UMSDOS_lookup (dir,name,len,&inode);
+						ret = UMSDOS_lookup (dir,name,len,S_NONE,&inode);
 						if (ret == 0){
 							PRINTK (("unlink nlink = %d ",inode->i_nlink));
 							inode->i_nlink--;
 							if (inode->i_nlink == 0){
-								struct inode *hdir = iget(inode->i_sb
-											  ,inode->u.umsdos_i.i_dir_owner);
+								struct inode *hdir = iget(inode->i_sb,
+											  inode->u.umsdos_i.i_dir_owner, S_NONE);
 								struct umsdos_dirent entry;
 								ret = umsdos_inode2entry (hdir,inode,&entry);
 								if (ret == 0){
diff -ru --new-file linux-1.2.12/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- linux-1.2.12/fs/umsdos/rdir.c	Wed Mar 22 09:31:43 1995
+++ linux/fs/umsdos/rdir.c	Tue Aug  1 12:18:31 1995
@@ -75,6 +75,7 @@
 	struct inode *dir,
 	const char *name,
 	int len,
+	int i_flags,
 	struct inode **result,	/* Will hold inode of the file, if successful */
 	int nopseudo)			/* Don't care about pseudo root mode */
 							/* so locating "linux" will work */
@@ -94,7 +95,7 @@
 			is the pseudo root (c:\linux).
 		*/
 	}else{
-		ret = umsdos_real_lookup (dir,name,len,result);
+		ret = umsdos_real_lookup (dir, name, len, i_flags, result);
 		if (ret == 0){
 			struct inode *inode = *result;
 			if (inode == pseudo_root && !nopseudo){
@@ -119,9 +120,10 @@
 	struct inode *dir,
 	const char *name,
 	int len,
+	int i_flags,
 	struct inode **result)	/* Will hold inode of the file, if successful */
 {
-	return umsdos_rlookup_x(dir,name,len,result,0);
+	return umsdos_rlookup_x(dir,name,len,i_flags,result,0);
 }
 
 static int UMSDOS_rrmdir (
@@ -161,7 +163,7 @@
 		if (ret == -ENOTEMPTY){
 			struct inode *sdir;
 			dir->i_count++;
-			ret = UMSDOS_rlookup (dir,name,len,&sdir);
+			ret = UMSDOS_rlookup (dir,name,len,S_NONE,&sdir);
 			PRINTK (("rrmdir lookup %d ",ret));
 			if (ret == 0){
 				int empty;
diff -ru --new-file linux-1.2.12/fs/xiafs/inode.c linux/fs/xiafs/inode.c
--- linux-1.2.12/fs/xiafs/inode.c	Mon Jan 23 09:38:28 1995
+++ linux/fs/xiafs/inode.c	Tue Aug  1 12:03:55 1995
@@ -152,7 +152,7 @@
     /* set up enough so that it can read an inode */
     s->s_dev = dev;
     s->s_op = &xiafs_sops;
-    s->s_mounted = iget(s, _XIAFS_ROOT_INO);
+    s->s_mounted = iget(s, _XIAFS_ROOT_INO, S_NONE);
     if (!s->s_mounted) 
         goto xiafs_read_super_fail;
     unlock_super(s);
diff -ru --new-file linux-1.2.12/fs/xiafs/namei.c linux/fs/xiafs/namei.c
--- linux-1.2.12/fs/xiafs/namei.c	Mon Jan 23 09:38:30 1995
+++ linux/fs/xiafs/namei.c	Tue Aug  1 12:03:55 1995
@@ -116,8 +116,8 @@
     return NULL;
 }
 
-int xiafs_lookup(struct inode * dir, const char * name, int len,
-	       struct inode ** result)
+int xiafs_lookup(struct inode * dir, const char * name, int len, int i_flags,
+                 struct inode ** result)
 {
     int ino;
     struct xiafs_direct * dep;
@@ -136,7 +136,7 @@
     }
     ino = dep->d_ino;
     brelse(bh);
-    if (!(*result = iget(dir->i_sb, ino))) {
+    if (!(*result = iget(dir->i_sb, ino, S_NONE))) {
         iput(dir);
 	return -EACCES;
     }
@@ -499,7 +499,7 @@
     if (!bh)
         goto end_rmdir;
     retval = -EPERM;
-    if (!(inode = iget(dir->i_sb, de->d_ino)))
+    if (!(inode = iget(dir->i_sb, de->d_ino, S_NONE)))
         goto end_rmdir;
     if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
@@ -551,7 +551,7 @@
     bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
     if (!bh)
         goto end_unlink;
-    if (!(inode = iget(dir->i_sb, de->d_ino)))
+    if (!(inode = iget(dir->i_sb, de->d_ino, S_NONE)))
         goto end_unlink;
     retval = -EPERM;
     if (S_ISDIR(inode->i_mode))
@@ -692,7 +692,7 @@
 	if (new_inode->i_dev != old_inode->i_dev)
 	    break;
 	ino = new_inode->i_ino;
-	if (xiafs_lookup(new_inode,"..",2,&new_inode))
+	if (xiafs_lookup(new_inode, "..", 2, S_NONE, &new_inode))
 	    break;
 	if (new_inode->i_ino == ino)
 	    break;
@@ -730,7 +730,7 @@
     retval = -ENOENT;
     if (!old_bh)
         goto end_rename;
-    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
+    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0, S_NONE); /* don't cross mnt-points */
     if (!old_inode)
         goto end_rename;
     retval = -EPERM;
@@ -740,7 +740,7 @@
         goto end_rename;
     new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
     if (new_bh) {
-        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
+        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0, S_NONE);
 	if (!new_inode) {
 	    brelse(new_bh);
 	    new_bh = NULL;
diff -ru --new-file linux-1.2.12/include/linux/acct.h linux/include/linux/acct.h
--- linux-1.2.12/include/linux/acct.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/acct.h	Tue Aug  1 12:03:55 1995
@@ -0,0 +1,28 @@
+#ifndef __LINUX_ACCT_H
+#define __LINUX_ACCT_H
+
+#define ACCT_COMM 16
+
+struct acct
+{
+   char          ac_comm[ACCT_COMM];	/* Accounting command name */
+   time_t        ac_utime;		/* Accounting user time */
+   time_t        ac_stime;		/* Accounting system time */
+   time_t        ac_etime;		/* Accounting elapsed time */
+   time_t        ac_btime;		/* Beginning time */
+   uid_t         ac_uid;		/* Accounting user ID */
+   gid_t         ac_gid;		/* Accounting group ID */
+   dev_t         ac_tty;		/* controlling tty */
+   char          ac_flag;		/* Accounting flag */
+   unsigned long ac_mem;		/* Pages of memory used */
+   unsigned long ac_io;			/* Number of bytes read/written */
+};
+
+#define AFORK	0001	/* has executed fork, but no exec */
+#define ASU	0002	/* used super-user privileges */
+#define ACORE	0004	/* dumped core */
+#define AXSIG	0010	/* killed by a signal */
+
+#define AHZ     100
+
+#endif
diff -ru --new-file linux-1.2.12/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- linux-1.2.12/include/linux/ext2_fs.h	Wed Mar 22 09:33:59 1995
+++ linux/include/linux/ext2_fs.h	Tue Aug  1 12:03:55 1995
@@ -411,9 +411,9 @@
 extern int ext2_permission (struct inode *, int);
 
 /* balloc.c */
-extern int ext2_new_block (struct super_block *, unsigned long,
+extern int ext2_new_block (const struct inode *, unsigned long,
 			   __u32 *, __u32 *);
-extern void ext2_free_blocks (struct super_block *, unsigned long,
+extern void ext2_free_blocks (const struct inode *, unsigned long,
 			      unsigned long);
 extern unsigned long ext2_count_free_blocks (struct super_block *);
 extern void ext2_check_blocks_bitmap (struct super_block *);
@@ -458,7 +458,7 @@
 
 /* namei.c */
 extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *,const char *, int, struct inode **);
+extern int ext2_lookup (struct inode *,const char *, int, int, struct inode **);
 extern int ext2_create (struct inode *,const char *, int, int,
 			struct inode **);
 extern int ext2_mkdir (struct inode *, const char *, int, int);
diff -ru --new-file linux-1.2.12/include/linux/ext_fs.h linux/include/linux/ext_fs.h
--- linux-1.2.12/include/linux/ext_fs.h	Sun Jul 24 16:39:46 1994
+++ linux/include/linux/ext_fs.h	Tue Aug  1 12:03:55 1995
@@ -63,7 +63,7 @@
 extern int ext_open(struct inode * inode, struct file * filp);
 extern void ext_release(struct inode * inode, struct file * filp);
 extern int ext_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result);
+                      int i_flags, struct inode ** result);
 extern int ext_create(struct inode * dir,const char * name, int len, int mode,
 	struct inode ** result);
 extern int ext_mkdir(struct inode * dir, const char * name, int len, int mode);
diff -ru --new-file linux-1.2.12/include/linux/fs.h linux/include/linux/fs.h
--- linux-1.2.12/include/linux/fs.h	Thu Feb 23 12:32:05 1995
+++ linux/include/linux/fs.h	Tue Aug  1 12:03:55 1995
@@ -36,6 +36,9 @@
 #define MAY_WRITE 2
 #define MAY_READ 4
 
+#define FMODE_READ 1
+#define FMODE_WRITE 2
+
 #define READ 0
 #define WRITE 1
 #define READA 2		/* read-ahead - don't pause */
@@ -63,15 +66,16 @@
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
-#define MS_RDONLY	 1 /* mount read-only */
-#define MS_NOSUID	 2 /* ignore suid and sgid bits */
-#define MS_NODEV	 4 /* disallow access to device special files */
-#define MS_NOEXEC	 8 /* disallow program execution */
-#define MS_SYNCHRONOUS	16 /* writes are synced at once */
-#define MS_REMOUNT	32 /* alter flags of a mounted FS */
-
-#define S_APPEND    256 /* append-only file */
-#define S_IMMUTABLE 512 /* immutable file */
+#define S_NONE		 0	/* No special inode flags */
+#define MS_RDONLY	 1	/* Mount read-only */
+#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
+#define MS_NODEV	 4	/* Disallow access to device special files */
+#define MS_NOEXEC	 8	/* Disallow program execution */
+#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
+#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
+#define S_WRITE		128	/* Write on file/directory/symlink */
+#define S_APPEND	256	/* Append-only file */
+#define S_IMMUTABLE	512	/* Immutable file */
 
 /*
  * Flags that can be altered by MS_REMOUNT
@@ -81,8 +85,8 @@
 /*
  * Magic mount flag number. Has to be or-ed to the flag values.
  */
-#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */
-#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */
+#define MS_MGC_VAL 0xC0ED0000	/* magic flag number to indicate "new" flags */
+#define MS_MGC_MSK 0xffff0000	/* magic flag number mask */
 
 /*
  * Note that read-only etc flags are inode-specific: setting some file-system
@@ -98,6 +102,7 @@
 #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
 #define IS_SYNC(inode) ((inode)->i_flags & MS_SYNCHRONOUS)
 
+#define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE)
 #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
 
@@ -200,6 +205,8 @@
 	time_t		ia_ctime;
 };
 
+#include <linux/quota.h>
+
 struct inode {
 	dev_t		i_dev;
 	unsigned long	i_ino;
@@ -216,17 +223,17 @@
 	unsigned long	i_blocks;
 	unsigned long	i_version;
 	struct semaphore i_sem;
-	struct inode_operations * i_op;
-	struct super_block * i_sb;
-	struct wait_queue * i_wait;
-	struct file_lock * i_flock;
-	struct vm_area_struct * i_mmap;
-	struct inode * i_next, * i_prev;
-	struct inode * i_hash_next, * i_hash_prev;
-	struct inode * i_bound_to, * i_bound_by;
-	struct inode * i_mount;
+	struct inode_operations *i_op;
+	struct super_block *i_sb;
+	struct wait_queue *i_wait;
+	struct file_lock *i_flock;
+	struct vm_area_struct *i_mmap;
+	struct dquot *i_dquot[MAXQUOTAS];
+	struct inode *i_next, *i_prev;
+	struct inode *i_hash_next, *i_hash_prev;
+	struct inode *i_bound_to, *i_bound_by;
+	struct inode *i_mount;
 	unsigned short i_count;
-	unsigned short i_wcount;
 	unsigned short i_flags;
 	unsigned char i_lock;
 	unsigned char i_dirt;
@@ -234,6 +241,7 @@
 	unsigned char i_sock;
 	unsigned char i_seek;
 	unsigned char i_update;
+	unsigned short i_writecount;
 	union {
 		struct pipe_inode_info pipe_i;
 		struct minix_inode_info minix_i;
@@ -304,6 +312,7 @@
 	unsigned char s_dirt;
 	struct file_system_type *s_type;
 	struct super_operations *s_op;
+	struct dquot_operations *dq_op;
 	unsigned long s_flags;
 	unsigned long s_magic;
 	unsigned long s_time;
@@ -343,7 +352,7 @@
 struct inode_operations {
 	struct file_operations * default_file_ops;
 	int (*create) (struct inode *,const char *,int,int,struct inode **);
-	int (*lookup) (struct inode *,const char *,int,struct inode **);
+	int (*lookup) (struct inode *,const char *,int,int,struct inode **);
 	int (*link) (struct inode *,struct inode *,const char *,int);
 	int (*unlink) (struct inode *,const char *,int);
 	int (*symlink) (struct inode *,const char *,int,const char *);
@@ -370,6 +379,16 @@
 	int (*remount_fs) (struct super_block *, int *, char *);
 };
 
+struct dquot_operations {
+	void (*initialize) (struct inode *, short);
+	void (*drop) (struct inode *);
+	int (*alloc_block) (const struct inode *, unsigned long);
+	int (*alloc_inode) (const struct inode *, unsigned long);
+	void (*free_block) (const struct inode *, unsigned long);
+	void (*free_inode) (const struct inode *, unsigned long);
+	int (*transfer) (struct inode *, struct iattr *, char);
+};
+
 struct file_system_type {
 	struct super_block *(*read_super) (struct super_block *, void *, int);
 	char *name;
@@ -466,8 +485,8 @@
 extern void sync_supers(dev_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 ** res_inode);
-extern int lnamei(const char * pathname, struct inode ** res_inode);
+extern int namei(const char * pathname, int i_flags, struct inode ** res_inode);
+extern int lnamei(const char * pathname, int i_flags, struct inode ** res_inode);
 extern int permission(struct inode * inode,int mask);
 extern int get_write_access(struct inode * inode);
 extern void put_write_access(struct inode * inode);
@@ -475,7 +494,7 @@
 	struct inode ** res_inode, struct inode * base);
 extern int do_mknod(const char * filename, int mode, dev_t dev);
 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,int crsmnt,int i_flags);
 extern struct inode * get_empty_inode(void);
 extern void insert_inode_hash(struct inode *);
 extern void clear_inode(struct inode *);
@@ -518,9 +537,9 @@
 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)
+extern inline struct inode * iget(struct super_block * sb,int nr, int i_flags)
 {
-	return __iget(sb,nr,1);
+	return __iget(sb, nr, 1, i_flags);
 }
 
 #endif /* __KERNEL__ */
diff -ru --new-file linux-1.2.12/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- linux-1.2.12/include/linux/iso_fs.h	Sat Aug  6 19:17:43 1994
+++ linux/include/linux/iso_fs.h	Tue Aug  1 12:03:55 1995
@@ -167,7 +167,7 @@
 extern int isofs_open(struct inode * inode, struct file * filp);
 extern void isofs_release(struct inode * inode, struct file * filp);
 extern int isofs_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result);
+			int i_flags, struct inode ** result);
 extern unsigned long isofs_count_free_inodes(struct super_block *sb);
 extern int isofs_new_block(int dev);
 extern int isofs_free_block(int dev, int block);
diff -ru --new-file linux-1.2.12/include/linux/kernel.h linux/include/linux/kernel.h
--- linux-1.2.12/include/linux/kernel.h	Wed Jan  4 20:16:05 1995
+++ linux/include/linux/kernel.h	Tue Aug  1 12:03:55 1995
@@ -54,19 +54,6 @@
 asmlinkage int printk(const char * fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 
-/*
- * This is defined as a macro, but at some point this might become a
- * real subroutine that sets a flag if it returns true (to do
- * BSD-style accounting where the process is flagged if it uses root
- * privs).  The implication of this is that you should do normal
- * permissions checks first, and check suser() last.
- *
- * "suser()" checks against the effective user id, while "fsuser()"
- * is used for file permission checking and checks against the fsuid..
- */
-#define suser() (current->euid == 0)
-#define fsuser() (current->fsuid == 0)
-
 #endif /* __KERNEL__ */
 
 #define SI_LOAD_SHIFT	16
diff -ru --new-file linux-1.2.12/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- linux-1.2.12/include/linux/minix_fs.h	Mon Jan  9 06:59:23 1995
+++ linux/include/linux/minix_fs.h	Tue Aug  1 12:03:55 1995
@@ -82,7 +82,7 @@
 #ifdef __KERNEL__
 
 extern int minix_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result);
+                        int i_flags, struct inode ** result);
 extern int minix_create(struct inode * dir,const char * name, int len, int mode,
 	struct inode ** result);
 extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode);
diff -ru --new-file linux-1.2.12/include/linux/mount.h linux/include/linux/mount.h
--- linux-1.2.12/include/linux/mount.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/mount.h	Tue Aug  1 12:03:55 1995
@@ -0,0 +1,30 @@
+/*
+ *
+ * Definitions for mount interface. This describes the in the kernel build 
+ * linkedlist with mounted filesystems.
+ *
+ * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net> <mvw@cistron.nl>
+ *
+ * Version: $Id: mount.h,v 1.3 1994/07/20 22:01:00 mvw Exp mvw $
+ *
+ */
+#ifndef _LINUX_MOUNT_H
+#define _LINUX_MOUNT_H
+
+struct vfsmount
+{
+   dev_t mnt_dev;                      /* Device this applies to */
+   char *mnt_devname;                  /* Name of device e.g. /dev/dsk/hda1 */
+   char *mnt_dirname;                  /* Name of directory mounted on */
+   unsigned int mnt_flags;             /* Flags of this device */
+   struct semaphore mnt_sem;           /* lock device while I/O in progress */
+   struct super_block *mnt_sb;         /* pointer to superblock */
+   struct file *mnt_quotas[MAXQUOTAS]; /* fp's to quotafiles */
+   time_t mnt_iexp[MAXQUOTAS];         /* expiretime for inodes */
+   time_t mnt_bexp[MAXQUOTAS];         /* expiretime for blocks */
+   struct vfsmount *mnt_next;          /* pointer to next in linkedlist */
+};
+
+struct vfsmount *lookup_vfsmnt(dev_t dev);
+
+#endif /* _LINUX_MOUNT_H */
diff -ru --new-file linux-1.2.12/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- linux-1.2.12/include/linux/msdos_fs.h	Sun Feb 26 17:52:02 1995
+++ linux/include/linux/msdos_fs.h	Tue Aug  1 12:03:55 1995
@@ -143,7 +143,7 @@
 /* namei.c */
 
 extern int msdos_lookup(struct inode *dir,const char *name,int len,
-	struct inode **result);
+                        int i_flags, struct inode **result);
 extern int msdos_create(struct inode *dir,const char *name,int len,int mode,
 	struct inode **result);
 extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode);
diff -ru --new-file linux-1.2.12/include/linux/ppp.h linux/include/linux/ppp.h
--- linux-1.2.12/include/linux/ppp.h	Wed Aug 10 18:26:43 1994
+++ linux/include/linux/ppp.h	Tue Aug  1 12:03:55 1995
@@ -5,8 +5,17 @@
    Michael Callahan <callahan@maths.ox.ac.uk>
    Nov. 4 1993 */
 
-/* how many PPP units? */
-#define PPP_NRUNIT     4
+/* how many PPP units? 
+   It is possible to extend the number of PPP/SLIP ports
+   to more than 16 but you will have to change Space.c and slip.c
+   in drivers/net
+   Danny ter Haar <dth@cistron.nl> */
+
+#if defined(SL_SLIP_LOTS)
+   #define PPP_NRUNIT     16
+#else
+   #define PPP_NRUNIT	   4
+#endif
 
 #define PPP_VERSION  "0.2.7"
 
diff -ru --new-file linux-1.2.12/include/linux/quota.h linux/include/linux/quota.h
--- linux-1.2.12/include/linux/quota.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/quota.h	Tue Aug  1 12:03:55 1995
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *   This product includes software developed by the University of
+ *   California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Version: $Id: quota.h,v 1.8 1995/03/11 11:43:07 mvw Exp mvw $
+ */
+
+#ifndef _LINUX_QUOTA_
+#define _LINUX_QUOTA_
+
+#include <linux/errno.h>
+
+/*
+ * Convert diskblocks to blocks and the other way around.
+ * currently only to fool the BSD source. :-)
+ */
+#define dbtob(num) (num << 10)
+#define btodb(num) (num >> 10)
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+
+#define MAXQUOTAS 2
+#define USRQUOTA  0		/* element used for user quotas */
+#define GRPQUOTA  1		/* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+   "user",      /* USRQUOTA */ \
+   "group",   /* GRPQUOTA */ \
+   "undefined", \
+};
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "staff"
+
+#define NR_DQHASH 43            /* Just an arbitrary number any suggestions ? */
+#define NR_DQUOTS 256           /* Number of quotas active at one time */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK  0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_QUOTAON  0x0100	/* enable quotas */
+#define Q_QUOTAOFF 0x0200	/* disable quotas */
+#define Q_GETQUOTA 0x0300	/* get limits and usage */
+#define Q_SETQUOTA 0x0400	/* set limits and usage */
+#define Q_SETUSE   0x0500	/* set usage */
+#define Q_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
+#define Q_SETQLIM  0x0700	/* set limits */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct dqblk
+  {
+    __u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+    __u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
+    __u32 dqb_curblocks;	/* current block count */
+    __u32 dqb_ihardlimit;	/* maximum # allocated inodes */
+    __u32 dqb_isoftlimit;	/* preferred inode limit */
+    __u32 dqb_curinodes;	/* current # allocated inodes */
+    time_t dqb_btime;		/* time limit for excessive disk use */
+    time_t dqb_itime;		/* time limit for excessive files */
+  };
+
+/*
+ * Shorthand notation.
+ */
+#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
+#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
+#define	dq_curblocks	dq_dqb.dqb_curblocks
+#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
+#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
+#define	dq_curinodes	dq_dqb.dqb_curinodes
+#define	dq_btime	dq_dqb.dqb_btime
+#define	dq_itime	dq_dqb.dqb_itime
+
+#define dqoff(UID)      ((off_t)((UID) * sizeof (struct dqblk)))
+
+#ifdef __KERNEL__
+
+/*
+ * Maximum lenght of a message generated in the quota system,
+ * that needs to be kicked onto the tty.
+ */
+#define MAX_QUOTA_MESSAGE 75
+
+#define DQ_LOCKED     0x01	/* locked for update */
+#define DQ_WANT       0x02	/* wanted for update */
+#define DQ_MOD        0x04	/* dquot modified since read */
+#define DQ_BLKS       0x10	/* uid/gid has been warned about blk limit */
+#define DQ_INODES     0x20	/* uid/gid has been warned about inode limit */
+#define DQ_FAKE       0x40	/* no limits only usage */
+
+struct dquot
+{
+   unsigned int dq_id;		/* id this applies to (uid, gid) */
+   short dq_type;		/* type of quota */
+   dev_t dq_dev;                /* Device this applies to */
+   short dq_flags;		/* see DQ_* */
+   short dq_count;		/* reference count */
+   struct vfsmount *dq_mnt;     /* vfsmountpoint this applies to */
+   struct dqblk dq_dqb;         /* diskquota usage */
+   struct wait_queue *dq_wait;	/* pointer to waitqueue */
+   struct dquot *dq_prev;	/* pointer to prev dquot */
+   struct dquot *dq_next;	/* pointer to next dquot */
+   struct dquot *dq_hash_prev;	/* pointer to prev dquot */
+   struct dquot *dq_hash_next;	/* pointer to next dquot */
+};
+
+#define NODQUOT (struct dquot *)NULL
+
+/*
+ * Flags used for set_dqblk.
+ */
+#define QUOTA_SYSCALL     0x01
+#define SET_QUOTA         0x02
+#define SET_USE           0x04
+#define SET_QLIMIT        0x08
+
+#define QUOTA_OK          0
+#define NO_QUOTA          1
+
+/*
+ * declaration of quota_function calls in kernel.
+ */
+int quota_off (dev_t dev, short type);
+int sync_dquots (dev_t dev, short type);
+
+extern void dquot_initialize(struct inode *inode, short type);
+extern void dquot_drop(struct inode *inode);
+extern int dquot_alloc_block(const struct inode *inode, unsigned long number);
+extern int dquot_alloc_inode(const struct inode *inode, unsigned long number);
+extern void dquot_free_block(const struct inode *inode, unsigned long number);
+extern void dquot_free_inode(const struct inode *inode, unsigned long number);
+extern int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction);
+
+extern void invalidate_dquots(dev_t dev, short type);
+extern int quota_off(dev_t dev, short type);
+extern int sync_dquots(dev_t dev, short type);
+
+#else
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int quotactl __P ((int, const char *, int, caddr_t));
+__END_DECLS
+
+#endif /* __KERNEL__ */
+#endif /* _QUOTA_ */
diff -ru --new-file linux-1.2.12/include/linux/sched.h linux/include/linux/sched.h
--- linux-1.2.12/include/linux/sched.h	Tue May  9 05:40:36 1995
+++ linux/include/linux/sched.h	Tue Aug  1 12:03:56 1995
@@ -176,6 +176,7 @@
 	long utime, stime, cutime, cstime, start_time;
 	struct rlimit rlim[RLIM_NLIMITS]; 
 	unsigned short used_math;
+	unsigned long io_usage; /* number of bytes read/written */
 	char comm[16];
 /* file system info */
 	int link_count;
@@ -206,6 +207,11 @@
 #define PF_STARTING	0x00000100	/* being created */
 #define PF_EXITING	0x00000200	/* getting shut down */
 
+#define PF_FORKNOEXEC	0x00001000	/* forked but didn't exec */
+#define PF_SUPERPREV	0x00002000	/* used super-user privileges */
+#define PF_DUMPCORE	0x00003000	/* dumped core */
+#define PF_SIGNALED	0x00004000	/* killed by a signal */
+
 /*
  * cloning flags:
  */
@@ -236,6 +242,7 @@
 		  {       0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \
 		  {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, {NR_OPEN, NR_OPEN}}, \
 /* math */	0, \
+/* io_usage */  0, \
 /* comm */	"swapper", \
 /* fs info */	0,NULL, \
 /* ipc */	NULL, NULL, \
@@ -280,6 +287,29 @@
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
 asmlinkage int do_signal(unsigned long, struct pt_regs *);
+
+/*
+ * This has now become a routine instead of a macro, it sets a flag if
+ * it returns true (to do BSD-style accounting where the process is flagged
+ * if it uses root privs). The implication of this is that you should do
+ * normal permissions checks first, and check suser() last.
+ *
+ * "suser()" checks against the effective user id, while "fsuser()"
+ * is used for file permission checking and checks against the fsuid..
+ */
+extern inline int suser(void)
+{
+	if (current->euid == 0)
+		current->flags |= PF_SUPERPREV;
+	return (current->euid == 0);
+}
+
+extern inline int fsuser(void)
+{
+	if (current->fsuid == 0)
+		current->flags |= PF_SUPERPREV;
+	return (current->fsuid == 0);
+}
 
 /*
  * The wait-queues are circular lists, and you have to be *very* sure
diff -ru --new-file linux-1.2.12/include/linux/sys.h linux/include/linux/sys.h
--- linux-1.2.12/include/linux/sys.h	Wed Feb 22 11:27:52 1995
+++ linux/include/linux/sys.h	Tue Aug  1 12:03:56 1995
@@ -27,6 +27,5 @@
  * These are system calls that haven't been implemented yet
  * but have an entry in the table for future expansion..
  */
-#define _sys_quotactl	_sys_ni_syscall
 
 #endif
diff -ru --new-file linux-1.2.12/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- linux-1.2.12/include/linux/sysv_fs.h	Tue Jan 10 16:02:10 1995
+++ linux/include/linux/sysv_fs.h	Tue Aug  1 12:03:56 1995
@@ -362,7 +362,7 @@
  */
 
 extern int sysv_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result);
+	               int i_flags, struct inode ** result);
 extern int sysv_create(struct inode * dir,const char * name, int len, int mode,
 	struct inode ** result);
 extern int sysv_mkdir(struct inode * dir, const char * name, int len, int mode);
diff -ru --new-file linux-1.2.12/include/linux/tty.h linux/include/linux/tty.h
--- linux-1.2.12/include/linux/tty.h	Tue May  9 05:40:36 1995
+++ linux/include/linux/tty.h	Tue Aug  1 12:03:56 1995
@@ -298,6 +298,7 @@
 extern int tty_unregister_driver(struct tty_driver *driver);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 			     int buflen);
+extern void tty_write_message(struct tty_struct *tty, char *msg);
 
 extern int is_orphaned_pgrp(int pgrp);
 extern int is_ignored(int sig);
diff -ru --new-file linux-1.2.12/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- linux-1.2.12/include/linux/umsdos_fs.p	Wed Mar 22 09:31:43 1995
+++ linux/include/linux/umsdos_fs.p	Tue Aug  1 12:18:31 1995
@@ -17,6 +17,7 @@
 int UMSDOS_lookup (struct inode *dir,
 	 const char *name,
 	 int len,
+	 int i_flags,
 	 struct inode **result);
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
 /* emd.c 30/01/95 22.05.32 */
@@ -65,6 +66,7 @@
 int umsdos_real_lookup (struct inode *dir,
 	 const char *name,
 	 int len,
+	 int i_flags,
 	 struct inode **result);
 void umsdos_setup_dir_inode (struct inode *inode);
 void umsdos_set_dirinfo (struct inode *inode,
@@ -129,10 +131,12 @@
 int umsdos_rlookup_x (struct inode *dir,
 	 const char *name,
 	 int len,
+	 int i_flags,
 	 struct inode **result,
 	 int nopseudo);
 int UMSDOS_rlookup (struct inode *dir,
 	 const char *name,
 	 int len,
+	 int i_flags,
 	 struct inode **result);
 /* symlink.c 30/01/95 22.05.32 */
diff -ru --new-file linux-1.2.12/include/linux/xia_fs.h linux/include/linux/xia_fs.h
--- linux-1.2.12/include/linux/xia_fs.h	Sun Jan 15 20:50:22 1995
+++ linux/include/linux/xia_fs.h	Tue Aug  1 12:03:56 1995
@@ -65,7 +65,7 @@
 #ifdef __KERNEL__
 
 extern int xiafs_lookup(struct inode * dir,const char * name, int len, 
-			struct inode ** result);
+			int i_flags, struct inode ** result);
 extern int xiafs_create(struct inode * dir,const char * name, int len, int mode,
 		      	struct inode ** result);
 extern int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode);
diff -ru --new-file linux-1.2.12/init/main.c linux/init/main.c
--- linux-1.2.12/init/main.c	Fri Feb 24 15:41:01 1995
+++ linux/init/main.c	Tue Aug  1 12:03:56 1995
@@ -82,6 +82,9 @@
 #ifdef CONFIG_SYSVIPC
 extern void ipc_init(void);
 #endif
+#ifdef CONFIG_QUOTA
+extern void dquot_init(void);
+#endif
 #ifdef CONFIG_SCSI
 extern unsigned long scsi_dev_init(unsigned long, unsigned long);
 #endif
@@ -383,6 +386,9 @@
 	sock_init();
 #ifdef CONFIG_SYSVIPC
 	ipc_init();
+#endif
+#ifdef CONFIG_QUOTA
+	dquot_init();
 #endif
 	sti();
 	check_bugs();
diff -ru --new-file linux-1.2.12/kernel/exit.c linux/kernel/exit.c
--- linux-1.2.12/kernel/exit.c	Wed Jun 28 22:00:46 1995
+++ linux/kernel/exit.c	Tue Aug  1 12:03:56 1995
@@ -18,6 +18,7 @@
 
 #include <asm/segment.h>
 extern void sem_exit (void);
+extern void acct_process (void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
 
@@ -382,6 +383,7 @@
 	}
 fake_volatile:
 	current->flags |= PF_EXITING;
+	acct_process();
 	sem_exit();
 	exit_mmap(current);
 	free_page_tables(current);
diff -ru --new-file linux-1.2.12/kernel/fork.c linux/kernel/fork.c
--- linux-1.2.12/kernel/fork.c	Thu Apr  6 17:24:38 1995
+++ linux/kernel/fork.c	Tue Aug  1 12:03:56 1995
@@ -190,7 +190,9 @@
 	p->kernel_stack_page = new_stack;
 	*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
 	p->state = TASK_UNINTERRUPTIBLE;
-	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
+	p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPREV);
+	p->flags |= PF_FORKNOEXEC;
+	p->io_usage = 0; /* Child doesn't inherit parent's I/O usage */
 	p->pid = last_pid;
 	p->p_pptr = p->p_opptr = current;
 	p->p_cptr = NULL;
diff -ru --new-file linux-1.2.12/kernel/printk.c linux/kernel/printk.c
--- linux-1.2.12/kernel/printk.c	Mon Jan 23 22:04:10 1995
+++ linux/kernel/printk.c	Tue Aug  1 12:03:56 1995
@@ -20,6 +20,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
 
 #define LOG_BUF_LEN	4096
 
@@ -229,4 +231,17 @@
 			msg_level = -1;
 		j = 0;
 	}
+}
+
+/*
+ * Write a message to a certain tty, not just the console. This is used for
+ * messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ */
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+	if (tty && tty->driver.write)
+		tty->driver.write(tty, 0, msg, strlen(msg));
+	return;
 }
diff -ru --new-file linux-1.2.12/kernel/sys.c linux/kernel/sys.c
--- linux-1.2.12/kernel/sys.c	Thu Jul 27 17:31:13 1995
+++ linux/kernel/sys.c	Tue Aug  1 12:03:56 1995
@@ -16,6 +16,9 @@
 #include <linux/ptrace.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/tty.h>
+#include <linux/fcntl.h>
+#include <linux/acct.h>
 #include <linux/mm.h>
 
 #include <asm/segment.h>
@@ -243,9 +246,132 @@
 	return 0;
 }
 
-asmlinkage int sys_acct(void)
+static char acct_active = 0;
+static struct file *acct_file;
+#define	KSTK_ESP(stack)	(((unsigned long *) stack)[1022])
+
+int acct_process(void)
+{
+	struct acct ac;
+	unsigned short fs;
+	unsigned long vsize, esp;
+
+	if (acct_active) {
+		memset(&ac, 0, sizeof(struct acct));
+		strncpy(ac.ac_comm, current->comm, ACCT_COMM);
+		ac.ac_comm[ACCT_COMM] = '\0';
+		ac.ac_utime = current->utime;
+		ac.ac_stime = current->stime;
+		ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
+		ac.ac_etime = CURRENT_TIME - ac.ac_btime;
+		ac.ac_uid   = current->uid;
+		ac.ac_gid   = current->gid;
+		ac.ac_tty   = (current->tty) ? MKDEV(4, current->tty->device) : MKDEV(4, -1);
+		ac.ac_flag  = 0;
+		if (current->flags & PF_FORKNOEXEC)
+			ac.ac_flag |= AFORK;
+		if (current->flags & PF_SUPERPREV)
+			ac.ac_flag |= ASU;
+		if (current->flags & PF_DUMPCORE)
+			ac.ac_flag |= ACORE;
+		if (current->flags & PF_SIGNALED)
+			ac.ac_flag |= AXSIG;
+		ac.ac_io    = current->io_usage;
+
+		/* Figure out the vsize of the current process and divide by the
+		 * page size to calculate AC_MEM.  This is the approved method
+		 * from the proc filesystem.
+		 */
+		vsize = current->kernel_stack_page;
+		if (vsize) {
+			esp = KSTK_ESP(vsize);
+			vsize = current->mm->brk - current->mm->start_code + (PAGE_SIZE - 1);
+			if (esp)
+				vsize += TASK_SIZE - esp;
+		}
+		/* now vsize contains the number of bytes used -- we want to
+		 * find out the number of pages, so divide it by the page size
+		 * and round up.
+		 */
+		ac.ac_mem = (vsize / PAGE_SIZE) + ((vsize % PAGE_SIZE) != 0);
+
+		/* Kernel segment override */
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		acct_file->f_op->write(acct_file->f_inode, acct_file,
+				      (char *)&ac, sizeof(struct acct));
+
+		set_fs(fs);
+	}
+	return 0;
+}
+
+extern void close_fp(struct file *, int);
+
+asmlinkage int sys_acct(const char *name)
 {
-	return -ENOSYS;
+	struct inode *inode = (struct inode *)0;
+	char *tmp;
+	int error;
+
+	if (!suser())
+		return -EPERM;
+
+	if (name == (char *)0) {
+		if (acct_active) {
+			acct_process(); 
+			acct_active = 0;
+			close_fp(acct_file, 0);
+		}
+		return 0;
+	} else {
+		if (!acct_active) {
+			if ((error = getname(name, &tmp)) != 0)
+				return (error);
+			error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+			putname(tmp);
+			if (error)
+				return (error);
+			if (!S_ISREG(inode->i_mode)) {
+				iput(inode);
+				return -EACCES;
+			}
+			if (!inode->i_op || !inode->i_op->default_file_ops || 
+			    !inode->i_op->default_file_ops->write) {
+				iput(inode);
+				return -EIO;
+			}
+			if ((acct_file = get_empty_filp()) != (struct file *)0) {
+				acct_file->f_mode = (O_WRONLY + 1) & O_ACCMODE;
+				acct_file->f_flags = O_WRONLY;
+				acct_file->f_inode = inode;
+				acct_file->f_pos = inode->i_size;
+				acct_file->f_reada = 0;
+				acct_file->f_op = inode->i_op->default_file_ops;
+				if ((error = get_write_access(acct_file->f_inode)) == 0) {
+					if (acct_file->f_op && acct_file->f_op->open)
+						error = acct_file->f_op->open(inode, acct_file);
+					if (error == 0) {
+						acct_active = 1;
+						return 0;
+					}
+					put_write_access(acct_file->f_inode);
+				}
+				acct_file->f_count--;
+			} else
+				error = -EUSERS;
+			iput(inode);
+			return error;
+		} else
+			return -EBUSY;
+	}
+}
+
+void acct_auto_close(dev_t dev)
+{
+	if (acct_active && acct_file && acct_file->f_inode->i_dev == dev)
+		sys_acct((char *)0);
 }
 
 asmlinkage int sys_phys(void)
diff -ru --new-file linux-1.2.12/mm/mmap.c linux/mm/mmap.c
--- linux-1.2.12/mm/mmap.c	Thu Mar  2 08:04:40 1995
+++ linux/mm/mmap.c	Tue Aug  1 12:03:56 1995
@@ -77,7 +77,7 @@
 		default:
 			return -EINVAL;
 		}
-		if ((flags & MAP_DENYWRITE) && (file->f_inode->i_wcount > 0))
+		if ((flags & MAP_DENYWRITE) && (file->f_inode->i_writecount > 0))
 			return -ETXTBSY;
 	} else if ((flags & MAP_TYPE) != MAP_PRIVATE)
 		return -EINVAL;
diff -ru --new-file linux-1.2.12/mm/swap.c linux/mm/swap.c
--- linux-1.2.12/mm/swap.c	Thu Jun  1 12:41:29 1995
+++ linux/mm/swap.c	Tue Aug  1 12:03:56 1995
@@ -987,7 +987,7 @@
 
 	if (!suser())
 		return -EPERM;
-	i = namei(specialfile,&inode);
+	i = namei(specialfile, S_NONE, &inode);
 	if (i)
 		return i;
 	p = swap_info;
@@ -1075,7 +1075,7 @@
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
 	p->max = 1;
-	error = namei(specialfile,&swap_inode);
+	error = namei(specialfile, S_NONE, &swap_inode);
 	if (error)
 		goto bad_swap_2;
 	p->swap_file = swap_inode;
