<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	fcntl.patch
# This archive created: Tue Aug 18 14:16:48 1992
cat &lt;&lt; \SHAR_EOF &gt; README
README for fcntl.patch

This patch provides an almost complete implementation of the file locking
facilities provided by fcntl(). The only missing pieces are

- deadlock detection
- mandatory locks

Neither of these have a very high priority with me so I do not intend to
implement them soon.

This patch must be applied to Linux 0.97 Patch Level 1.

Apply it with:

cd /usr/src
patch -p0 &lt;fcntl.patch 2&gt;&amp;1 | tee fcntlpatch.log

Enjoy!

Doug Evans, dje@sspiff.UUCP or dje@sspiff.ampr.ab.ca, 92Aug18
SHAR_EOF
cat &lt;&lt; \SHAR_EOF &gt; fcntl.patch
*** linux.pl1/fs/Makefile	Sat Aug  1 15:44:01 1992
--- linux/fs/Makefile	Sat Aug  8 00:02:15 1992
***************
*** 7,13 ****
  #
  # Note 2! The CFLAGS definitions are now in the main makefile...
  
! SUBDIRS	=minix ext msdos
  
  .c.s:
  	$(CC) $(CFLAGS) -S $&lt;
--- 7,13 ----
  #
  # Note 2! The CFLAGS definitions are now in the main makefile...
  
! SUBDIRS	=minix ext msdos # xenix
  
  .c.s:
  	$(CC) $(CFLAGS) -S $&lt;
***************
*** 18,24 ****
  
  OBJS=	open.o read_write.o inode.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
  
  all: fs.o fssubdirs
  
--- 18,24 ----
  
  OBJS=	open.o read_write.o inode.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
  
  all: fs.o fssubdirs
  
*** linux.pl1/fs/fcntl.c	Tue Aug 18 12:51:57 1992
--- linux/fs/fcntl.c	Tue Aug 18 13:11:57 1992
***************
*** 14,19 ****
--- 14,21 ----
  #include &lt;linux/string.h&gt;
  
  extern int sys_close(int fd);
+ extern int fcntl_getlk(unsigned int, struct flock *);
+ extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
  
  static int dupfd(unsigned int fd, unsigned int arg)
  {
***************
*** 56,85 ****
  	if (fd &gt;= NR_OPEN || !(filp = current-&gt;filp[fd]))
  		return -EBADF;
  	switch (cmd) {
! 		case F_DUPFD:
! 			return dupfd(fd,arg);
! 		case F_GETFD:
! 			return (current-&gt;close_on_exec&gt;&gt;fd)&amp;1;
! 		case F_SETFD:
! 			if (arg&amp;1)
! 				current-&gt;close_on_exec |= (1&lt;&lt;fd);
! 			else
! 				current-&gt;close_on_exec &amp;= ~(1&lt;&lt;fd);
! 			return 0;
! 		case F_GETFL:
! 			return filp-&gt;f_flags;
! 		case F_SETFL:
! 			filp-&gt;f_flags &amp;= ~(O_APPEND | O_NONBLOCK);
! 			filp-&gt;f_flags |= arg &amp; (O_APPEND | O_NONBLOCK);
! 			return 0;
! 		case F_GETLK:	case F_SETLK:	case F_SETLKW:
! 			return -ENOSYS;
! 		default:
! 			/* sockets need a few special fcntls. */
! 			if (S_ISSOCK (filp-&gt;f_inode-&gt;i_mode))
! 			  {
! 			     return (sock_fcntl (filp, cmd, arg));
! 			  }
! 			return -EINVAL;
  	}
  }
