diff -urN -X dontdiff linux/Documentation/filesystems/bfs.txt linux-bfs/Documentation/filesystems/bfs.txt
--- linux/Documentation/filesystems/bfs.txt	Fri Nov  5 18:30:13 1999
+++ linux-bfs/Documentation/filesystems/bfs.txt	Sat Feb  5 09:06:53 2000
@@ -1,13 +1,9 @@
-The BFS filesystem is used on SCO UnixWare machines for /stand slice.
-By default, if you attempt to mount it read-write it will be automatically
-mounted read-only. If you want to enable (limited) write support, you need
-to select "BFS write support" when configuring the kernel. The write support
-at this stage is limited to the blocks preallocated for a given inode.
-This means that writes beyond the value of inode->iu_eblock will fail with EIO.
-In particular, this means you can create empty files but not write data to them
-or you can write data to the existing files and increase their size but not the
-number of blocks allocated to them. I am currently working on removing this
-limitation, i.e. ability to migrate inodes within BFS filesystem.
+BFS FILESYSTEM FOR LINUX
+========================
+
+The BFS filesystem is used by SCO UnixWare OS for the /stand slice, which
+usually contains the kernel image and a few other files required for the
+boot process.
 
 In order to access /stand partition under Linux you obviously need to
 know the partition number and the kernel must support UnixWare disk slices
@@ -29,7 +25,9 @@
 # mount -t bfs -o loop stand.img /mnt/stand
 
 this will allocate the first available loopback device (and load loop.o 
-kernel module if necessary) automatically. Beware that umount will not
+kernel module if necessary) automatically. If the loopback driver is not
+loaded automatically, make sure that your kernel is compiled with kmod 
+support (CONFIG_KMOD) enabled. Beware that umount will not
 deallocate /dev/loopN device if /etc/mtab file on your system is a
 symbolic link to /proc/mounts. You will need to do it manually using
 "-d" switch of losetup(8). Read losetup(8) manpage for more info.
@@ -51,9 +49,9 @@
 
 # od -Ad -tx4 stand.img | more
 
-The first 4 bytes should be 0x1BADFACE.
+The first 4 bytes should be 0x1badface.
 
-If you have any questions or suggestions regarding this BFS implementation
-please contact me:
+If you have any patches, questions or suggestions regarding this BFS
+implementation please contact the author:
 
 Tigran A. Aivazian <tigran@ocston.org>.
diff -urN -X dontdiff linux/fs/Config.in linux-bfs/fs/Config.in
--- linux/fs/Config.in	Sat Jan 29 12:11:53 2000
+++ linux-bfs/fs/Config.in	Sat Feb  5 09:58:12 2000
@@ -15,8 +15,7 @@
 
 dep_tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
-dep_tristate 'BFS filesystem (read only) support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
-dep_bool '  BFS filesystem write support (DANGEROUS)' CONFIG_BFS_FS_WRITE $CONFIG_BFS_FS
+dep_tristate 'BFS filesystem support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
 
 # msdos filesystems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
diff -urN -X dontdiff linux/fs/bfs/bfs_defs.h linux-bfs/fs/bfs/bfs_defs.h
--- linux/fs/bfs/bfs_defs.h	Fri Nov  5 18:30:13 1999
+++ linux-bfs/fs/bfs/bfs_defs.h	Sat Feb  5 09:09:20 2000
@@ -5,7 +5,6 @@
 #define su_lf_ioff	u.bfs_sb.si_lf_ioff
 #define su_lf_sblk	u.bfs_sb.si_lf_sblk
 #define su_lf_eblk	u.bfs_sb.si_lf_eblk
-#define su_bmap		u.bfs_sb.si_bmap
 #define su_imap		u.bfs_sb.si_imap
 #define su_sbh		u.bfs_sb.si_sbh
 #define su_bfs_sb	u.bfs_sb.si_bfs_sb
@@ -13,3 +12,6 @@
 #define iu_dsk_ino	u.bfs_i.i_dsk_ino
 #define iu_sblock	u.bfs_i.i_sblock
 #define iu_eblock	u.bfs_i.i_eblock
