diff -rc --new-file linuxpl14/config.in linux/config.in
*** linuxpl14/config.in	Sun Nov 28 16:30:44 1993
--- linux/config.in	Wed Dec  8 09:54:43 1993
***************
*** 98,103 ****
--- 98,104 ----
  bool 'NFS filesystem support' CONFIG_NFS_FS y
  bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
  bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
+ bool 'Disk QUOTA support' CONFIG_QUOTA y
  *
  *  character devices
  *
diff -rc --new-file linuxpl14/fs/Makefile linux/fs/Makefile
*** linuxpl14/fs/Makefile	Tue Nov 23 19:43:08 1993
--- linux/fs/Makefile	Wed Dec  8 09:53:40 1993
***************
*** 50,56 ****
  
  OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o locks.o filesystems.o $(BINFMTS)
  
  all: fs.o filesystems.a
  
--- 50,56 ----
  
  OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o locks.o quota.o filesystems.o $(BINFMTS)
  
  all: fs.o filesystems.a
  
diff -rc --new-file linuxpl14/fs/buffer.c linux/fs/buffer.c
*** linuxpl14/fs/buffer.c	Tue Nov 23 19:43:09 1993
--- linux/fs/buffer.c	Wed Dec  8 09:53:41 1993
***************
*** 26,31 ****
--- 26,34 ----
  #include <linux/string.h>
  #include <linux/locks.h>
  #include <linux/errno.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/system.h>
  #include <asm/io.h>
***************
*** 153,158 ****
--- 156,164 ----
  	sync_supers(dev);
  	sync_inodes(dev);
  	sync_buffers(dev, 0);
+ #ifdef CONFIG_QUOTA
+ 	sync_quota(dev, -1);
+ #endif
  }
  
  int fsync_dev(dev_t dev)
diff -rc --new-file linuxpl14/fs/exec.c linux/fs/exec.c
*** linuxpl14/fs/exec.c	Sat Oct 30 23:20:41 1993
--- linux/fs/exec.c	Wed Dec  8 09:53:41 1993
***************
*** 40,45 ****
--- 40,47 ----
  #include <linux/malloc.h>
  
  #include <asm/system.h>
+ #include <linux/config.h>
+ #include <linux/fileio.h>
  
  #include <linux/binfmts.h>
  
***************
*** 96,102 ****
   * macros to write out all the necessary info.
   */
  #define DUMP_WRITE(addr,nr) \
! while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
  
  #define DUMP_SEEK(offset) \
  if (file.f_op->lseek) { \
--- 98,104 ----
   * macros to write out all the necessary info.
   */
  #define DUMP_WRITE(addr,nr) \
! while (vfs_write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
  
  #define DUMP_SEEK(offset) \
  if (file.f_op->lseek) { \
diff -rc linuxpl14/fs/ext2/super.c linux/fs/ext2/super.c
*** linuxpl14/fs/ext2/super.c	Tue Nov 23 19:43:09 1993
--- linux/fs/ext2/super.c	Wed Dec  8 18:59:44 1993
***************
*** 190,199 ****
  			if (*value)
  				return 0;
  		}
! 		else {
! 			printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
! 			return 0;
! 		}
  	}
  	return 1;
  }
--- 190,197 ----
  			if (*value)
  				return 0;
  		}
! 		else
! 			return 1;
  	}
  	return 1;
  }
diff -rc linuxpl14/fs/isofs/inode.c linux/fs/isofs/inode.c
*** linuxpl14/fs/isofs/inode.c	Mon Nov 29 22:40:35 1993
--- linux/fs/isofs/inode.c	Wed Dec  8 18:58:03 1993
***************
*** 112,118 ****
  		  if (ivalue != 1024 && ivalue != 2048) return 0;
  		  *blocksize = ivalue;
  		}
! 		else return 0;
  	}
  	return 1;
  }
--- 112,118 ----
  		  if (ivalue != 1024 && ivalue != 2048) return 0;
  		  *blocksize = ivalue;
  		}
! 		else return 1;
  	}
  	return 1;
  }
diff -rc linuxpl14/fs/msdos/inode.c linux/fs/msdos/inode.c
*** linuxpl14/fs/msdos/inode.c	Tue Nov 23 19:43:10 1993
--- linux/fs/msdos/inode.c	Wed Dec  8 18:58:25 1993
***************
*** 133,139 ****
  			if (value) return 0;
  			*quiet = 1;
  		}
! 		else return 0;
  	}
  	return 1;
  }
--- 133,139 ----
  			if (value) return 0;
  			*quiet = 1;
  		}
! 		else return 1;
  	}
  	return 1;
  }
diff -rc --new-file linuxpl14/fs/namei.c linux/fs/namei.c
*** linuxpl14/fs/namei.c	Tue Oct 26 11:59:23 1993
--- linux/fs/namei.c	Wed Dec  8 09:53:41 1993
***************
*** 16,21 ****
--- 16,23 ----
  #include <linux/string.h>
  #include <linux/fcntl.h>
  #include <linux/stat.h>
+ #include <linux/config.h>
+ #include <linux/fileio.h>
  
  #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
  
***************
*** 319,325 ****
  			return -EROFS;
  		}
  		dir->i_count++;		/* create eats the dir */
! 		error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
  		if (error != -EEXIST) {
  			iput(dir);
  			return error;
--- 321,327 ----
  			return -EROFS;
  		}
  		dir->i_count++;		/* create eats the dir */
! 		error = vfs_create(dir, basename, namelen, mode, res_inode);
  		if (error != -EEXIST) {
  			iput(dir);
  			return error;
***************
*** 375,390 ****
  			}
   		}
   	}
! 	if (flag & O_TRUNC) {
! 	      inode->i_size = 0;
! 	      if (inode->i_op && inode->i_op->truncate)
! 	           inode->i_op->truncate(inode);
! 	      if ((error = notify_change(NOTIFY_SIZE, inode))) {
! 		   iput(inode);
! 		   return error;
! 	      }
! 	      inode->i_dirt = 1;
! 	}
  	*res_inode = inode;
  	return 0;
  }
--- 377,384 ----
  			}
   		}
   	}
! 	if (flag & O_TRUNC)
! 		vfs_truncate(inode, 0);
  	*res_inode = inode;
  	return 0;
  }
***************
*** 415,421 ****
  		iput(dir);
  		return -EPERM;
  	}
! 	return dir->i_op->mknod(dir,basename,namelen,mode,dev);
  }
  
  asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
--- 409,415 ----
  		iput(dir);
  		return -EPERM;
  	}
! 	return vfs_mknod(dir, basename, namelen, mode, dev);
  }
  
  asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
***************
*** 467,473 ****
  		iput(dir);
  		return -EPERM;
  	}
! 	return dir->i_op->mkdir(dir,basename,namelen,mode);
  }
  
  asmlinkage int sys_mkdir(const char * pathname, int mode)
--- 461,467 ----
  		iput(dir);
  		return -EPERM;
  	}
! 	return vfs_mkdir(dir, basename, namelen, mode);
  }
  
  asmlinkage int sys_mkdir(const char * pathname, int mode)
***************
*** 508,514 ****
  		iput(dir);
  		return -EPERM;
  	}
! 	return dir->i_op->rmdir(dir,basename,namelen);
  }
  
  asmlinkage int sys_rmdir(const char * pathname)
--- 502,508 ----
  		iput(dir);
  		return -EPERM;
  	}
! 	return vfs_rmdir(dir, basename, namelen);
  }
  
  asmlinkage int sys_rmdir(const char * pathname)
***************
*** 549,555 ****
  		iput(dir);
  		return -EPERM;
  	}
! 	return dir->i_op->unlink(dir,basename,namelen);
  }
  
  asmlinkage int sys_unlink(const char * pathname)
--- 543,549 ----
  		iput(dir);
  		return -EPERM;
  	}
! 	return vfs_unlink(dir, basename, namelen);
  }
  
  asmlinkage int sys_unlink(const char * pathname)
***************
*** 590,596 ****
  		iput(dir);
  		return -EPERM;
  	}
! 	return dir->i_op->symlink(dir,basename,namelen,oldname);
  }
  
  asmlinkage int sys_symlink(const char * oldname, const char * newname)
