Resent-Date: Mon, 13 Sep 1999 18:36:37 +0200 (MET DST)
Date: Mon, 13 Sep 1999 18:35:55 +0200 (MET DST)
From: Roman Zippel <zippel@fh-brandenburg.de>
X-Sender: zippel@zeus
To: Linux/m68k <linux-m68k@lists.linux-m68k.org>
Subject: first (unstable) affs patch
Resent-From: linux-m68k@phil.uni-sb.de

Hi,

Unfortunately I hadn't much time over the weekend to work on this, so
maybe someone else wants to look into this. It's still crashes at umount,
because of an ownerless buffer, some prints might help to find where it's
coming from. The old fs part is still untested.
Usual disclaimer: this is not an official release, use it at your own
risk, I'm not responsible if it formats your disks - I warned you.

bye, Roman

Index: fs/affs/file.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.3/fs/affs/file.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 file.c
--- file.c	1999/07/02 20:47:10	1.1.1.3
+++ file.c	1999/09/12 11:31:35
@@ -12,7 +12,7 @@
  *  affs regular file handling primitives
  */
 
-#define DEBUG 0
+#define DEBUG 1
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/sched.h>
@@ -37,7 +37,9 @@
 #endif
 
 static int affs_bmap(struct inode *inode, int block);
-static struct buffer_head *affs_getblock(struct inode *inode, s32 block);
+static int affs_get_block(struct inode *inode, long block,
+			  struct buffer_head *bh_result, int create);
+struct buffer_head *affs_getblk(struct inode *inode, s32 block);
 static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);
 static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
 static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);
@@ -74,10 +76,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	affs_bmap,		/* get_block */
+	affs_get_block,		/* get_block */
 	block_read_full_page,	/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,	/* flushpage */
 	affs_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
@@ -357,9 +359,9 @@
  * next ones, so you have to fix [n-1] after allocating [n].
  * What a mess.
  */
-
-static struct buffer_head *
-affs_getblock(struct inode *inode, s32 block)
+static int
+affs_get_block(struct inode *inode, long block,
+	       struct buffer_head *bh_result, int create)
 {
 	struct super_block	*sb = inode->i_sb;
 	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;
@@ -370,12 +372,25 @@
 	int			 cf, j, pt;
 	int			 index;
 	int			 err;
+
+	pr_debug("AFFS: getblock(%lu,%ld,%d)\n",inode->i_ino,block,create);
 
-	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+	if (!create) {
+		key = affs_bmap(inode, block);
+		if (key) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = key;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
+		return 0;
+	}
 
 	if (block < 0)
 		goto out_fail;
 
+	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
+		return -ENOMEM;
+
 	key    = calc_key(inode,&ext);
 	block -= ext * AFFS_I2HSIZE(inode);
 	pt     = ext ? T_LIST : T_SHORT;
@@ -409,7 +424,7 @@
 							be32_to_cpu(k),
 							AFFS_I2BSIZE(inode));
 				} else
-					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
+					pbh = affs_getblk(inode,inode->u.affs_i.i_lastblock);
 				if (!pbh) {
 					affs_error(sb,"getblock",
 						"Cannot get last block in file");
@@ -516,14 +531,38 @@
 	if (!key)
 		goto out_fail;
 
-	bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
-	return bh;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = key;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	return 0;
 
 out_free_block:
 	affs_free_block(sb, key);
 out_free_bh:
 	affs_brelse(bh);
 out_fail:
+	return -EIO;
+}
+
+struct buffer_head *
+affs_getblk(struct inode *inode, s32 block)
+{
+	struct buffer_head dummy;
+	int error;
+
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = affs_get_block(inode, block, &dummy, 1);
+	if (!error && buffer_mapped(&dummy)) {
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, AFFS_I2BSIZE(inode));
+		if (buffer_new(&dummy)) {
+			memset(bh->b_data, 0, AFFS_I2BSIZE(inode));
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
+		}
+		return bh;
+	}
 	return NULL;
 }
 
@@ -576,123 +615,42 @@
 	return buf - start;
 }
 