+
+#define printf(format, args...) \
+	printk(KERN_ERR "BFS-fs: " __FUNCTION__ "(): " format, ## args)
diff -urN -X dontdiff linux/fs/bfs/dir.c linux-bfs/fs/bfs/dir.c
--- linux/fs/bfs/dir.c	Thu Jan 13 21:21:07 2000
+++ linux-bfs/fs/bfs/dir.c	Sat Feb  5 09:07:43 2000
@@ -14,9 +14,9 @@
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(x...)	printk(x)
+#define dprintf(x...)	printf(x)
 #else
-#define DBG(x...)
+#define dprintf(x...)
 #endif
 
 static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
@@ -38,14 +38,13 @@
 	int block;
 
 	if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_ERR "BFS-fs: %s(): Bad inode or not a directory %s:%08lx\n",
-			__FUNCTION__, bdevname(dev), dir->i_ino);
+		printf("Bad inode or not a directory %s:%08lx\n", bdevname(dev), dir->i_ino);
 		return -EBADF;
 	}
 
 	if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
-		printk(KERN_ERR "BFS-fs: %s(): Bad f_pos=%08lx for %s:%08lx\n", 
-			__FUNCTION__, (unsigned long)f->f_pos, bdevname(dev), dir->i_ino);
+		printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos, 
+			bdevname(dev), dir->i_ino);
 		return -EBADF;
 	}
 
@@ -189,9 +188,8 @@
 		goto out_brelse;
 
 	if (!inode->i_nlink) {
-		printk(KERN_WARNING 
-		"BFS-fs: %s(): unlinking non-existent file %s:%lu (nlink=%d)\n",
-		__FUNCTION__, bdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
+		printf("unlinking non-existent file %s:%lu (nlink=%d)\n", bdevname(inode->i_dev), 
+				inode->i_ino, inode->i_nlink);
 		inode->i_nlink = 1;
 	}
 	de->ino = 0;
@@ -294,7 +292,7 @@
 	kdev_t dev;
 	int i;
 
-	DBG(KERN_ERR "BFS-fs: %s(%s,%d)\n", __FUNCTION__, name, namelen);
+	dprintf("name=%s, namelen=%d\n", name, namelen);
 
 	if (!namelen)
 		return -ENOENT;
diff -urN -X dontdiff linux/fs/bfs/file.c linux-bfs/fs/bfs/file.c
--- linux/fs/bfs/file.c	Thu Jan 13 21:21:07 2000
+++ linux-bfs/fs/bfs/file.c	Mon Feb  7 19:18:16 2000
@@ -5,15 +5,17 @@
  */
 
 #include <linux/fs.h>
+#include <linux/locks.h>
 #include <linux/bfs_fs.h>
+#include <linux/smp_lock.h>
 #include "bfs_defs.h"
 
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(x...)	printk(x)
+#define dprintf(x...)	printf(x)
 #else
-#define DBG(x...)
+#define dprintf(x...)
 #endif
 
 static ssize_t bfs_file_write(struct file * f, const char * buf, size_t count, loff_t *ppos)
@@ -36,18 +38,104 @@
 	fasync:			NULL,
 };
 