--- 584,590 ----
  		iput(dir);
  		return -EPERM;
  	}
! 	return vfs_symlink(dir, basename, namelen, oldname);
  }
  
  asmlinkage int sys_symlink(const char * oldname, const char * newname)
diff -rc --new-file linuxpl14/fs/open.c linux/fs/open.c
*** linuxpl14/fs/open.c	Tue Oct 26 12:03:54 1993
--- linux/fs/open.c	Wed Dec  8 09:53:41 1993
***************
*** 16,21 ****
--- 16,23 ----
  #include <linux/signal.h>
  #include <linux/tty.h>
  #include <linux/time.h>
+ #include <linux/config.h>
+ #include <linux/fileio.h>
  
  #include <asm/segment.h>
  
***************
*** 81,92 ****
  		iput(inode);
  		return -EROFS;
  	}
! 	inode->i_size = length;
! 	if (inode->i_op && inode->i_op->truncate)
! 		inode->i_op->truncate(inode);
! 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
! 	inode->i_dirt = 1;
! 	error = notify_change(NOTIFY_SIZE, inode);
  	iput(inode);
  	return error;
  }
--- 83,89 ----
  		iput(inode);
  		return -EROFS;
  	}
! 	error = vfs_truncate(inode, length);
  	iput(inode);
  	return error;
  }
***************
*** 102,113 ****
  		return -ENOENT;
  	if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
  		return -EACCES;