+/*
+ * Write to a file (through the page cache).
+ */
 static ssize_t
 affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
 {
-	struct inode		*inode = filp->f_dentry->d_inode;
-	off_t			 pos;
-	ssize_t			 written;
-	ssize_t			 c;
-	ssize_t			 blocksize;
-	struct buffer_head	*bh;
-	char			*p;
-
-	if (!count)
-		return 0;
-	pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
-		 (unsigned long)*ppos,count);
-
-	if (!inode) {
-		affs_error(inode->i_sb,"file_write","Inode = NULL");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		affs_error(inode->i_sb,"file_write",
-			   "Trying to write to non-regular file (mode=%07o)",
-			   inode->i_mode);
-		return -EINVAL;
-	}
-	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
-		return -ENOMEM;
-	if (filp->f_flags & O_APPEND)
-		pos = inode->i_size;
-	else
-		pos = *ppos;
-	written   = 0;
-	blocksize = AFFS_I2BSIZE(inode);
-
-	while (written < count) {
-		bh = affs_getblock(inode,pos / blocksize);
-		if (!bh) {
-			if (!written)
-				written = -ENOSPC;
-			break;
-		}
-		c = blocksize - (pos % blocksize);
-		if (c > count - written)
-			c = count - written;
-		if (c != blocksize && !buffer_uptodate(bh)) {
-			ll_rw_block(READ,1,&bh);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh)) {
-				affs_brelse(bh);
-				if (!written)
-					written = -EIO;
-				break;
-			}
-		}
-		p  = (pos % blocksize) + bh->b_data;
-		c -= copy_from_user(p,buf,c);
-		if (!c) {
-			affs_brelse(bh);
-			if (!written)
-				written = -EFAULT;
-			break;
-		}
-		update_vm_cache(inode,pos,p,c);
-		mark_buffer_uptodate(bh,1);
-		mark_buffer_dirty(bh,0);
-		affs_brelse(bh);
-		pos     += c;
-		written += c;
-		buf     += c;
-	}
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	*ppos          = pos;
-	mark_inode_dirty(inode);
-	return written;
+	return generic_file_write(filp, buf, count,
+				  ppos, block_write_partial_page);
 }
 
-static ssize_t
-affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+static int
+affs_writepage_ofs(struct file *file, struct page *page, unsigned long offset,
+		   unsigned long count, const char * buf)
 {
-	struct inode		*inode = filp->f_dentry->d_inode;
+	struct dentry		*dentry = file->f_dentry;
+	struct inode		*inode = dentry->d_inode;
 	off_t			 pos;
 	ssize_t			 written;
 	ssize_t			 c;
 	ssize_t			 blocksize;
 	struct buffer_head	*bh;
 	char			*p;
+	char			*target_buf;
 
-	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
-		(unsigned long)*ppos,count);
+	pos = page->offset + offset;
+	target_buf = (char *)page_address(page) + offset;
 
-	if (!count)
-		return 0;
-	if (!inode) {
-		affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		affs_error(inode->i_sb,"file_write_ofs",
-			   "Trying to write to non-regular file (mode=%07o)",
-			   inode->i_mode);
-		return -EINVAL;
-	}
-	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
-		return -ENOMEM;
-	if (filp->f_flags & O_APPEND)
-		pos = inode->i_size;
-	else
-		pos = *ppos;
+	if (!PageLocked(page))
+		BUG();
+	get_page(page);
 
-	bh        = NULL;
 	blocksize = AFFS_I2BSIZE(inode) - 24;
 	written   = 0;
+
 	while (written < count) {
-		bh = affs_getblock(inode,pos / blocksize);
+		bh = affs_getblk(inode,pos / blocksize);
 		if (!bh) {
 			if (!written)
 				written = -ENOSPC;
@@ -712,32 +670,35 @@
 			}
 		}
 		p  = (pos % blocksize) + bh->b_data + 24;
-		c -= copy_from_user(p,buf,c);
-		if (!c) {
+		if (copy_from_user(p, buf, c)) {
 			affs_brelse(bh);
-			if (!written)
-				written = -EFAULT;
+			written = -EFAULT;
 			break;
 		}
-		update_vm_cache(inode,pos,p,c);
+		memcpy(target_buf, p, c);
 
 		pos     += c;
 		buf     += c;
 		written += c;
+		target_buf += c;
+
 		DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c);
 		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
 		mark_buffer_uptodate(bh,1);
 		mark_buffer_dirty(bh,0);
 		affs_brelse(bh);
 	}
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-	*ppos = pos;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
+
 	return written;
 }
 
+static ssize_t
+affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+{
+	return generic_file_write(filp, buf, count,
+				  ppos, affs_writepage_ofs);
+}
+
 /* Free any preallocated blocks. */
 
 void
@@ -790,7 +751,7 @@
 			/* XXX Fine! No way to indicate an error. */
 			return /* -ENOSPC */;
 		}
-		bh = affs_getblock(inode,first - 1);
+		bh = affs_getblk(inode,first - 1);
 		if (!bh) {
 			affs_warning(inode->i_sb,"truncate","Cannot extend file");
 			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
@@ -875,7 +836,7 @@
 		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
 			rem += 24;
 		pr_debug("AFFS: Zeroing from offset %d in block %d\n",rem,block);
-		bh = affs_getblock(inode,block);
+		bh = affs_getblk(inode,block);
 		if (bh) {
 			memset(bh->b_data + rem,0,blocksize - rem);
 			if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) {