+static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
+{
+	struct buffer_head *bh, *new = NULL;
+
+	bh = bread(dev, from, BFS_BSIZE);
+	if (!bh)
+		return -EIO;
+	new = getblk(dev, to, BFS_BSIZE);
+	memcpy(new->b_data, bh->b_data, bh->b_size);
+	mark_buffer_dirty(new, 1);
+	bforget(bh);
+	brelse(new);
+	return 0;
+}
+
+static int bfs_move_blocks(kdev_t dev, unsigned long start, unsigned long end, 
+				unsigned long where)
+{
+	unsigned long i;
+
+	dprintf("%08lx-%08lx->%08lx\n", start, end, where);
+	for (i = start; i <= end; i++)
+		if(bfs_move_block(i, where + i, dev)) {
+			dprintf("failed to move block %08lx -> %08lx\n", i, where + i);
+			return -EIO;
+		}
+	return 0;
+}
+
 static int bfs_get_block(struct inode * inode, long block, 
 	struct buffer_head * bh_result, int create)
 {
-	long phys = inode->iu_sblock + block;
-	if (!create || phys <= inode->iu_eblock) {
+	long phys, next_free_block;
+	int err;
+	struct super_block *s = inode->i_sb;
+
+	if (block < 0 || block > s->su_blocks)
+		return -EIO;
+
+	phys = inode->iu_sblock + block;
+	if (!create) {
+		if (phys <= inode->iu_eblock) {
+			dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
+		return 0;
+	}
+
+	/* if the file is not empty and the requested block is within the range
+	   of blocks allocated for this file, we can grant it */
+	if (inode->i_size && phys <= inode->iu_eblock) {
+		dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", create, block, phys);
 		bh_result->b_dev = inode->i_dev;
 		bh_result->b_blocknr = phys;
 		bh_result->b_state |= (1UL << BH_Mapped);
 		return 0;
-	} 
-	/* no support for file migration, working on it */
-	return -EIO;
+	}
+
+	/* the rest has to be protected against itself */
+	lock_kernel();
+
+	/* if the last data block for this file is the last allocated block, we can
+	   extend the file trivially, without moving it anywhere */
+	if (inode->iu_eblock == s->su_lf_eblk) {
+		dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", create, block, phys);
+		bh_result->b_dev = inode->i_dev;
+		bh_result->b_blocknr = phys;
+		bh_result->b_state |= (1UL << BH_Mapped);
+		s->su_lf_eblk = inode->iu_eblock = inode->iu_sblock + block;
+		mark_inode_dirty(inode);
+		mark_buffer_dirty(s->su_sbh, 1);
+		err = 0;
+		goto out;
+	}
+
+	/* Ok, we have to move this entire file to the next free block */
+	next_free_block = s->su_lf_eblk + 1;
+	if (inode->iu_sblock) {
+		err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, inode->iu_eblock, next_free_block);
+		if (err) {
+			dprintf("failed to move ino=%08lx -> possible fs corruption\n", inode->i_ino);
+			goto out;
+		}
+	} else
+		err = 0;
+
+	inode->iu_sblock = next_free_block;
+	s->su_lf_eblk = inode->iu_eblock = next_free_block + block;
+	mark_inode_dirty(inode);
+	mark_buffer_dirty(s->su_sbh, 1);
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = inode->iu_sblock + block;
+	bh_result->b_state |= (1UL << BH_Mapped);
+out:
+	unlock_kernel();
+	return err;
 }
 
 struct inode_operations bfs_file_inops = {
diff -urN -X dontdiff linux/fs/bfs/inode.c linux-bfs/fs/bfs/inode.c
--- linux/fs/bfs/inode.c	Tue Nov  9 18:02:33 1999
+++ linux-bfs/fs/bfs/inode.c	Sat Feb  5 09:32:52 2000
@@ -5,7 +5,6 @@
  *	From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
@@ -18,15 +17,15 @@
 #include "bfs_defs.h"
 
 MODULE_AUTHOR("Tigran A. Aivazian");
-MODULE_DESCRIPTION("UnixWare BFS filesystem for Linux");
+MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
 EXPORT_NO_SYMBOLS;
 
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(x...)	printk(x)
+#define dprintf(x...)	printf(x)
 #else
-#define DBG(x...)
+#define dprintf(x...)
 #endif
 
 void dump_imap(const char *prefix, struct super_block * s);
@@ -40,8 +39,7 @@
 	int block, off;
 
 	if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
-		printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n", 
-			__FUNCTION__, bdevname(dev), ino);
+		printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
 		make_bad_inode(inode);
 		return;
 	}
@@ -49,8 +47,7 @@
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = bread(dev, block, BFS_BSIZE);
 	if (!bh) {
-		printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
-			__FUNCTION__, bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		make_bad_inode(inode);
 		return;
 	}
@@ -94,16 +91,14 @@
 	int block, off;
 
 	if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