! 	inode->i_size = length;
! 	if (inode->i_op && inode->i_op->truncate)
! 		inode->i_op->truncate(inode);
! 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
! 	inode->i_dirt = 1;
! 	return notify_change(NOTIFY_SIZE, inode);
  }
  
  /* If times==NULL, set access and modification to current time,
--- 99,105 ----
  		return -ENOENT;
  	if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
  		return -EACCES;
! 	return vfs_truncate(inode, length);
  }
  
  /* If times==NULL, set access and modification to current time,
***************
*** 294,306 ****
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) ||
! 	    suser()) {
! 		inode->i_uid = user;
! 		inode->i_gid = group;
! 		inode->i_ctime = CURRENT_TIME;
! 		inode->i_dirt = 1;
! 		return notify_change(NOTIFY_UIDGID, inode);
  	}
  	return -EPERM;
  }
--- 286,293 ----
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) || suser()) {
! 		return vfs_chown(inode, user, group);
  	}
  	return -EPERM;
  }
***************
*** 322,334 ****
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) ||
! 	    suser()) {
! 		inode->i_uid = user;
! 		inode->i_gid = group;
! 		inode->i_ctime = CURRENT_TIME;
! 		inode->i_dirt = 1;
! 		error = notify_change(NOTIFY_UIDGID, inode);
  		iput(inode);
  		return error;
  	}
--- 309,316 ----
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) || suser()) {
! 		error = vfs_chown(inode, user, group);
  		iput(inode);
  		return error;
  	}
diff -rc --new-file linuxpl14/fs/quota.c linux/fs/quota.c
*** linuxpl14/fs/quota.c
--- linux/fs/quota.c	Wed Dec  8 09:59:47 1993
***************
*** 0 ****
--- 1,1158 ----
+ /*
+  * QUOTA    An 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: quota.c,v 3.3 1993/12/05 11:08:30 mvw Exp mvw $
+  * 
+  * Authors: Marco van Wieringen <v892273@si.hhs.nl> <mvw@mercury.mcs.nl.mugnet.org>
+  *          Edvard Tuinder <v892231@si.hhs.nl> <ed@delirium.nl.mugnet.org>
+  *          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+  * 
+  *          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/config.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ 
+ #ifdef CONFIG_QUOTA
+ #include <linux/types.h>
+ #include <linux/sched.h>
+ #include <linux/quota.h>
+ #include <linux/string.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/segment.h>
+ #include <linux/fs.h>
+ #include <linux/tty.h>
+ #include <linux/malloc.h>
+ 
+ #include <asm/segment.h>
+ #include <sys/sysmacros.h>
+ 
+ /* Linked list with enabled devices */
+ static struct device_list *devicelist[MAXQUOTAS];
+ 
+ /* Most recent used device */
+ static struct device_list *mru_device[MAXQUOTAS];
+ 
+ /* Most recent used id on the device in mru_device */
+ static struct dquot *mru_dquot[MAXQUOTAS];
+ 
+ static inline char *typetoname(int type)
+ {
+    if (type == USRQUOTA)
+       return "uid";
+    else
+       return "gid";
+ }
+ 
+ /*
+  * Kick the message in quotamessage to the tty.
+  */
+ static void quota_message(char *quotamessage)
+ {
+    struct tty_struct *tty;
+ 
+    if (current->tty >= 0) {
+       tty = TTY_TABLE(current->tty);
+       (void) tty_write_data(tty, quotamessage, strlen(quotamessage),
+                             (void *)0, (void *)0);
+    }
+ }
+ 
+ /*
+  * Functions for management of devices.
+  */
+ static struct device_list *lookup_device(dev_t dev, int type)
+ {
+    register struct device_list *lptr;
+ 
+    if (devicelist[type] == (struct device_list *) 0)
+       return ((struct device_list *) 0);
+ 
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_device[type]->dq_dev == dev)
+       return (mru_device[type]);
+ 
+    for (lptr = devicelist[type]; lptr != (struct device_list *)0; lptr = lptr->next)
+       if (lptr->dq_dev == dev)
+          return (lptr);
+ 
+    return ((struct device_list *) 0);
+ }
+ 
+ static struct device_list *add_device(dev_t dev, char *devicename, int type)
+ {
+    register struct device_list *lptr;
+    int error;
+    char *tmp;
+ 
+    if ((lptr = (struct device_list *)
+         kmalloc(sizeof(struct device_list), GFP_KERNEL)) == (struct device_list *) 0)
+       return ((struct device_list *) 0);
+    memset(lptr, 0, sizeof(struct device_list));
+ 
+    lptr->dq_dev = dev;
+    lptr->dq_dirt = 0;
+    lptr->dq_quota = (struct dquot *) 0;
+ 
+    if ((error = getname(devicename, &tmp)) != 0)
+       return ((struct device_list *) 0);
+    if ((lptr->dq_devicename = (char *)
+         kmalloc(strlen(tmp), GFP_KERNEL)) == (char *)0)
+       return ((struct device_list *) 0);
+    strcpy(lptr->dq_devicename, tmp);
+    putname(tmp);
+ 
+    lptr->next = devicelist[type];
+    devicelist[type] = lptr;
+ 
+    return (lptr);
+ }
+ 
+ static inline int device_can_be_removed(struct device_list *device)
+ {
+    register struct dquot *lptr;
+ 
+    for(lptr = device->dq_quota; lptr != (struct dquot *)0; lptr = lptr->next)
+       if (lptr->dq_flags & DQ_LOCKED)
+          return 0;
+    return 1;
+ }
+ 
+ static void remove_device(dev_t dev, int type)
+ {
+    register struct device_list *lptr, *tmp;
+    register struct dquot *idp, *tofree;
+ 
+    if (devicelist[type] == (struct device_list *) 0)
+       return;
+ 
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_device[type]->dq_dev == dev) {
+       mru_device[type] = (struct device_list *) 0;
+       mru_dquot[type] = (struct dquot *) 0;
+    }
+ 
+    lptr = devicelist[type];
+    if (lptr->dq_dev == dev)
+       devicelist[type] = lptr->next;
+    else {
+       while (lptr->next != (struct device_list *) 0) {
+          if (lptr->next->dq_dev == dev)
+             break;
+          lptr = lptr->next;
+       }
+       tmp = lptr->next;
+       lptr->next = lptr->next->next;
+       lptr = tmp;
+    }
+ 
+    idp = lptr->dq_quota;
+    while (idp != (struct dquot *) 0) {
+       tofree = idp;
+       idp = idp->next;
+       kfree_s(tofree, sizeof(struct dquot));
+    }
+ 
+    kfree_s(lptr->dq_devicename, strlen(lptr->dq_devicename));
+    kfree_s(lptr, sizeof(struct device_list));
+ }
+ 
+ /*
+  * Functions for management of dquot structs
+  * 
+  * Locking of dqblk for a user or group.
+  */
+ static void wait_on_dqblk(struct dquot * dquot)
+ {
+    struct wait_queue wait = {current, NULL};
+ 
+    add_wait_queue(&dquot->dq_wait, &wait);
+    while (dquot->dq_flags & DQ_LOCKED) {
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule();
+    }
+    remove_wait_queue(&dquot->dq_wait, &wait);
+    current->state = TASK_RUNNING;
+ }
+ 
+ static inline void lock_dquot(struct dquot * dquot)
+ {
+    if (dquot != (struct dquot *)0) {
+       while (dquot->dq_flags & DQ_LOCKED) {
+          dquot->dq_flags |= DQ_WANT;
+          wait_on_dqblk(dquot);
+       }
+       dquot->dq_flags |= DQ_LOCKED;
+    }
+ }
+ 
+ static inline void unlock_dquot(struct dquot * dquot)
+ {
+    if (dquot != (struct dquot *)0) {
+       dquot->dq_flags &= ~DQ_LOCKED;
+       if (dquot->dq_flags & DQ_WANT) {
+          dquot->dq_flags &= ~DQ_WANT;
+          wake_up(&dquot->dq_wait);
+       }
+    }
+ }
+ 
+ /*
+  * Functions for management of dquot's
+  */
+ static struct dquot *lookup_dquot(struct device_list *device, int id, int type)
+ {
+    register struct dquot *lptr = (struct dquot *) 0;
+ 
+    if (id <= ID_NO_QUOTA)
+       return ((struct dquot *) 0);
+ 
+    /*
+     * First fast lookup when same as used before.
+     */
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_dquot[type] != (struct dquot *) 0 &&
+        mru_dquot[type]->dq_id == id &&
+        mru_device[type]->dq_dev == device->dq_dev) {
+       lock_dquot(mru_dquot[type]);
+       return (mru_dquot[type]);
+    }
+ 
+    for (lptr = device->dq_quota; lptr != (struct dquot *) 0; lptr = lptr->next)
+       if (lptr->dq_id == id) {
+          mru_device[type] = device;
+          mru_dquot[type] = lptr;
+          lock_dquot(lptr);
+          return (lptr);
+       }
+    return ((struct dquot *) 0);
+ }
+ 
+ static struct dquot *add_dquot(struct device_list * device, int id)
+ {
+    register struct dquot *lptr;
+ 
+    if ((lptr = (struct dquot *)
+         kmalloc(sizeof(struct dquot), GFP_KERNEL)) == (struct dquot *) 0)
+       return ((struct dquot *) 0);
+    memset(lptr, 0, sizeof(struct dquot));
+ 
+    lptr->dq_id = id;
+    lptr->dq_btime = lptr->dq_itime = (time_t) 0;
+    lptr->dq_flags |= DQ_LOCKED; /* lock it right away */
+ 
+    /*
+     * Stuff it in at front of the dquot list.
+     */
+    lptr->next = device->dq_quota;
+    device->dq_quota = lptr;
+ 
+    return (lptr);
+ }
+ 
+ static void remove_dquot(struct device_list * device, int id, int type)
+ {
+    register struct dquot *lptr, *tmp;
+ 
+    /*
+     * Remove fast lookup references.
+     */
+    if (mru_dquot[type] != (struct dquot *) 0 && mru_dquot[type]->dq_id == id)
+       mru_dquot[type] = (struct dquot *) 0;
+ 
+    lptr = device->dq_quota;
+    if (lptr->dq_id == id)
+       device->dq_quota = lptr->next;
+    else {
+       while (lptr->next != (struct dquot *) 0) {
+          if (lptr->next->dq_id == id)
+             break;
+          lptr = lptr->next;
+       }
+ 
+       tmp = lptr->next;
+       lptr->next = lptr->next->next;
+       lptr = tmp;
+    }
+ 
+    kfree_s(lptr, sizeof(struct dquot));
+ }
+ 
+ /*
+  * Check quota for inodes. Returns QUOTA_OK if can allocate and
+  * NO_QUOTA if it can't.
+  */
+ static int check_idq(struct device_list * device, struct dquot * dquot,
+                      int id, int type, u_long wanted_inodes)
+ {
+    static char message[MAX_QUOTA_MESSAGE];
+ 
+    if (wanted_inodes == 0 ||
+       (dquot->dq_isoftlimit == 0 && dquot->dq_ihardlimit == 0))
+       return QUOTA_OK;
+ 
+    if (dquot->dq_ihardlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_ihardlimit) {
+       if ((dquot->dq_flags & DQ_INODES) == 0) {
+          sprintf(message,
+                 "File LIMIT reached on %s for %s %d. !! NO MORE !!\n\r",
+                 device->dq_devicename, typetoname(type), id);
+          quota_message(message);
+          dquot->dq_flags &= DQ_INODES;
+       }
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_isoftlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_isoftlimit &&
+        dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime) {
+       sprintf(message,
+               "File QUOTA exceeded TOO long on %s for %s %d. !! NO MORE !!\n\r",
+               device->dq_devicename, typetoname(type), id);
+       quota_message(message);
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_isoftlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_isoftlimit &&
+        dquot->dq_itime == 0) {
+       sprintf(message,
+               "File QUOTA exceeded on %s for %s %d\n\r",
+               device->dq_devicename, typetoname(type), id);
+       quota_message(message);
+       dquot->dq_itime = CURRENT_TIME + device->dq_iexp;
+    }
+ 
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Check quota for blocks. Returns QUOTA_OK if can allocate and
+  * NO_QUOTA if it can't. When we can't allocate wanted_blocks you get
+  * the number we can allocate in avail_blocks.
+  */
+ static int check_bdq(struct device_list * device, struct dquot * dquot, int id,
+                      int type, u_long wanted_blocks, u_long *avail_blocks)
+ {
+    static char message[MAX_QUOTA_MESSAGE];
+ 
+    if (wanted_blocks == 0 ||
+       (dquot->dq_bsoftlimit == 0 && dquot->dq_bhardlimit == 0))
+       return QUOTA_OK;
+ 
+    if (dquot->dq_bhardlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bhardlimit) {
+       if ((dquot->dq_flags & DQ_BLKS) == 0) {
+          sprintf(message,
+                  "Block LIMIT reached on %s for %s %d. !! NO MORE !!\n\r",
+                  device->dq_devicename, typetoname(type), id);
+          quota_message(message);
+          dquot->dq_flags &= DQ_BLKS;
+       }
+       if (dquot->dq_curblocks != dquot->dq_bhardlimit) {
+          *avail_blocks = dquot->dq_bhardlimit - dquot->dq_curblocks;
+          return QUOTA_OK;
+       } else
+          return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_bsoftlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bsoftlimit &&
+        dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime) {
+       sprintf(message,
+               "Block QUOTA exceeded TOO long on %s for %s %d. !! NO MORE !!\n\r",
+               device->dq_devicename, typetoname(type), id);
+          quota_message(message);
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_bsoftlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bsoftlimit &&
+        dquot->dq_btime == 0) {
+       sprintf(message,
+               "Block QUOTA exceeded on %s for %s %d\n\r",
+               device->dq_devicename, typetoname(type), id);
+       quota_message(message);
+       dquot->dq_btime = CURRENT_TIME + device->dq_bexp;
+    }
+ 
+    *avail_blocks = wanted_blocks;
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Remove inodes from a quota. Resets grace times if we go below
+  * inode softlimit.
+  */
+ static void remove_idq(struct dquot * dquot, u_long inodes)
+ {
+    if (dquot->dq_curinodes >= inodes)
+       dquot->dq_curinodes -= inodes;
+    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;
+ }
+ 
+ /*
+  * Remove blocks from a quota. Resets grace times if we go below
+  * block softlimit.
+  */
+ static void remove_bdq(struct dquot * dquot, u_long blocks)
+ {
+    if (dquot->dq_curblocks >= blocks)
+       dquot->dq_curblocks -= blocks;
+    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;
+ }
+ 
+ /*
+  * Realy sync the quota info to the quota file.
+  */
+ static int sync_device(struct device_list * device, int type)
+ {
+    register struct dquot *dquot = (struct dquot *) 0;
+    struct dqblk exp_times;
+    unsigned short fs;
+ 
+    if (device->dq_dirt == 0)
+       return 0;
+ 
+    if (!device->dq_file.f_op->write)
+       return -EIO;
+ 
+    fs = get_fs();
+ 
+    /* First write expire times */
+    memset(&exp_times, 0, sizeof(struct dqblk));
+    exp_times.dqb_itime = device->dq_iexp;
+    exp_times.dqb_btime = device->dq_bexp;
+ 
+    /*
+     * Seek to absolute begin point of quota file.
+     */
+    if (device->dq_file.f_op->lseek) {
+       if (device->dq_file.f_op->lseek(device->dq_file.f_inode,
+                                       &device->dq_file, 0, 0) != 0)
+          goto end_sync;
+    } else
+       device->dq_file.f_pos = 0;
+ 
+    set_fs(KERNEL_DS);
+    if (device->dq_file.f_op->write(device->dq_file.f_inode, &device->dq_file,
+        (char *)&exp_times, sizeof(struct dqblk)) != sizeof(struct dqblk))
+       goto end_sync;
+ 
+    /*
+     * Write out all quota-structs that are marked with DQ_MOD, those
+     * are modified since the last time the were written to disk.
+     */
+    dquot = device->dq_quota;
+    while (dquot != (struct dquot *)0) {
+       if (dquot->dq_flags & DQ_MOD) {
+          if (device->dq_file.f_op->lseek) {
+             if (device->dq_file.f_op->lseek(device->dq_file.f_inode,
+                                             &device->dq_file,
+                                             dqoff(dquot->dq_id), 0) !=
+                                             dqoff(dquot->dq_id))
+                goto end_sync;
+          } else
+             device->dq_file.f_pos = dqoff(dquot->dq_id);
+ 
+          if (device->dq_file.f_op->write(device->dq_file.f_inode,
+                                          &device->dq_file,
+                                          (char *) &dquot->dq_dqb,
+                                          sizeof(struct dqblk)) !=
+                                          sizeof(struct dqblk))
+             goto end_sync;
+          dquot->dq_flags &= ~DQ_MOD;
+       }
+       dquot = dquot->next;
+    }
+ 
+    set_fs(fs);
+    device->dq_dirt = 0;
+    return 0;
+ 
+ end_sync:
+    set_fs(fs);
+    return -EIO;
+ }
+ 
+ /*
+  * Initialize a dquot-struct with new quota info. This is used by the
+  * systemcall interface functions.
+  */ 
+ static int set_dqblk(struct device_list * device, int id, int type, int flags,
+                      struct dqblk *dqblk)
+ {
+    register struct dquot *dquot = (struct dquot *) 0;
+    struct dqblk dq_dqblk;
+    int error;
+ 
+    /* No quota enabled for users and groups below ID_NO_QUOTA */
+    if (id > 0 && id <= ID_NO_QUOTA)
+       return 0;
+ 
+    if (dqblk == (struct dqblk *)0)
+       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));
+    }
+ 
+    /* set expiration times */
+    if (id == 0) {
+       device->dq_iexp = (dq_dqblk.dqb_itime) ? dq_dqblk.dqb_itime : MAX_IQ_TIME;
+       device->dq_bexp = (dq_dqblk.dqb_btime) ? dq_dqblk.dqb_btime : MAX_DQ_TIME;
+       device->dq_dirt = 1;
+       return 0;
+    }
+ 
+    dquot = lookup_dquot(device, id, type);
+    if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
+        dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) {
+       if (dquot == (struct dquot *) 0)
+          return 0; /* No quota set */
+ 
+       dquot->dq_flags |= DQ_REMOVE; /* sync and remove at the end */
+    }
+ 
+    if (dquot == (struct dquot *) 0)
+       if ((dquot = add_dquot(device, id)) == (struct dquot *) 0)
+          return -EUSERS;
+ 
+    if ((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 & QUOTA_SYSCALL) == 0) {
+          dquot->dq_btime = dq_dqblk.dqb_btime;
+          dquot->dq_itime = dq_dqblk.dqb_itime;
+       }
+    }
+ 
+    if ((flags & SET_QUOTA) || (flags & SET_USE)) {
+       dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
+       dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
+       if (dquot->dq_btime && dquot->dq_curblocks < dquot->dq_bsoftlimit)
+          dquot->dq_btime = (time_t) 0;
+       if (dquot->dq_itime && dquot->dq_curinodes < dquot->dq_isoftlimit)
+          dquot->dq_itime = (time_t) 0;
+    }
+ 
+    device->dq_dirt = 1;
+    dquot->dq_flags |= DQ_MOD;
+ 
+    if (dquot->dq_flags & DQ_REMOVE) {
+       sync_device(device, type);
+       remove_dquot(device, id, type);
+    } else
+       unlock_dquot(dquot);
+ 
+    return 0;
+ }
+ 
+ /*
+  * ====================== Entry points of module ======================
+  * All functions under this line are callable from within the kernel.
+  */
+ 
+ /*
+  * This are two simple algorithms that calculates the size of a file in blocks
+  * and from a number of blocks to a isize.
+  * It is not perfect but works most of the time.
+  */
+ 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;
+ }
+ 
+ /*
+  * And this works the other way around to calculate the inodesize
+  * of a file if it may consume a certain number of blocks.
+  */ 
+ size_t blocks_to_isize(u_long blocks, size_t blksize)
+ {
+    size_t isize;
+    u_long indirect;
+ 
+    if (!blksize)
+       blksize = BLOCK_SIZE;
+ 
+    isize = blocks * blksize;
+    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 */
+       }
+       isize -= indirect * blksize;
+    }
+    return isize;
+ }
+ 
+ /*
+  * Allocate the number of inodes and blocks from a diskquota.
+  */
+ int quota_alloc(dev_t dev, uid_t uid, gid_t gid, u_long wanted_inodes,
+                 u_long wanted_blocks, u_long *avail_blocks)
+ {
+    u_long availblocks = 0, usr_avail = 0, grp_avail = 0;
+    struct device_list *usr_device = (struct device_list *) 0,
+                       *grp_device = (struct device_list *) 0;
+    struct dquot *usr_dquot = (struct dquot *) 0,
+                 *grp_dquot = (struct dquot *) 0;
+ 
+    availblocks = wanted_blocks;
+    if (wanted_inodes > 0 || wanted_blocks > 0) {
+       if ((usr_device = lookup_device(dev, USRQUOTA)) !=
+           (struct device_list *)0) {
+          if ((usr_dquot = lookup_dquot(usr_device, uid, USRQUOTA)) !=
+              (struct dquot *) 0) {
+             if (check_idq(usr_device, usr_dquot, uid, USRQUOTA,
+                           wanted_inodes) == NO_QUOTA ||
+                 check_bdq(usr_device, usr_dquot, uid, USRQUOTA,
+                           wanted_blocks, &usr_avail) == NO_QUOTA) {
+                unlock_dquot(usr_dquot);
+                return NO_QUOTA;
+             }
+             availblocks = usr_avail;
+          }
+       }
+ 
+       if ((grp_device = lookup_device(dev, GRPQUOTA)) !=
+           (struct device_list *)0) {
+          if ((grp_dquot = lookup_dquot(grp_device, gid, GRPQUOTA)) !=
+              (struct dquot *) 0) {
+             if (check_idq(grp_device, grp_dquot, gid, GRPQUOTA,
+                           wanted_inodes) == NO_QUOTA ||
+                 check_bdq(grp_device, grp_dquot, gid, GRPQUOTA,
+                           wanted_blocks, &grp_avail) == NO_QUOTA) {
+                unlock_dquot(usr_dquot);
+                unlock_dquot(grp_dquot);
+                return NO_QUOTA;
+             }
+             availblocks = (usr_avail == 0) ? grp_avail : \
+                           min(usr_avail, grp_avail);
+          }
+       }
+ 
+       /* Have exclusive lock on both quotas if needed and can allocate */
+       if (usr_dquot != (struct dquot *) 0) {
+          usr_dquot->dq_curinodes += wanted_inodes;
+          usr_dquot->dq_curblocks += availblocks;
+          usr_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(usr_dquot);
+          usr_device->dq_dirt = 1;
+       }
+ 
+       if (grp_dquot != (struct dquot *) 0) {
+          grp_dquot->dq_curinodes += wanted_inodes;
+          grp_dquot->dq_curblocks += availblocks;
+          grp_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(grp_dquot);
+          grp_device->dq_dirt = 1;
+       }
+    }
+ 
+    if (avail_blocks != (u_long *)0)
+       *avail_blocks = availblocks;
+ 
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Transfer the number of inode and blocks from one diskquota to an other.
+  */
+ int quota_transfer(dev_t dev, uid_t olduid, uid_t newuid, gid_t oldgid,
+                    gid_t newgid, u_long inodes, u_long blocks)
+ {
+    u_long availblocks = 0;
+    struct device_list *usr_device = (struct device_list *) 0,
+                       *grp_device = (struct device_list *) 0;
+    struct dquot *old_usr_dquot = (struct dquot *) 0,
+                 *new_usr_dquot = (struct dquot *) 0,
+                 *old_grp_dquot = (struct dquot *) 0,
+                 *new_grp_dquot = (struct dquot *) 0;
+ 
+    if (olduid != newuid &&
+       (usr_device = lookup_device(dev, USRQUOTA)) != (struct device_list *)0) {
+       if ((new_usr_dquot = lookup_dquot(usr_device, newuid, USRQUOTA)) !=
+           (struct dquot *) 0) {
+          if (check_idq(usr_device, new_usr_dquot, newuid, USRQUOTA,
+                        inodes) == NO_QUOTA ||
+              check_bdq(usr_device, new_usr_dquot, newuid, USRQUOTA,
+                        blocks, &availblocks) == NO_QUOTA ||
+              availblocks != blocks) {
+             unlock_dquot(new_usr_dquot);
+             return NO_QUOTA;
+          }
+       }
+    }
+ 
+    if (oldgid != newgid &&
+       (grp_device = lookup_device(dev, GRPQUOTA)) != (struct device_list *)0) {
+       if ((new_grp_dquot = lookup_dquot(grp_device, newgid, GRPQUOTA)) !=
+           (struct dquot *) 0) {
+          if (check_idq(grp_device, new_grp_dquot, newgid,
+                        GRPQUOTA, inodes) == NO_QUOTA ||
+              check_bdq(grp_device, new_grp_dquot, newgid, GRPQUOTA,
+                        blocks, &availblocks) == NO_QUOTA ||
+              availblocks != blocks) {
+             unlock_dquot(new_usr_dquot);
+             unlock_dquot(new_grp_dquot);
+             return NO_QUOTA;
+          }
+       }
+    }
+ 
+    /* Have exclusive lock on both quotas if needed and can allocate */
+    if (olduid != newuid && usr_device != (struct device_list *)0) {
+       if ((old_usr_dquot = lookup_dquot(usr_device, olduid, USRQUOTA)) !=
+           (struct dquot *) 0) {
+          /* Remove it from old */
+          if (inodes)
+             remove_idq(old_usr_dquot, inodes);
+          if (blocks)
+             remove_bdq(old_usr_dquot, blocks);
+          unlock_dquot(old_usr_dquot);
+       }
+ 
+       /* Move it to new diskquota */
+       if (new_usr_dquot != (struct dquot *)0) {
+          new_usr_dquot->dq_curinodes += inodes;
+          new_usr_dquot->dq_curblocks += blocks;
+          new_usr_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(new_usr_dquot);
+       }
+       usr_device->dq_dirt = 1;
+    }
+    
+ 
+    if (oldgid != newgid && grp_device != (struct device_list *)0) {
+       if ((old_grp_dquot = lookup_dquot(grp_device, oldgid, GRPQUOTA)) !=
+           (struct dquot *) 0) {
+          /* Remove it from old */
+          if (inodes)
+             remove_idq(old_grp_dquot, inodes);
+          if (blocks)
+             remove_bdq(old_grp_dquot, blocks);
+          unlock_dquot(old_grp_dquot);
+       }
+ 
+       /* Move it to new diskquota */
+       if (new_grp_dquot != (struct dquot *) 0) {
+          new_grp_dquot->dq_curinodes += inodes;
+          new_grp_dquot->dq_curblocks += blocks;
+          new_grp_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(new_grp_dquot);
+       }
+       grp_device->dq_dirt = 1;
+    }
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Remove the number of inodes and blocks from a diskquota.
+  */
+ void quota_remove(dev_t dev, uid_t uid, gid_t gid, u_long inodes, u_long blocks
+ )
+ {
+    struct device_list *usr_device, *grp_device;
+    struct dquot *usr_dquot, *grp_dquot;
+ 
+    if (inodes > 0 || blocks > 0) {
+       if ((usr_device = lookup_device(dev, USRQUOTA)) !=
+           (struct device_list *)0) {
+          if ((usr_dquot = lookup_dquot(usr_device, uid, USRQUOTA)) !=
+              (struct dquot *) 0) {
+             if (inodes)
+                remove_idq(usr_dquot, inodes);
+             if (blocks)
+                remove_bdq(usr_dquot, blocks);
+             unlock_dquot(usr_dquot);
+             usr_device->dq_dirt = 1;
+          }
+       }
+ 
+       if ((grp_device = lookup_device(dev, GRPQUOTA)) !=
+           (struct device_list *)0) {
+          if ((grp_dquot = lookup_dquot(grp_device, gid, GRPQUOTA)) !=
+              (struct dquot *) 0) {
+             if (inodes)
+                remove_idq(grp_dquot, inodes);
+             if (blocks)
+                remove_bdq(grp_dquot, blocks);
+             unlock_dquot(grp_dquot);
+             grp_device->dq_dirt = 1;
+          }
+       }
+    }
+ }
+ 
+ /*
+  * Following functions used by systemcall interface don't use it your self !!
+  */
+ int set_quota(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_QUOTA | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int set_use(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_USE | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int set_qlimit(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_QLIMIT | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int get_quota(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+    register struct dquot *dquot;
+    struct dqblk exp_times;
+    int error;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0) {
+       if (dqblk == (struct dqblk *) 0)
+          return -EFAULT;
+ 
+       if ((error = verify_area(VERIFY_WRITE, dqblk, sizeof(struct dqblk))) != 0)
+          return (error);
+ 
+       if (id > ID_NO_QUOTA &&
+          (dquot = lookup_dquot(device, id, type)) != (struct dquot *) 0) {
+          memcpy_tofs(dqblk, (char *) &dquot->dq_dqb, sizeof(struct dqblk));
+          unlock_dquot(dquot);
+          return 0;
+       } else {
+          if (id == 0) {
+             /*
+              * Special case for getting of expiration times.
+              */
+             memset(&exp_times, 0, sizeof(struct dqblk));
+             exp_times.dqb_btime = device->dq_iexp;
+             exp_times.dqb_itime = device->dq_bexp;
+             memcpy_tofs(dqblk, &exp_times, sizeof(struct dqblk));
+             return 0;
+          }
+          return -ESRCH;
+       }
+    } else
+       return -ESRCH;
+ }
+ 
+ /*
+  * Sync quota on a device. Dev == 0 ==> sync all quotafiles.
+  * Type == -1 ==> sync all types.
+  */
+ int sync_quota(dev_t dev, int type)
+ {
+    register struct device_list *device;
+    int cnt, retval = 0;
+ 
+    if (dev) {
+       if (type != -1) {
+          if ((device = lookup_device(dev, type)) == (struct device_list *) 0)
+             return -ESRCH;
+          return sync_device(device, type);
+       } else {
+          for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+             if ((device = lookup_device(dev, cnt)) == (struct device_list *) 0)
+                continue;
+             retval |= sync_device(device, cnt);
+          }
+          return retval;
+       }
+    } else {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+          device = devicelist[cnt];
+          while (device != (struct device_list *) 0) {
+             retval |= sync_device(device, cnt);
+             device = device->next;
+          }
+       }
+       return retval;
+    }
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
+  */
+ int quota_off(dev_t dev, int type)
+ {
+    register struct device_list *device;
+    register struct inode *inode = (struct inode *) 0;
+    int cnt;
+ 
+    if (type != -1) {
+       if ((device = lookup_device(dev, type)) == (struct device_list *) 0)
+          return -ESRCH;
+ 
+       if (!device_can_be_removed(device))
+          return -EBUSY;
+ 
+       (void) sync_device(device, type);   /* Yes, just like Q_SYNC... */
+ 
+       if (device->dq_file.f_op->release)
+          device->dq_file.f_op->release(device->dq_file.f_inode,
+                                        &device->dq_file);
+ 
+       if ((inode = device->dq_file.f_inode) != (struct inode *) 0)
+          iput(device->dq_file.f_inode);   /* Now release the inode */
+ 
+       remove_device(dev, type);
+    } else {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+          if ((device = lookup_device(dev, cnt)) == (struct device_list *) 0)
+             continue;
+ 
+          if (!device_can_be_removed(device))
+             return -EBUSY;
+ 
+          (void) sync_device(device, cnt);   /* Yes, just like Q_SYNC... */
+ 
+          if (device->dq_file.f_op->release)
+             device->dq_file.f_op->release(device->dq_file.f_inode,
+                                           &device->dq_file);
+ 
+          if ((inode = device->dq_file.f_inode) != (struct inode *) 0)
+             iput(device->dq_file.f_inode);   /* Now release the inode */
+ 
+          remove_device(dev, cnt);
+       }
+    }
+    return 0;
+ }
+ 
+ int quota_on(dev_t dev, const char *devicename, int type, char *path)
+ {
+    register struct device_list *device;
+    struct dqblk dq_dqb;
+    struct inode *inode;
+    char *tmp;
+    int error, maxid, id = ID_NO_QUOTA;
+    unsigned short  fs;
+ 
+    /* Quota already enabled */
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       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 ((device = add_device(dev, devicename, type)) == (struct device_list *) 0) {
+       iput(inode);
+       return -EUSERS;
+    }
+ 
+    fs = get_fs();
+    if (!inode->i_op || !inode->i_op->default_file_ops)
+       goto end_quotaon;
+ 
+    device->dq_file.f_mode = 3;
+    device->dq_file.f_flags = 0;
+    device->dq_file.f_count = 1;
+    device->dq_file.f_inode = inode;
+    device->dq_file.f_pos = 0;
+    device->dq_file.f_reada = 0;
+    device->dq_file.f_op = inode->i_op->default_file_ops;
+ 
+    if (device->dq_file.f_op->open)
+       if (device->dq_file.f_op->open(device->dq_file.f_inode, &device->dq_file))
+          goto end_quotaon;
+ 
+    if (!device->dq_file.f_op->read)
+       goto end_quotaon;
+ 
+    maxid = inode->i_size / sizeof(struct dqblk);
+ 
+    set_fs(KERNEL_DS);
+ 
+    /* First read expire times */
+    if (device->dq_file.f_op->read(inode, &device->dq_file,
+        (char *)&dq_dqb, sizeof(struct dqblk)) != sizeof(struct dqblk))
+       goto end_quotaon;
+    set_dqblk(device, 0, type, SET_QUOTA, &dq_dqb);
+ 
+    /* Seek to first real entry */
+    if (device->dq_file.f_op->lseek) {
+       if (device->dq_file.f_op->lseek(inode, &device->dq_file,
+           dqoff(id), 0) != dqoff(id))
+          goto end_quotaon;
+    } else
+       device->dq_file.f_pos = dqoff(id);
+ 
+    while (id < maxid) {
+       if (device->dq_file.f_op->read(inode, &device->dq_file, (char *)&dq_dqb,
+           sizeof(struct dqblk)) != sizeof(struct dqblk))
+          goto end_quotaon;
+       set_dqblk(device, id++, type, SET_QUOTA, &dq_dqb);
+    }
+    set_fs(fs);
+ 
+    return 0;
+ 
+ end_quotaon:
+    set_fs(fs);
+    iput(inode);
+    remove_device(device->dq_dev, type);
+    return -EIO;
+ }
+ 
+ void quota_init(void)
+ {
+    unsigned short  cnt;
+ 
+    for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+       devicelist[cnt] = (struct device_list *) 0;
+       mru_dquot[cnt] = (struct dquot *) 0;
+       mru_device[cnt] = (struct device_list *) 0;
+    }
+ }
+ 
+ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t * addr)
+ {
+    int cmds = 0, type = 0;
+    struct inode *ino;
+    dev_t dev;
+ 
+    cmds = cmd >> SUBCMDSHIFT;
+    type = cmd & SUBCMDMASK;
+    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 *)0 && cmds == Q_SYNC)
+       dev = 0;
+    else {
+       if (namei(special, &ino))
+          return -EINVAL;
+       dev = ino->i_rdev;
+       if (!S_ISBLK(ino->i_mode)) {
+          iput(ino);
+          return -ENOTBLK;
+       }
+       iput(ino);
+    }
+ 
+    if ((u_int) type >= MAXQUOTAS)
+       return -EINVAL;
+ 
+    switch (cmds) {
+       case Q_QUOTAON:
+          return quota_on(dev, special, 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:
+          return set_quota(dev, id, type, (struct dqblk *) addr);
+       case Q_SETUSE:
+          return set_use(dev, id, type, (struct dqblk *) addr);
+       case Q_SETQLIM:
+          return set_qlimit(dev, id, type, (struct dqblk *) addr);
+       case Q_SYNC:
+          return sync_quota(dev, type);
+       default:
+          return -EINVAL;
+    }
+    /* NOTREACHED */
+ }
+ 
+ #else
+ 
+ asmlinkage int sys_quotactl(int cmd, const char *special, int id, char *addr)
+ {
+    return -ENOSYS;
+ }
+ 
+ #endif /* CONFIG_QUOTA */
+ 
diff -rc --new-file linuxpl14/fs/read_write.c linux/fs/read_write.c
*** linuxpl14/fs/read_write.c	Sat Sep  4 05:36:30 1993
--- linux/fs/read_write.c	Wed Dec  8 09:53:41 1993
***************
*** 9,14 ****
--- 9,16 ----
  #include <linux/stat.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
