Date: Mon, 23 Jun 97 08:31:42 +0200
From: hjwidmai@foxboro.com (Hans-Joachim Widmaier)
To: linux-m68k@phil.uni-sb.de
Subject: L68K: affs 3.5 patch
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de

The patch to make loopback devices work with affs
is finally here. It's against 2.1.44pre2, but should
apply cleanly onto any 2.1. after .37.
Affs 3.5 for 2.0.xx is still in the works, sorry.

jbhr

diff -urN linux-o/fs/affs/Changes linux/fs/affs/Changes
--- linux-o/fs/affs/Changes	Sun Jun 22 14:37:08 1997
+++ linux/fs/affs/Changes	Sun Jun 22 08:42:31 1997
@@ -13,11 +13,25 @@
   reads basically work (but all files are of size 0).
   Alas, I've got no alpha to debug. :-(
 - If an affs mounted filesystem is exported via
-  nfs, it cannot be written to. No networking to
-  test that, either. :-(
+  nfs, it cannot be written to. 
+  As soon as I have my network up and running, I'll
+  try to fix this.
+- The partition checker (drivers/block/genhd.c)
+  doesn't work with devices which have 256 byte
+  blocks (some very old SCSI drives). 
 
 Please direct bug reports to: hjw@zvw.de
 
+Version 3.5
+-----------
+
+- Extension block caches are now allocated on
+  demand instead of when a file is opened, as
+  files can be read and written without opening
+  them (e. g. the loopback device does this).
+
+- Removed an unused function.
+
 Version 3.4
 -----------
 
@@ -80,7 +94,7 @@
   interface in Linux 1.3.
 - Write support.
 - Support for hard and symbolic links.
-- Lots of things I remeber even less ...
+- Lots of things I remember even less ...
 
 Version 2.0
 -----------
diff -urN linux-o/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- linux-o/fs/affs/amigaffs.c	Sun Jun 22 14:37:08 1997
+++ linux/fs/affs/amigaffs.c	Fri Jun 20 17:52:37 1997
@@ -26,27 +26,6 @@
  *
  */
 
-/* Find the next used hash entry at or after *HASH_POS in a directory's hash
-   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
-   the directory header block in memory.  If there are no more entries,
-   0 is returned.  Otherwise, the key number in the next used hash slot
-   is returned. */
-
-static int
-affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
-{
-	struct dir_front *dir_front = dir_data;
-	int i;
-
-	for (i = *hash_pos; i < hsize; i++)
-		if (dir_front->hashtable[i] != 0)
-			break;
-	if (i >= hsize)
-		return 0;
-	*hash_pos = i;
-	return htonl(dir_front->hashtable[i]);
-}
-
 /* Set *NAME to point to the file name in a file header block in memory
    pointed to by FH_DATA.  The length of the name is returned. */
 
diff -urN linux-o/fs/affs/file.c linux/fs/affs/file.c
--- linux-o/fs/affs/file.c	Sun Jun 22 14:38:26 1997
+++ linux/fs/affs/file.c	Sun Jun 22 08:26:07 1997
@@ -43,8 +43,8 @@
 			    unsigned long count);
 static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf,
 				unsigned long count);
-static int affs_open_file(struct inode *inode, struct file *filp);
 static int affs_release_file(struct inode *inode, struct file *filp);
+static int alloc_ext_cache(struct inode *inode);
 
 static struct file_operations affs_file_operations = {
 	NULL,			/* lseek - default */
@@ -54,7 +54,7 @@
 	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
-	affs_open_file,		/* special open is needed */
+	NULL,			/* no special open */
 	affs_release_file,	/* release */
 	file_fsync		/* brute force, but works */
 };
@@ -87,7 +87,7 @@
 	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
-	affs_open_file,		/* special open is needed */
+	NULL,			/* no special open */
 	affs_release_file,	/* release */
 	file_fsync		/* brute force, but works */
 };