-		printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n", 
-			__FUNCTION__, bdevname(dev), ino);
+		printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
 		return;
 	}
 
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = bread(dev, block, BFS_BSIZE);
 	if (!bh) {
-		printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
-			__FUNCTION__, bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		return;
 	}
 
@@ -140,30 +135,12 @@
 	int block, off;
 	struct super_block * s = inode->i_sb;
 
-	DBG(KERN_ERR "%s(ino=%08lx)\n", __FUNCTION__, inode->i_ino);
+	dprintf("ino=%08lx\n", inode->i_ino);
 
-	if (!inode)
+	if (!inode || !inode->i_dev || inode->i_count > 1 || inode->i_nlink || !s)
 		return;
-	if (!inode->i_dev) {
-		printk(KERN_ERR "BFS-fs: free_inode(%08lx) !dev\n", inode->i_ino);
-		return;
-	}
-	if (inode->i_count > 1) {
-		printk(KERN_ERR "BFS-fs: free_inode(%08lx) count=%d\n", 
-			inode->i_ino, inode->i_count);
-		return;
-	}
-	if (inode->i_nlink) {
-		printk(KERN_ERR "BFS-fs: free_inode(%08lx) nlink=%d\n", 
-			inode->i_ino, inode->i_nlink);
-		return;
-	}
-	if (!inode->i_sb) {
-		printk(KERN_ERR "BFS-fs: free_inode(%08lx) !sb\n", inode->i_ino);
-		return;
-	}
 	if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > inode->i_sb->su_lasti) {
-		printk(KERN_ERR "BFS-fs: free_inode(%08lx) invalid ino\n", inode->i_ino);
+		printf("invalid ino=%08lx\n", inode->i_ino);
 		return;
 	}
 	
@@ -173,8 +150,7 @@
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = bread(dev, block, BFS_BSIZE);
 	if (!bh) {
-		printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
-			__FUNCTION__, bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		return;
 	}
 	off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
@@ -189,6 +165,14 @@
 	di->i_sblock = 0;
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
+
+	/* if this was the last file, make the previous 
+	   block "last files last block" even if there is no real file there,
+	   saves us 1 gap */
+	if (s->su_lf_eblk == inode->iu_eblock) {
+		s->su_lf_eblk = inode->iu_sblock - 1;
+		mark_buffer_dirty(s->su_sbh, 1);
+	}
 	clear_inode(inode);
 }
 
@@ -196,7 +180,6 @@
 {
 	brelse(s->su_sbh);
 	kfree(s->su_imap);
-	kfree(s->su_bmap);
 	MOD_DEC_USE_COUNT;
 }
 
@@ -251,7 +234,7 @@
 		else
 			strcat(tmpbuf, "0");
 	}
-	printk(KERN_ERR "BFS-fs: %s: lasti=%d <%s>\n", prefix, s->su_lasti, tmpbuf);
+	printk(KERN_ERR "BFS-fs: %s: lasti=%08lx <%s>\n", prefix, s->su_lasti, tmpbuf);
 	free_page((unsigned long)tmpbuf);
 #endif
 }
@@ -263,7 +246,7 @@
 	struct buffer_head * bh;
 	struct bfs_super_block * bfs_sb;
 	struct inode * inode;
-	int i, imap_len, bmap_len;
+	int i, imap_len;
 
 	MOD_INC_USE_COUNT;
 	lock_super(s);
@@ -272,58 +255,43 @@
 	s->s_blocksize = BFS_BSIZE;
 	s->s_blocksize_bits = BFS_BSIZE_BITS;
 
-	/* read ahead 8K to get inodes as we'll need them in a tick */
-	bh = breada(dev, 0, BFS_BSIZE, 0, 8192);
+	bh = bread(dev, 0, BFS_BSIZE);
 	if(!bh)
 		goto out;
 	bfs_sb = (struct bfs_super_block *)bh->b_data;
 	if (bfs_sb->s_magic != BFS_MAGIC) {
 		if (!silent)
-			printk(KERN_ERR "BFS-fs: No BFS filesystem on %s (magic=%08x)\n", 
-					bdevname(dev), bfs_sb->s_magic);
+			printf("No BFS filesystem on %s (magic=%08x)\n", 
+				bdevname(dev), bfs_sb->s_magic);
 		goto out;
 	}
 	if (BFS_UNCLEAN(bfs_sb, s) && !silent)