--- 58,89 ----
  	if (fd &gt;= NR_OPEN || !(filp = current-&gt;filp[fd]))
  		return -EBADF;
  	switch (cmd) {
! 	case F_DUPFD:
! 		return dupfd(fd,arg);
! 	case F_GETFD:
! 		return (current-&gt;close_on_exec&gt;&gt;fd)&amp;1;
! 	case F_SETFD:
! 		if (arg&amp;1)
! 			current-&gt;close_on_exec |= (1&lt;&lt;fd);
! 		else
! 			current-&gt;close_on_exec &amp;= ~(1&lt;&lt;fd);
! 		return 0;
! 	case F_GETFL:
! 		return filp-&gt;f_flags;
! 	case F_SETFL:
! 		filp-&gt;f_flags &amp;= ~(O_APPEND | O_NONBLOCK);
! 		filp-&gt;f_flags |= arg &amp; (O_APPEND | O_NONBLOCK);
! 		return 0;
! 	case F_GETLK:
! 		return fcntl_getlk(fd, (struct flock *) arg);
! 	case F_SETLK:
! 		return fcntl_setlk(fd, cmd, (struct flock *) arg);
! 	case F_SETLKW:
! 		return fcntl_setlk(fd, cmd, (struct flock *) arg);
! 	default:
! 		/* sockets need a few special fcntls. */
! 		if (S_ISSOCK (filp-&gt;f_inode-&gt;i_mode))
! 		      return sock_fcntl (filp, cmd, arg);
! 		return -EINVAL;
  	}
  }
*** linux.pl1/fs/open.c	Tue Aug 18 12:51:57 1992
--- linux/fs/open.c	Mon Aug 17 13:31:22 1992
***************
*** 17,22 ****
--- 17,24 ----
  #include &lt;linux/tty.h&gt;
  #include &lt;asm/segment.h&gt;
  
+ extern void fcntl_remove_locks(struct task_struct *, struct file *);
+ 
  struct file_operations * chrdev_fops[MAX_CHRDEV] = {
  	NULL,
  };
***************
*** 339,347 ****
  }
  
  static int