+ #include <linux/config.h>
+ #include <linux/fileio.h>
  
  #include <asm/segment.h>
  
***************
*** 104,108 ****
  	error = verify_area(VERIFY_READ,buf,count);
  	if (error)
  		return error;
! 	return file->f_op->write(inode,file,buf,count);
  }
--- 106,110 ----
  	error = verify_area(VERIFY_READ,buf,count);
  	if (error)
  		return error;
! 	return vfs_write(inode, file, buf, count);
  }
diff -rc --new-file linuxpl14/fs/super.c linux/fs/super.c
*** linuxpl14/fs/super.c	Mon Nov 29 22:40:36 1993
--- linux/fs/super.c	Wed Dec  8 09:53:41 1993
***************
*** 15,20 ****
--- 15,23 ----
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/locks.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/system.h>
  #include <asm/segment.h>
***************
*** 216,221 ****
--- 219,227 ----
  		}
  		return 0;
  	}
+ #ifdef CONFIG_QUOTA
+ 	quota_off(dev, -1); /* Turn off all quotas first */
+ #endif
  	if (!(sb=get_super(dev)) || !(sb->s_covered))
  		return -ENOENT;
  	if (!sb->s_covered->i_mount)
diff -rc --new-file linuxpl14/include/linux/fileio.h linux/include/linux/fileio.h
*** linuxpl14/include/linux/fileio.h
--- linux/include/linux/fileio.h	Wed Dec  8 10:00:12 1993
***************
*** 0 ****
--- 1,259 ----
+ /*
+  *
+  * Simple VFS definitions for fileio. It contains both versions for normal
+  * and for quota supported routines.
+  *
+  * Authors: Marco van Wieringen <v892273@si.hhs.nl> <mvw@mercury.mcs.nl.mugnet.org>
+  *          Edvard Tuinder <v892231@si.hhs.nl> <ed@delirium.nl.mugnet.org>
+  *
+  * Version: $Id: fileio.h,v 1.1 1993/11/08 20:49:01 mvw Exp mvw $
+  *
+  */
+ #ifndef _LINUX_FILEIO_H
+ #define _LINUX_FILEIO_H
+ 
+ #include <linux/config.h>
+ 
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ 
+ int lookup(struct inode *, const char *, int, struct inode **);
+ 
+ static inline int vfs_write(struct inode *ino, struct file *file,
+                             char *addr, size_t bytes)
+ {
+    size_t written;
+    u_long cur_blocks, wanted_blocks, avail_blocks;
+ 
+    if (S_ISREG(ino->i_mode)) {
+       cur_blocks = isize_to_blocks(ino->i_size, ino->i_blksize);
+       wanted_blocks = isize_to_blocks(file->f_pos + bytes, ino->i_blksize) -
+                       cur_blocks;
+       if (quota_alloc(ino->i_dev, ino->i_uid, ino->i_gid, 0,
+                       wanted_blocks, &avail_blocks) == NO_QUOTA)
+          return -EDQUOT;
+       if (avail_blocks < wanted_blocks)
+          bytes = blocks_to_isize((cur_blocks + avail_blocks), ino->i_blksize) -
+                  file->f_pos;
+       if ((written = file->f_op->write(ino, file, addr, bytes)) != bytes) {
+          quota_remove(ino->i_dev, ino->i_uid, ino->i_gid, 0, avail_blocks -
+                      (isize_to_blocks(ino->i_size, ino->i_blksize) -
+                       isize_to_blocks((ino->i_size - written), ino->i_blksize)));
+       }
+       if (avail_blocks < wanted_blocks)
+          return -EDQUOT;
+ 
+       return written;
+    } else
+       return file->f_op->write(ino, file, (char *)addr, bytes);
+ }
+ 
+ static inline int vfs_create(struct inode *dir, const char *basename,
+                              int namelen, int mode, struct inode **res_ino)
+ {
+    int error;
+ 
+    if (quota_alloc(dir->i_dev, current->euid, current->egid, 1, 0,
+                   (u_long *)0) == NO_QUOTA)
+       return -EDQUOT;
+    error = dir->i_op->create(dir, basename, namelen, mode, res_ino);
+    if (error)
+       quota_remove(dir->i_dev, current->euid, current->egid, 1, 0);
+ 
+    return error;
+ }
+ 
+ static inline int vfs_truncate(struct inode *ino, size_t lenght)
+ {
+    int error;
+    size_t old_isize;
+ 
+    old_isize = ino->i_size;
+    ino->i_size = lenght;
+    if (ino->i_op && ino->i_op->truncate)
+       ino->i_op->truncate(ino);
+    ino->i_ctime = ino->i_mtime = CURRENT_TIME;
+    ino->i_dirt = 1;
+    if ((error = notify_change(NOTIFY_SIZE, ino))) {
+       return error;
+    }
+    quota_remove(ino->i_dev, ino->i_uid, ino->i_gid, 0,
+                 isize_to_blocks(old_isize, ino->i_blksize));
+ 
+    return error;
+ }
+ 
+ static inline int vfs_mknod(struct inode *dir, const char *basename,
+                             int namelen, int mode, dev_t dev)
+ {
+    int error;
+ 
+    if (quota_alloc(dir->i_dev, current->euid, current->egid, 1, 0,
+       (u_long *)0) == NO_QUOTA) {
+       iput(dir);
+       return -EDQUOT;
+    }
+    dir->i_count++; /* mknod uses up dir */
+    error = dir->i_op->mknod(dir, basename, namelen, mode, dev);
+    if (error)
+       quota_remove(dir->i_dev, current->euid, current->egid, 1, 0);
+    iput(dir);
+ 
+    return error;
+ }
+ 
+ static inline int vfs_mkdir(struct inode *dir, const char *basename,
+                             int namelen, int mode)
+ {
+    int error;
+ 
+    if (quota_alloc(dir->i_dev, current->euid, current->egid, 1, 1,
+                   (u_long *)0) == NO_QUOTA) {
+       iput(dir);
+       return -EDQUOT;
+    }
+    dir->i_count++; /* mkdir uses up dir */
+    error = dir->i_op->mkdir(dir, basename, namelen, mode);
+    if (error)
+       quota_remove(dir->i_dev, current->euid, current->egid, 1, 1);
+    iput(dir);
+ 
+    return error;
+ }
+ 
+ static inline int vfs_rmdir(struct inode *dir, const char *basename,
+                             int namelen)
+ {
+    int error;
+    struct inode inode, *ino;
+ 
+    /* Need inode entry of directory */
+    dir->i_count++; /* lookup uses up dir */
+    if ((error = lookup(dir, basename, namelen, &ino))) {
+       iput(dir);
+       return error;
+    }
+    inode = *ino;
+    iput(ino);
+    if (!(error = dir->i_op->rmdir(dir, basename, namelen)))
+       quota_remove(inode.i_dev, inode.i_uid, inode.i_gid, 1, 1);
+ 
+    return error;
+ }
+ 
+ static inline int vfs_unlink(struct inode *dir, const char *basename,
+                              int namelen)
+ {
+    int error;
+    struct inode inode, *ino;
+ 
+    /* Need inode info for quota operations */
+    dir->i_count++; /* lookup uses up dir */
+    if ((error = lookup(dir, basename, namelen, &ino))) {
+       iput(dir);
+       return error;
+    }
+    inode = *ino;
+    iput(ino);
+    error = dir->i_op->unlink(dir, basename, namelen);
+    /* Remove block and inode. Only if link-count was 1 ! */
+    if (!error && inode.i_nlink == 1)
+       quota_remove(inode.i_dev, inode.i_uid, inode.i_gid, 1,
+                    isize_to_blocks(inode.i_size, inode.i_blksize));
+ 
+    return error;
+ }
+ 
+ static inline int vfs_symlink(struct inode *dir, const char *basename,
+                               int namelen, const char *oldname)
+ {
+    int error;
+ 
+    if (quota_alloc(dir->i_dev, current->euid, current->egid, 1, 1,
+       (u_long *)0) == NO_QUOTA) {
+       iput(dir);
+       return -EDQUOT;
+    }
+    dir->i_count++; /* symlink uses up dir */
+    if (!(error = dir->i_op->symlink(dir, basename, namelen, oldname)))
+       quota_remove(dir->i_dev, current->euid, current->egid, 1, 1);
+    iput(dir);
+ 
+    return error;
+ }
+ 
+ static inline int vfs_chown(struct inode *ino, uid_t uid, gid_t gid)
+ {
+    int error;
+    uid_t olduid;
+    gid_t oldgid;
+ 
+    olduid = ino->i_uid;
+    oldgid = ino->i_gid;
+    if (quota_transfer(ino->i_dev, olduid, uid, oldgid, gid, 1,
+                       isize_to_blocks(ino->i_size, ino->i_blksize)) == NO_QUOTA)
+       return -EDQUOT;
+    ino->i_uid = uid;
+    ino->i_gid = gid;
+    ino->i_ctime = CURRENT_TIME;
+    ino->i_dirt = 1;
+    error = notify_change(NOTIFY_UIDGID, ino);
+    if (error)
+       quota_transfer(ino->i_dev, uid, olduid, gid, oldgid, 1,
+                      isize_to_blocks(ino->i_size, ino->i_blksize));
+ 
+    return error;
+ }
+ 
+ #else /* CONFIG_QUOTA */
+ 
+ static inline int vfs_write(struct inode *ino, struct file *file,
+                             char *addr, int bytes)
+ {
+    return file->f_op->write(ino, file, addr, bytes);
+ }
+ 
+ #define vfs_create(dir, basename, namelen, mode, res_ino) \
+ dir->i_op->create(dir, basename, namelen, mode, res_inode)
+ 
+ static inline int vfs_truncate(struct inode *ino, size_t lenght)
+ {
+    int error;
+ 
+    ino->i_size = lenght;
+    if (ino->i_op && ino->i_op->truncate)
+       ino->i_op->truncate(ino);
+    if ((error = notify_change(NOTIFY_SIZE, ino))) {
+       return error;
+    }
+    ino->i_dirt = 1;
+ 
+    return error;
+ }
+ 
+ #define vfs_mknod(dir, basename, namelen, mode, dev) \
+ dir->i_op->mknod((dir),(basename),(namelen),(mode),(dev))
+ 
+ #define vfs_mkdir(dir, basename, namelen, mode) \
+ dir->i_op->mkdir((dir),(basename),(namelen),(mode))
+ 
+ #define vfs_rmdir(dir, basename, namelen) \
+ dir->i_op->rmdir((dir),(basename),(namelen));
+ 
+ #define vfs_unlink(dir, basename, namelen) \
+ dir->i_op->unlink((dir),(basename),(namelen));
+ 
+ #define vfs_symlink(dir, basename, namelen, oldname) \
+ dir->i_op->symlink((dir),(basename),(namelen),(oldname));
+ 
+ static inline int vfs_chown(struct inode *ino, uid_t uid, gid_t gid)
+ {
+    ino->i_uid = uid;
+    ino->i_gid = gid;
+    ino->i_ctime = CURRENT_TIME;
+    ino->i_dirt = 1;
+    return notify_change(NOTIFY_UIDGID, ino);
+ }
+ 
+ #endif /* CONFIG_QUOTA */
+ #endif /* _LINUX_FILEIO_H */
diff -rc --new-file linuxpl14/include/linux/kernel.h linux/include/linux/kernel.h
*** linuxpl14/include/linux/kernel.h	Mon Nov 29 22:40:36 1993
--- linux/include/linux/kernel.h	Wed Dec  8 09:53:41 1993
***************
diff -rc --new-file linuxpl14/include/linux/quota.h linux/include/linux/quota.h
*** linuxpl14/include/linux/quota.h
--- linux/include/linux/quota.h	Wed Dec  8 10:00:02 1993
***************
*** 0 ****
--- 1,207 ----
+ /*
+  * 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.5 1993/11/11 21:51: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)
+ 
+ /*
+  * Some nice macros to determine min and max of two values
+  */
+ #define min(a,b) ((a) < (b)) ? (a) : (b)
+ #define max(a,b) ((a) > (b)) ? (a) : (b)
+ 
+ /*
+  * Definitions for disk quotas imposed on the average user
+  * (big brother finally hits UNIX).
+  *
+  * 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 */
+ 
+ #define ID_NO_QUOTA 10 /* ids for which quota isn't enabled (<=)*/
+ 
+ /*
+  * Definitions for the default names of the quotas files.
+  */
+ #define INITQFNAMES { \
+    "user",      /* USRQUOTA */ \
+    "group",   /* GRPQUOTA */ \
+    "undefined", \
+ };
+ #define QUOTAFILENAME "quota"
+ #define QUOTAGROUP "staff"
+ 
+ /*
+  * 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 {
+    u_long dqb_bhardlimit;   /* absolute limit on disk blks alloc */
+    u_long dqb_bsoftlimit;   /* preferred limit on disk blks */
+    u_long dqb_curblocks;    /* current block count */
+    u_long dqb_ihardlimit;   /* maximum # allocated inodes */
+    u_long dqb_isoftlimit;   /* preferred inode limit */
+    u_long 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
+ 
+ #include <linux/fs.h>
+ 
+ struct device_list {
+    dev_t               dq_dev;        /* device number */
+    char                dq_dirt;       /* quotas are updated since last write */
+    time_t              dq_iexp;       /* expiration time of inode softlimit */
+    time_t              dq_bexp;       /* expiration time of block softlimit */
+    struct file         dq_file;       /* filepointer to quotafile on the device */ 
+    char               *dq_devicename; /* devicename of device */
+    struct dquot       *dq_quota;      /* list of ids with quota on this device */
+    struct device_list *next;          /* pointer to next device */
+ };
+ 
+ #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_REMOVE     0x40            /* sync this dqblk and remove from list */
+ 
+ struct dquot {
+    int                dq_id;          /* id this applies to (uid, gid) */
+    short              dq_flags;       /* see DQ_* */
+    struct dqblk       dq_dqb;         /* diskquota for id */
+    struct wait_queue *dq_wait;        /* pointer to waitqueue */
+    struct dquot      *next;           /* pointer to next id */
+ };
+ 
+ /*
+  * Flags used for set_dqblk.
+  */
+ #define QUOTA_SYSCALL     0x01
+ #define SET_QUOTA         0x02
+ #define SET_USE           0x04
+ #define SET_QLIMIT        0x08
+ 
+ /*
+  * Return values when requesting quota.
+  */
+ #define NO_QUOTA 0                    /* no more quota available */
+ #define QUOTA_OK 1                    /* can allocate the space */
+ 
+ /*
+  * declaration of quota_function calls in kernel.
+  */
+ u_long isize_to_blocks(size_t isize, size_t blksize);
+ size_t blocks_to_isize(u_long blocks, size_t blksize);
+ int    quota_alloc(dev_t dev, uid_t uid, gid_t gid, u_long inodes,
+                    u_long wantedblocks, u_long *availblocks);
+ int    quota_transfer(dev_t dev, uid_t olduid, uid_t newuid, gid_t oldgid,
+                       gid_t newgid, u_long inodes, u_long blocks);
+ void   quota_remove(dev_t dev, uid_t uid, gid_t gid, u_long inodes,
+                     u_long blocks);
+ int    sync_quota(dev_t dev, int type);
+ int    quota_off(dev_t dev, int type);
+ 
+ #else
+ 
+ #include <sys/cdefs.h>
+ 
+ __BEGIN_DECLS
+ int   quotactl __P((int, const char *, int, caddr_t *));
+ __END_DECLS
+ 
+ #endif /* __KERNEL__ */
+ #endif /* _QUOTA_ */
diff -rc --new-file linuxpl14/include/linux/sys.h linux/include/linux/sys.h
*** linuxpl14/include/linux/sys.h	Fri Oct 29 08:44:28 1993
--- linux/include/linux/sys.h	Wed Dec  8 09:53:41 1993
***************
*** 135,140 ****
--- 135,141 ----
  extern int sys_adjtimex();
  extern int sys_mprotect();
  extern int sys_sigprocmask();