-		printk(KERN_WARNING "BFS-fs: %s is unclean\n", bdevname(dev));
+		printf("%s is unclean, continuing\n", bdevname(dev));
 
-#ifndef CONFIG_BFS_FS_WRITE
-	s->s_flags |= MS_RDONLY; 
-#endif
 	s->s_magic = BFS_MAGIC;
 	s->su_bfs_sb = bfs_sb;
 	s->su_sbh = bh;
 	s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode) 
 			+ BFS_ROOT_INO - 1;
 
-	bmap_len = sizeof(struct bfs_bmap) * s->su_lasti;
-	s->su_bmap = kmalloc(bmap_len, GFP_KERNEL);
-	if (!s->su_bmap)
-		goto out;
-	memset(s->su_bmap, 0, bmap_len);
 	imap_len = s->su_lasti/8 + 1;
 	s->su_imap = kmalloc(imap_len, GFP_KERNEL);
-	if (!s->su_imap) {
-		kfree(s->su_bmap);
+	if (!s->su_imap)
 		goto out;
-	}
 	memset(s->su_imap, 0, imap_len);
-	for (i=0; i<BFS_ROOT_INO; i++) {
-		s->su_bmap[i].start = s->su_bmap[i].end = 0;
+	for (i=0; i<BFS_ROOT_INO; i++) 
 		set_bit(i, s->su_imap);
-	}
 
 	s->s_op = &bfs_sops;
 	inode = iget(s, BFS_ROOT_INO);
 	if (!inode) {
 		kfree(s->su_imap);
-		kfree(s->su_bmap);
 		goto out;
 	}
 	s->s_root = d_alloc_root(inode);
 	if (!s->s_root) {
 		iput(inode);
 		kfree(s->su_imap);
-		kfree(s->su_bmap);
 		goto out;
 	}
 
@@ -335,10 +303,9 @@
 	s->su_lf_ioff = 0;
 	for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
 		inode = iget(s,i);
-		if (inode->iu_dsk_ino == 0) {
+		if (inode->iu_dsk_ino == 0)
 			s->su_freei++;
-			s->su_bmap[i].start = s->su_bmap[i].end = 0;
-		} else {
+		else {
 			set_bit(i, s->su_imap);
 			s->su_freeb -= inode->i_blocks;
 			if (inode->iu_eblock > s->su_lf_eblk) {
@@ -346,8 +313,6 @@
 				s->su_lf_sblk = inode->iu_sblock;
 				s->su_lf_ioff = BFS_INO2OFF(i);
 			}
-			s->su_bmap[i].start = inode->iu_sblock;
-			s->su_bmap[i].end = inode->iu_eblock;
 		}
 		iput(inode);
 	}
diff -urN -X dontdiff linux/include/linux/bfs_fs_sb.h linux-bfs/include/linux/bfs_fs_sb.h
--- linux/include/linux/bfs_fs_sb.h	Fri Nov  5 18:30:13 1999
+++ linux-bfs/include/linux/bfs_fs_sb.h	Sat Feb  5 09:09:10 2000
@@ -7,13 +7,6 @@
 #define _LINUX_BFS_FS_SB
 
 /*
- * BFS block map entry, an array of these is kept in bfs_sb_info.
- */
- struct bfs_bmap {
- 	unsigned long start, end;
- };
-
-/*
  * BFS file system in-core superblock info
  */
 struct bfs_sb_info {
@@ -24,7 +17,6 @@
 	unsigned long si_lf_sblk;
 	unsigned long si_lf_eblk;
 	unsigned long si_lasti;
-	struct bfs_bmap * si_bmap;
 	char * si_imap;
 	struct buffer_head * si_sbh;		/* buffer header w/superblock */
 	struct bfs_super_block * si_bfs_sb;	/* superblock in si_sbh->b_data */