(16K) [patch-2.3.42] BFS write support

From: Tigran Aivazian (tigran@aivazian.fsnet.co.uk)
Date: Sat Feb 05 2000 - 05:19:03 EST


Hi Linus,

Please consider this patch. It does:

  a) lots of cleanup in BFS filesystem

  b) finishes the bfs_get_block() routine to provide write support

The only thing left to do is compactification, i.e. at the moment
filesystem will get very fragmented very soon.

Regards,
Tigran.

Sorry, I have to include the patch instead of the URL because my website
is down at the moment.

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 Sat Feb 5 10:05:31 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,103 @@
         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);
+ if (!buffer_uptodate(new))
+ wait_on_buffer(new);
+ 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(i && 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;
+ 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;
+ }
+
+ 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 */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Feb 07 2000 - 21:00:12 EST