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 */