@@ -248,9 +248,9 @@
 		return 0;
 	}
 	if (!inode->u.affs_i.i_ec) {
-		affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)",
-			inode->i_ino);
-		return 0;
+		if (alloc_ext_cache(inode)) {
+			return 0;
+		}
 	}
 
 	/* Try to find the requested key in the cache.
@@ -582,6 +582,12 @@
 		iput(inode);
 		return -EINVAL;
 	}
+	if (!inode->u.affs_i.i_ec) {
+		if (alloc_ext_cache(inode)) {
+			iput(inode);
+			return -ENOMEM;
+		}
+	}
 	if (filp->f_flags & O_APPEND) {
 		pos = inode->i_size;
 	} else
@@ -861,40 +867,6 @@
 }
 
 static int
-affs_open_file(struct inode *inode, struct file *filp)
-{
-	int	 error;
-	u32	 key;
-	int	 i;
-
-	pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
-
-	error = 0;
-	inode->u.affs_i.i_cache_users++;
-	lock_super(inode->i_sb);
-	if (!inode->u.affs_i.i_ec) {
-		inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
-		if (!inode->u.affs_i.i_ec) {
-			affs_error(inode->i_sb,"open_file","Cache allocation failed");
-			error = ENOMEM;
-		} else {
-			/* We only have to initialize non-zero values.
-			 * get_free_page() zeroed the page already.
-			 */
-			key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
-			inode->u.affs_i.i_ec->ec[0] = key;
-			for (i = 0; i < 4; i++) {
-				inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
-				inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
-			}
-		}
-	}
-	unlock_super(inode->i_sb);
-
-	return error;
-}
-
-static int
 affs_release_file(struct inode *inode, struct file *filp)
 {
 	struct affs_zone	*zone;
@@ -916,13 +888,35 @@
 			unlock_super(inode->i_sb);
 		}
 	}
+	return 0;
+}
+
+static int
+alloc_ext_cache(struct inode *inode)
+{
+	s32	 key;
+	int	 i;
+
 	lock_super(inode->i_sb);
-	if (--inode->u.affs_i.i_cache_users == 0) {
+	if (!inode->u.affs_i.i_ec) {
+		inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
 		if (inode->u.affs_i.i_ec) {
-			free_page((unsigned long)inode->u.affs_i.i_ec);
-			inode->u.affs_i.i_ec = NULL;
+			/* We only have to initialize non-zero values.
+			 * get_free_page() zeroed the page already.
+			 */
+			key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+			inode->u.affs_i.i_ec->ec[0] = key;
+			for (i = 0; i < 4; i++) {
+				inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
+				inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
+			}
 		}
 	}
 	unlock_super(inode->i_sb);
+
+	if (!inode->u.affs_i.i_ec) {
+		affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
+		return -ENOMEM;
+	}
 	return 0;
 }
diff -urN linux-o/fs/affs/inode.c linux/fs/affs/inode.c
--- linux-o/fs/affs/inode.c	Sun Jun 22 14:38:26 1997
+++ linux/fs/affs/inode.c	Sun Jun 22 08:26:07 1997
@@ -691,7 +691,6 @@
 	inode->u.affs_i.i_pa_next      = 0;
 	inode->u.affs_i.i_pa_last      = 0;
 	inode->u.affs_i.i_ec           = NULL;
-	inode->u.affs_i.i_cache_users  = 0;
 	inode->u.affs_i.i_lastblock    = -1;
 	inode->i_nlink                 = 1;
 	inode->i_mode                  = 0;
@@ -870,6 +869,12 @@
 affs_put_inode(struct inode *inode)
 {
 	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
+	lock_super(inode->i_sb);
+	if (inode->u.affs_i.i_ec) {
+		free_page((unsigned long)inode->u.affs_i.i_ec);
+		inode->u.affs_i.i_ec = NULL;
+	}
+	unlock_super(inode->i_sb);
 	if (inode->i_nlink) {
 		return;
 	}
@@ -921,7 +926,6 @@
 	inode->u.affs_i.i_pa_next      = 0;
 	inode->u.affs_i.i_pa_last      = 0;
 	inode->u.affs_i.i_ec           = NULL;
-	inode->u.affs_i.i_cache_users  = 0;
 	inode->u.affs_i.i_lastblock    = -1;
 
 	insert_inode_hash(inode);
diff -urN linux-o/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- linux-o/include/linux/affs_fs_i.h	Sun Jun 22 14:37:14 1997
+++ linux/include/linux/affs_fs_i.h	Sun Jun 22 08:40:02 1997
@@ -34,7 +34,6 @@
 	s32	 i_original;			/* if != 0, this is the key of the original */
 	s32	 i_data[AFFS_MAX_PREALLOC];	/* preallocated blocks */
 	struct ext_cache *i_ec;			/* Cache gets allocated dynamically */
-	int	 i_cache_users;			/* Cache cannot be freed while > 0 */
 	int	 i_lastblock;			/* last allocated block */
 	short	 i_pa_cnt;			/* number of preallocated blocks */
 	short	 i_pa_next;			/* Index of next block in i_data[] */