! close_fp (struct file *filp)
! {
!    struct inode *inode;
  
  	if (filp-&gt;f_count == 0) {
  		printk("Close: file count is 0\n");
--- 341,349 ----
  }
  
  static int
! close_fp(struct file *filp)
! {	
! 	struct inode * inode;
  
  	if (filp-&gt;f_count == 0) {
  		printk("Close: file count is 0\n");
***************
*** 348,359 ****
  		return 0;
  	}
  
  	if (filp-&gt;f_count &gt; 1) {
  		filp-&gt;f_count--;
  		return 0;
  	}
!      
! 	inode = filp-&gt;f_inode;
  	if (filp-&gt;f_op &amp;&amp; filp-&gt;f_op-&gt;release)
  		filp-&gt;f_op-&gt;release(inode,filp);
  
--- 350,364 ----
  		return 0;
  	}
  
+ 	inode = filp-&gt;f_inode;
+ 	if (S_ISREG(inode-&gt;i_mode))
+ 		fcntl_remove_locks(current, filp);
+ 
  	if (filp-&gt;f_count &gt; 1) {
  		filp-&gt;f_count--;
  		return 0;
  	}
! 
  	if (filp-&gt;f_op &amp;&amp; filp-&gt;f_op-&gt;release)
  		filp-&gt;f_op-&gt;release(inode,filp);
  
*** linux.pl1/fs/locks.c	Tue Aug 11 14:27:34 1992
--- linux/fs/locks.c	Tue Aug 18 13:18:51 1992
***************
*** 0 ****
--- 1,451 ----
+ /*
+  *  linux/fs/locks.c
+  *
+  *  Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls.
+  *  Doug Evans, 92Aug07, dje@sspiff.UUCP.
+  *
+  * FIXME: two things aren't handled yet:
+  *	- deadlock detection/avoidance (of dubious merit, but since it's in
+  *	  the definition, I guess it should be provided eventually)
+  *	- mandatory locks (requires lots of changes elsewhere)
+  *
+  * FIXME: Should vector locking operations through table based on filesystem
+  *	type. NFS mounts obviously won't be able to use this code.
+  */
+ 
+ #include &lt;asm/segment.h&gt;
+ 
+ #include &lt;linux/sched.h&gt;
+ #include &lt;linux/kernel.h&gt;
+ #include &lt;linux/errno.h&gt;
+ #include &lt;linux/stat.h&gt;
+ #include &lt;linux/fcntl.h&gt;
+ 
+ #define OFFSET_MAX	0x7fffffff	/* FIXME: move elsewhere? */
+ 
+ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l);
+ static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
+ static int overlap(struct file_lock *fl1, struct file_lock *fl2);
+ static int lock_it(struct file *filp, struct file_lock *caller);
+ static int unlock_it(struct file *filp, struct file_lock *caller);
+ static struct file_lock *alloc_lock(struct file *filp, struct file_lock *template);
+ static void free_lock(struct file *filp, struct file_lock *fl);
+ 
+ static struct file_lock file_lock_table[NR_FILE_LOCKS];
+ static struct file_lock *file_lock_free_list;
+ 
+ /*
+  * Called at boot time to initialize the lock table ...
+  */
+ 
+ void fcntl_init_locks(void)
+ {
+ 	struct file_lock *fl;
+ 
+ 	for (fl = &amp;file_lock_table[0]; fl &lt; file_lock_table + NR_FILE_LOCKS - 1; fl++) {
+ 		fl-&gt;fl_next = fl + 1;
+ 		fl-&gt;fl_owner = NULL;
+ 	}
+ 	file_lock_table[NR_FILE_LOCKS - 1].fl_next = NULL;
+ 	file_lock_table[NR_FILE_LOCKS - 1].fl_owner = NULL;
+ 	file_lock_free_list = &amp;file_lock_table[0];
+ }
+ 
+ int fcntl_getlk(unsigned int fd, struct flock *l)
+ {	
+ 	struct flock flock;
+ 	struct file *filp;
+ 	struct file_lock *fl,file_lock;
+ 
+ 	if (fd &gt;= NR_OPEN || !(filp = current-&gt;filp[fd]))
+ 		return -EBADF;
+ 	verify_area(l, sizeof(*l));
+ 	memcpy_fromfs(&amp;flock, l, sizeof(flock));
+ 	if (flock.l_type == F_UNLCK)
+ 		return -EINVAL;
+ 	if (!copy_flock(filp, &amp;file_lock, &amp;flock))
+ 		return -EINVAL;
+ 
+ 	for (fl = filp-&gt;f_inode-&gt;i_flock; fl != NULL; fl = fl-&gt;fl_next) {
+ 		if (conflict(&amp;file_lock, fl)) {
+ 			flock.l_pid = fl-&gt;fl_owner-&gt;pid;
+ 			flock.l_start = fl-&gt;fl_start;
+ 			flock.l_len = fl-&gt;fl_end == OFFSET_MAX ? 0 :
+ 				fl-&gt;fl_end - fl-&gt;fl_start + 1;
+ 			/* Note: this will always be SEEK_SET. */
+ 			flock.l_whence = fl-&gt;fl_whence;
+ 			flock.l_type = fl-&gt;fl_type;
+ 			memcpy_tofs(l, &amp;flock, sizeof(flock));
+ 			return 0;
+ 		}
+ 	}
+ 
+ 	flock.l_type = F_UNLCK;			/* no conflict found */
+ 	memcpy_tofs(l, &amp;flock, sizeof(flock));
+ 	return 0;
+ }
+ 
+ /*
+  * This function implements both F_SETLK and F_SETLKW.
+  */
+ 
+ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
+ {	
+ 	struct file *filp;
+ 	struct file_lock *fl,file_lock;
+ 	struct flock flock;
+ 
+ 	/*
+ 	 * Get arguments and validate them ...
+ 	 */
+ 
+ 	if (fd &gt;= NR_OPEN || !(filp = current-&gt;filp[fd]))
+ 		return -EBADF;
+ 	verify_area(l, sizeof(*l));
+ 	memcpy_fromfs(&amp;flock, l, sizeof(flock));
+ 	if (!copy_flock(filp, &amp;file_lock, &amp;flock))
+ 		return -EINVAL;
+ 	switch (file_lock.fl_type) {
+ 	case F_RDLCK :
+ 		if (!(filp-&gt;f_mode &amp; 1))
+ 			return -EBADF;
+ 		break;
+ 	case F_WRLCK :
+ 		if (!(filp-&gt;f_mode &amp; 2))
+ 			return -EBADF;
+ 		break;
+ 	case F_UNLCK :
+ 		break;
+ 	}
+ 
+ 	/*
+ 	 * F_UNLCK needs to be handled differently ...
+ 	 */
+ 
+ 	if (file_lock.fl_type == F_UNLCK)
+ 		return unlock_it(filp, &amp;file_lock);
+ 
+ 	/*
+ 	 * Scan for a conflicting lock ...
+ 	 */
+ 
+ repeat:
+ 	for (fl = filp-&gt;f_inode-&gt;i_flock; fl != NULL; fl = fl-&gt;fl_next) {
+ 		if (!conflict(&amp;file_lock, fl))
+ 			continue;
+ 		/*
+ 		 * File is locked by another process. If this is F_SETLKW
+ 		 * wait for the lock to be released.
+ 		 * FIXME: We need to check for deadlocks here.
+ 		 */
+ 		if (cmd == F_SETLKW) {
+ 			interruptible_sleep_on(&amp;fl-&gt;fl_wait);
+ 			goto repeat;
+ 		}
+ 		return -EAGAIN;
+ 	}
+ 
+ 	/*
+ 	 * Lock doesn't conflict with any other lock ...
+ 	 */
+ 
+ 	return lock_it(filp, &amp;file_lock);
+ }
+ 
+ /*
+  * This function is called when the file is closed.
+  */
+ 
+ void fcntl_remove_locks(struct task_struct *task, struct file *filp)
+ {
+ 	struct file_lock *fl,*next;
+ 
+ 	for (fl = filp-&gt;f_inode-&gt;i_flock; fl != NULL; ) {
+ 		/*
+ 		 * If this one is freed, &lt;fl_next&gt; gets clobbered when the
+ 		 * entry is moved to the free list, so grab it now ...
+ 		 */
+ 		next = fl-&gt;fl_next;
+ 		if (fl-&gt;fl_owner == task)
+ 			free_lock(filp, fl);
+ 		fl = next;
+ 	}
+ }
+ 
+ /*
+  * Verify a "struct flock" and copy it to a "struct file_lock" ...
+  * Result is a boolean indicating success.
+  */
+ 
+ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l)
+ {
+ 	off_t start;
+ 
+ 	if (!filp-&gt;f_inode)	/* just in case */
+ 		return 0;
+ 	if (!S_ISREG(filp-&gt;f_inode-&gt;i_mode))
+ 		return 0;
+ 	if (l-&gt;l_type != F_UNLCK &amp;&amp; l-&gt;l_type != F_RDLCK &amp;&amp; l-&gt;l_type != F_WRLCK)
+ 		return 0;
+ 	switch (l-&gt;l_whence) {
+ 	case 0 /*SEEK_SET*/ : start = 0; break;
+ 	case 1 /*SEEK_CUR*/ : start = filp-&gt;f_pos; break;
+ 	case 2 /*SEEK_END*/ : start = filp-&gt;f_inode-&gt;i_size; break;
+ 	default : return 0;
+ 	}
+ 	if ((start += l-&gt;l_start) &lt; 0 || l-&gt;l_len &lt; 0)
+ 		return 0;
+ 	fl-&gt;fl_type = l-&gt;l_type;
+ 	fl-&gt;fl_start = start;	/* we record the absolute position */
+ 	fl-&gt;fl_whence = 0;	/* FIXME: do we record &lt;l_start&gt; as passed? */
+ 	if (l-&gt;l_len == 0 || (fl-&gt;fl_end = start + l-&gt;l_len - 1) &lt; 0)
+ 		fl-&gt;fl_end = OFFSET_MAX;
+ 	fl-&gt;fl_owner = current;
+ 	fl-&gt;fl_wait = NULL;		/* just for cleanliness */
+ 	return 1;
+ }
+ 
+ /*
+  * Determine if lock &lt;sys_fl&gt; blocks lock &lt;caller_fl&gt; ...
+  */
+ 
+ static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+ {
+ 	if (caller_fl-&gt;fl_owner == sys_fl-&gt;fl_owner)
+ 		return 0;
+ 	if (!overlap(caller_fl, sys_fl))
+ 		return 0;
+ 	switch (caller_fl-&gt;fl_type) {
+ 	case F_RDLCK :
+ 		return sys_fl-&gt;fl_type != F_RDLCK;
+ 	case F_WRLCK :
+ 		return 1;	/* overlapping region not owned by caller */
+ 	}
+ 	return 0;	/* shouldn't get here, but just in case */
+ }
+ 
+ static int overlap(struct file_lock *fl1, struct file_lock *fl2)
+ {
+ 	if (fl1-&gt;fl_start &lt;= fl2-&gt;fl_start) {
+ 		return fl1-&gt;fl_end &gt;= fl2-&gt;fl_start;
+ 	} else {
+ 		return fl2-&gt;fl_end &gt;= fl1-&gt;fl_start;
+ 	}
+ }
+ 
+ /*
+  * Add a lock to a file ...
+  * Result is 0 for success or -ENOLCK.
+  *
+  * We try to be real clever here and always minimize the number of table
+  * entries we use. For example we merge adjacent locks whenever possible. This
+  * consumes a bit of cpu and code space, is it really worth it? Beats me.
+  *
+  * I've tried to keep the following as small and simple as possible. If you can
+  * make it smaller or simpler, please do. /dje 92Aug11
+  *
+  * WARNING: We assume the lock doesn't conflict with any other lock.
+  */
+ 
+ static int lock_it(struct file *filp, struct file_lock *caller)
+ {
+ 	struct file_lock *fl,*new;
+ 
+ 	/*
+ 	 * It's easier if we allocate a slot for the lock first, and then
+ 	 * release it later if we have to (IE: if it can be merged with
+ 	 * another). This way the for() loop always knows that &lt;caller&gt; is an
+ 	 * existing entry. This will cause the routine to fail unnecessarily
+ 	 * in rare cases, but perfection can be pushed too far. :-)
+ 	 */
+ 
+ 	if ((caller = alloc_lock(filp, caller)) == NULL)
+ 		return -ENOLCK;
+ 
+ 	/*
+ 	 * First scan to see if we are changing/augmenting an existing lock ...
+ 	 */
+ 
+ 	for (fl = filp-&gt;f_inode-&gt;i_flock; fl != NULL; fl = fl-&gt;fl_next) {
+ 		if (caller-&gt;fl_owner != fl-&gt;fl_owner)
+ 			continue;
+ 		if (caller == fl)
+ 			continue;
+ 		if (!overlap(caller, fl)) {
+ 			/*
+ 			 * Detect adjacent regions (if same lock type) ...
+ 			 */
+ 			if (caller-&gt;fl_type != fl-&gt;fl_type)
+ 				continue;
+ 			if (caller-&gt;fl_end + 1 == fl-&gt;fl_start) {
+ 				fl-&gt;fl_start = caller-&gt;fl_start;
+ 				free_lock(filp, caller);
+ 				caller = fl;
+ 				/* must continue, may overlap others now */
+ 			} else if (caller-&gt;fl_start - 1 == fl-&gt;fl_end) {
+ 				fl-&gt;fl_end = caller-&gt;fl_end;
+ 				free_lock(filp, caller);
+ 				caller = fl;
+ 				/* must continue, may overlap others now */
+ 			}
+ 			continue;
+ 		}
+ 		/*
+ 		 * We've found an overlapping region. Is it a change of lock
+ 		 * type, or are we changing the size of the locked space?
+ 		 */
+ 		if (caller-&gt;fl_type != fl-&gt;fl_type) {
+ 			if (caller-&gt;fl_start &gt; fl-&gt;fl_start &amp;&amp; caller-&gt;fl_end &lt; fl-&gt;fl_end) {
+ 				/*
+ 				 * The new lock splits the old one in two ...
+ 				 * &lt;fl&gt; is the bottom piece, &lt;caller&gt; is the
+ 				 * new lock, and &lt;new&gt; is the top piece.
+ 				 */
+ 				if ((new = alloc_lock(filp, fl)) == NULL) {
+ 					free_lock(filp, caller);
+ 					return -ENOLCK;
+ 				}
+ 				fl-&gt;fl_end = caller-&gt;fl_start - 1;
+ 				new-&gt;fl_start = caller-&gt;fl_end + 1;
+ 				return 0;
+ 			}
+ 			if (caller-&gt;fl_start &lt;= fl-&gt;fl_start &amp;&amp; caller-&gt;fl_end &gt;= fl-&gt;fl_end) {
+ 				/*
+ 				 * The new lock completely replaces old one ...
+ 				 */
+ 				free_lock(filp, fl);
+ 				return 0;
+ 			}
+ 			if (caller-&gt;fl_end &lt; fl-&gt;fl_end) {
+ 				fl-&gt;fl_start = caller-&gt;fl_end + 1;
+ 				/* must continue, may be more overlaps */
+ 			} else if (caller-&gt;fl_start &gt; fl-&gt;fl_start) {
+ 				fl-&gt;fl_end = caller-&gt;fl_start - 1;
+ 				/* must continue, may be more overlaps */
+ 			} else {
+ 				printk("lock_it: program bug: unanticipated overlap\n");
+ 				free_lock(filp, caller);
+ 				return -ENOLCK;
+ 			}
+ 		} else {	/* The new lock augments an existing lock ... */
+ 			int grew = 0;
+ 
+ 			if (caller-&gt;fl_start &lt; fl-&gt;fl_start) {
+ 				fl-&gt;fl_start = caller-&gt;fl_start;
+ 				grew = 1;
+ 			}
+ 			if (caller-&gt;fl_end &gt; fl-&gt;fl_end) {
+ 				fl-&gt;fl_end = caller-&gt;fl_end;
+ 				grew = 1;
+ 			}
+ 			free_lock(filp, caller);
+ 			caller = fl;
+ 			if (!grew)
+ 				return 0;
+ 			/* must continue, may be more overlaps */
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * New lock doesn't overlap any regions ...
+ 	 * alloc_lock() has already been called, so we're done!
+ 	 */
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Handle F_UNLCK ...
+  * Result is 0 for success, or -EINVAL or -ENOLCK.
+  * ENOLCK can happen when a lock is split into two.
+  */
+ 
+ static int unlock_it(struct file *filp, struct file_lock *caller)
+ {
+ 	int one_unlocked = 0;
+ 	struct file_lock *fl,*next;
+ 
+ 	for (fl = filp-&gt;f_inode-&gt;i_flock; fl != NULL; ) {
+ 		if (caller-&gt;fl_owner != fl-&gt;fl_owner || !overlap(caller, fl)) {
+ 			fl = fl-&gt;fl_next;
+ 			continue;
+ 		}
+ 		one_unlocked = 1;
+ 		if (caller-&gt;fl_start &gt; fl-&gt;fl_start &amp;&amp; caller-&gt;fl_end &lt; fl-&gt;fl_end) {
+ 			/*
+ 			 * Lock is split in two ...
+ 			 * &lt;fl&gt; is the bottom piece, &lt;next&gt; is the top piece.
+ 			 */
+ 			if ((next = alloc_lock(filp, fl)) == NULL)
+ 				return -ENOLCK;
+ 			fl-&gt;fl_end = caller-&gt;fl_start - 1;
+ 			next-&gt;fl_start = caller-&gt;fl_end + 1;
+ 			return 0;
+ 		}
+ 		if (caller-&gt;fl_start &lt;= fl-&gt;fl_start &amp;&amp; caller-&gt;fl_end &gt;= fl-&gt;fl_end) {
+ 			/*
+ 			 * &lt;fl_next&gt; gets clobbered when the entry is moved to
+ 			 * the free list, so grab it now ...
+ 			 */
+ 			next = fl-&gt;fl_next;
+ 			free_lock(filp, fl);
+ 			fl = next;
+ 		}
+ 		if (caller-&gt;fl_start == fl-&gt;fl_start &amp;&amp; caller-&gt;fl_end == fl-&gt;fl_end)
+ 			return 0;	/* no more to be found */
+ 		/* must continue, there may be more to unlock */
+ 	}
+ 
+ 	return one_unlocked ? 0 : -EINVAL;
+ }
+ 
+ static struct file_lock *alloc_lock(struct file *filp, struct file_lock *template)
+ {
+ 	struct file_lock *new;
+ 
+ 	if (file_lock_free_list == NULL)
+ 		return NULL;			/* no available entry */
+ 	if (file_lock_free_list-&gt;fl_owner != NULL)
+ 		panic("alloc_lock: broken free list\n");
+ 
+ 	new = file_lock_free_list;		/* remove from free list */
+ 	file_lock_free_list = file_lock_free_list-&gt;fl_next;
+ 
+ 	*new = *template;
+ 
+ 	new-&gt;fl_next = filp-&gt;f_inode-&gt;i_flock;	/* insert into file's list */
+ 	filp-&gt;f_inode-&gt;i_flock = new;
+ 
+ 	new-&gt;fl_owner = current;	/* FIXME: needed? */
+ 	new-&gt;fl_wait = NULL;
+ 	return new;
+ }
+ 
+ static void free_lock(struct file *filp, struct file_lock *fl)
+ {
+ 	struct file_lock **fl_p;
+ 
+ 	if (fl-&gt;fl_owner == NULL)	/* sanity check */
+ 		panic("free_lock: broken lock list\n");
+ 
+ 	/*
+ 	 * We only use a singly linked list to save some memory space
+ 	 * (the only place we'd use a doubly linked list is here).
+ 	 */
+ 
+ 	for (fl_p = &amp;filp-&gt;f_inode-&gt;i_flock; *fl_p != NULL; fl_p = &amp;(*fl_p)-&gt;fl_next) {
+ 		if (*fl_p == fl)
+ 			break;
+ 	}
+ 	if (*fl_p == NULL) {
+ 		printk("free_lock: lock is not in file's lock list\n");
+ 	} else {
+ 		*fl_p = (*fl_p)-&gt;fl_next;
+ 	}
+ 
+ 	fl-&gt;fl_next = file_lock_free_list;	/* add to free list */
+ 	file_lock_free_list = fl;
+ 	fl-&gt;fl_owner = NULL;			/* for sanity checks */
+ 
+ 	wake_up(&amp;fl-&gt;fl_wait);
+ }
*** linux.pl1/fs/super.c	Sat Aug  1 13:09:35 1992
--- linux/fs/super.c	Mon Aug 17 13:54:39 1992
***************
*** 12,17 ****
--- 12,18 ----
  #include &lt;linux/minix_fs.h&gt;
  #include &lt;linux/ext_fs.h&gt;
  #include &lt;linux/msdos_fs.h&gt;
+ /*#include &lt;linux/xenix_fs.h&gt;*/
  #include &lt;linux/kernel.h&gt;
  #include &lt;linux/stat.h&gt;
  #include &lt;linux/errno.h&gt;
***************
*** 21,26 ****
--- 22,28 ----
  
  int sync_dev(int dev);
  void wait_for_keypress(void);
+ void fcntl_init_locks(void);
  
  /* set_bit uses setb, as gas doesn't recognize setc */
  #define set_bit(bitnr,addr) ({ \
***************
*** 35,42 ****
  /* Move into include file later */
  
  static struct file_system_type file_systems[] = {
  	{minix_read_super,"minix"},
! 	{ext_read_super,"ext"},
  	{msdos_read_super,"msdos"},
  	{NULL,NULL}
  };
--- 37,45 ----
  /* Move into include file later */
  
  static struct file_system_type file_systems[] = {
+ 	/*{xenix_read_super,"xenix"},*/
  	{minix_read_super,"minix"},
! 	/*{ext_read_super,"ext"},*/
  	{msdos_read_super,"msdos"},
  	{NULL,NULL}
  };
***************
*** 314,319 ****
--- 317,323 ----
  		panic("bad i-node size");
  	for(i=0;i&lt;NR_FILE;i++)
  		file_table[i].f_count=0;
+ 	fcntl_init_locks();
  	if (MAJOR(ROOT_DEV) == 2) {
  		printk("Insert root floppy and press ENTER");
  		wait_for_keypress();
*** linux.pl1/include/linux/fcntl.h	Tue Aug 18 13:04:28 1992
--- linux/include/linux/fcntl.h	Tue Aug 18 13:02:31 1992
***************
*** 24,32 ****
  #define F_SETFD		2	/* set f_flags */
  #define F_GETFL		3	/* more flags (cloexec) */
  #define F_SETFL		4
! #define F_GETLK		5	/* not implemented */
! #define F_SETLK		6
! #define F_SETLKW	7
  
  #define F_SETOWN	8	/*  for sockets. */
  #define F_GETOWN	9	/*  for sockets. */
--- 24,32 ----
  #define F_SETFD		2	/* set f_flags */
  #define F_GETFL		3	/* more flags (cloexec) */
  #define F_SETFL		4
! #define F_GETLK		5	/* get conflicting lock */
! #define F_SETLK		6	/* set lock, don't wait */
! #define F_SETLKW	7	/* set lock, wait if necessary */
  
  #define F_SETOWN	8	/*  for sockets. */
  #define F_GETOWN	9	/*  for sockets. */
*** linux.pl1/include/linux/limits.h	Tue Aug 18 12:52:50 1992
--- linux/include/linux/limits.h	Mon Aug 17 13:34:52 1992
***************
*** 8,13 ****
--- 8,14 ----
  #define NR_FILE 128
  #define NR_SUPER 8
  #define NR_HASH 997
+ #define NR_FILE_LOCKS 32
  #define BLOCK_SIZE 1024
  #define BLOCK_SIZE_BITS 10
  #define MAX_CHRDEV 16
SHAR_EOF
#	End of shell archive
exit 0
</pre></body></html>