+ extern int sys_quotactl();
  
  /*
   * These are system calls that will be removed at some time
diff -rc --new-file linuxpl14/include/linux/unistd.h linux/include/linux/unistd.h
*** linuxpl14/include/linux/unistd.h	Wed Oct 27 15:07:23 1993
--- linux/include/linux/unistd.h	Wed Dec  8 09:53:42 1993
***************
*** 133,138 ****
--- 133,139 ----
  #define __NR_adjtimex		124
  #define __NR_mprotect		125
  #define __NR_sigprocmask	126
+ #define __NR_quotactl           127
  
  extern int errno;
  
diff -rc --new-file linuxpl14/init/main.c linux/init/main.c
*** linuxpl14/init/main.c	Sun Nov 28 15:08:32 1993
--- linux/init/main.c	Wed Dec  8 09:53:42 1993
***************
*** 93,98 ****
--- 93,101 ----
  #ifdef CONFIG_SYSVIPC
  extern void ipc_init(void);
  #endif
+ #ifdef CONFIG_QUOTA
+ extern void quota_init(void);
+ #endif
  #ifdef CONFIG_SCSI
  extern unsigned long scsi_dev_init(unsigned long, unsigned long);
  #endif
***************
*** 384,389 ****
--- 387,395 ----
  #ifdef CONFIG_SYSVIPC
  	ipc_init();
  #endif
+ #ifdef CONFIG_QUOTA
+ 	quota_init();
+ #endif
  	sti();
  	
  	/*
diff -rc --new-file linuxpl14/kernel/sched.c linux/kernel/sched.c
*** linuxpl14/kernel/sched.c	Sun Nov 28 15:08:32 1993
--- linux/kernel/sched.c	Wed Dec  8 09:56:02 1993
***************
*** 126,132 ****
  sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
  sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
  sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
! sys_adjtimex, sys_mprotect, sys_sigprocmask };
  
  /* So we don't have to do any more manual updating.... */
  int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
--- 126,132 ----
  sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
  sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
  sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
! sys_adjtimex, sys_mprotect, sys_sigprocmask, sys_quotactl};
  
  /* So we don't have to do any more manual updating.... */
  int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
