summaryrefslogtreecommitdiffstats
path: root/fs/bfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
commitf969d69ba9f952e5bdd38278e25e26a3e4a61a70 (patch)
treeb3530d803df59d726afaabebc6626987dee1ca05 /fs/bfs
parenta10ce7ef2066b455d69187643ddf2073bfc4db24 (diff)
Merge with 2.3.27.
Diffstat (limited to 'fs/bfs')
-rw-r--r--fs/bfs/.cvsignore2
-rw-r--r--fs/bfs/Makefile14
-rw-r--r--fs/bfs/bfs_defs.h15
-rw-r--r--fs/bfs/dir.c382
-rw-r--r--fs/bfs/file.c76
-rw-r--r--fs/bfs/inode.c389
6 files changed, 878 insertions, 0 deletions
diff --git a/fs/bfs/.cvsignore b/fs/bfs/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/bfs/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/bfs/Makefile b/fs/bfs/Makefile
new file mode 100644
index 000000000..0aeda0cca
--- /dev/null
+++ b/fs/bfs/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for BFS filesystem.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main Makefile...
+
+O_TARGET := bfs.o
+O_OBJS := inode.o file.o dir.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/bfs/bfs_defs.h b/fs/bfs/bfs_defs.h
new file mode 100644
index 000000000..54d7dad29
--- /dev/null
+++ b/fs/bfs/bfs_defs.h
@@ -0,0 +1,15 @@
+#define su_lasti u.bfs_sb.si_lasti
+#define su_blocks u.bfs_sb.si_blocks
+#define su_freeb u.bfs_sb.si_freeb
+#define su_freei u.bfs_sb.si_freei
+#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
+
+#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
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
new file mode 100644
index 000000000..8aa200451
--- /dev/null
+++ b/fs/bfs/dir.c
@@ -0,0 +1,382 @@
+/*
+ * fs/bfs/dir.c
+ * BFS directory operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bfs_fs.h>
+#include <linux/locks.h>
+
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir);
+
+static ssize_t bfs_dir_read(struct file * f, char * buf, size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
+{
+ struct inode * dir = f->f_dentry->d_inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ kdev_t dev = dir->i_dev;
+ unsigned int offset;
+ 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);
+ 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);
+ return -EBADF;
+ }
+
+ while (f->f_pos < dir->i_size) {
+ offset = f->f_pos & (BFS_BSIZE-1);
+ block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ f->f_pos += BFS_BSIZE - offset;
+ continue;
+ }
+ do {
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ if (de->ino) {
+ int size = strnlen(de->name, BFS_NAMELEN);
+ if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) {
+ brelse(bh);
+ return 0;
+ }
+ }
+ offset += BFS_DIRENT_SIZE;
+ f->f_pos += BFS_DIRENT_SIZE;
+ } while (offset < BFS_BSIZE && f->f_pos < dir->i_size);
+ brelse(bh);
+ }
+
+ UPDATE_ATIME(dir);
+ return 0;
+}
+
+static struct file_operations bfs_dir_operations = {
+ llseek: NULL,
+ read: bfs_dir_read,
+ write: NULL,
+ readdir: bfs_readdir,
+ poll: NULL,
+ ioctl: NULL,
+ mmap: NULL,
+ open: NULL,
+ flush: NULL,
+ release: NULL,
+ fsync: file_fsync,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+extern void dump_imap(const char *, struct super_block *);
+
+static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
+{
+ int err;
+ struct inode * inode;
+ struct super_block * s = dir->i_sb;
+ unsigned long ino;
+
+ inode = get_empty_inode();
+ if (!inode)
+ return -ENOSPC;
+ inode->i_sb = s;
+ ino = find_first_zero_bit(s->su_imap, s->su_lasti);
+ if (ino > s->su_lasti) {
+ iput(inode);
+ return -ENOSPC;
+ }
+ set_bit(ino, s->su_imap);
+ s->su_freei--;
+ inode->i_dev = s->s_dev;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = inode->i_blksize = 0;
+ inode->i_op = &bfs_file_inops;
+ inode->i_mode = mode;
+ inode->i_ino = inode->iu_dsk_ino = ino;
+ inode->iu_sblock = inode->iu_eblock = 0;
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+ dump_imap("create",s);
+
+ err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
+ if (err) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ return err;
+ }
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct inode * inode = NULL;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ if (dentry->d_name.len > BFS_NAMELEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->ino);
+ brelse(bh);
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new)
+{
+ struct inode * inode = old->d_inode;
+ int err;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino);
+ if (err)
+ return err;
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ inode->i_count++;
+ d_instantiate(new, inode);
+ return 0;
+}
+
+
+static int bfs_unlink(struct inode * dir, struct dentry * dentry)
+{
+ int error = -ENOENT;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ inode = dentry->d_inode;
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!bh || de->ino != inode->i_ino)
+ 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);
+ inode->i_nlink = 1;
+ }
+ de->ino = 0;
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+ mark_inode_dirty(inode);
+ d_delete(dentry);
+ error = 0;
+
+out_brelse:
+ brelse(bh);
+ return error;
+}
+
+static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh;
+ struct bfs_dirent * old_de, * new_de;
+ int error = -ENOENT;
+
+ old_bh = new_bh = NULL;
+ old_inode = old_dentry->d_inode;
+ if (S_ISDIR(old_inode->i_mode))
+ return -EINVAL;
+
+ old_bh = bfs_find_entry(old_dir,
+ old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de);
+
+ if (!old_bh || old_de->ino != old_inode->i_ino)
+ goto end_rename;
+
+ error = -EPERM;
+ new_inode = new_dentry->d_inode;
+ new_bh = bfs_find_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de);
+
+ if (new_bh && !new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ if (!new_bh) {
+ error = bfs_add_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, old_inode->i_ino);
+ if (error)
+ goto end_rename;
+ }
+ old_de->ino = 0;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_version = ++event;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
+ mark_buffer_dirty(old_bh, 1);
+ error = 0;
+
+end_rename:
+ brelse(old_bh);
+ brelse(new_bh);
+ return error;
+}
+
+struct inode_operations bfs_dir_inops = {
+ default_file_ops: &bfs_dir_operations,
+ create: bfs_create,
+ lookup: bfs_lookup,
+ link: bfs_link,
+ unlink: bfs_unlink,
+ symlink: NULL,
+ mkdir: NULL,
+ rmdir: NULL,
+ mknod: NULL,
+ rename: bfs_rename,
+ readlink: NULL,
+ follow_link: NULL,
+ get_block: NULL,
+ readpage: NULL,
+ writepage: NULL,
+ flushpage: NULL,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
+{
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ int block, sblock, eblock, off;
+ kdev_t dev;
+ int i;
+
+ DBG(KERN_ERR "BFS-fs: %s(%s,%d)\n", __FUNCTION__, name, namelen);
+
+ if (!namelen)
+ return -ENOENT;
+ if (namelen > BFS_NAMELEN)
+ return -ENAMETOOLONG;
+
+ dev = dir->i_dev;
+ sblock = dir->iu_sblock;
+ eblock = dir->iu_eblock;
+ for (block=sblock; block<=eblock; block++) {
+ bh = bread(dev, block, BFS_BSIZE);
+ if(!bh)
+ return -ENOSPC;
+ for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
+ de = (struct bfs_dirent *)(bh->b_data + off);
+ if (!de->ino) {
+ if ((block-sblock)*BFS_BSIZE + off >= dir->i_size) {
+ dir->i_size += BFS_DIRENT_SIZE;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ de->ino = ino;
+ for (i=0; i<BFS_NAMELEN; i++)
+ de->name[i] = (i < namelen) ? name[i] : 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return 0;
+ }
+ }
+ brelse(bh);
+ }
+ return -ENOSPC;
+}
+
+static inline int bfs_namecmp(int len, const char * name, const char * buffer)
+{
+ if (len < BFS_NAMELEN && buffer[len])
+ return 0;
+ return !memcmp(name, buffer, len);
+}
+
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir)
+{
+ unsigned long block, offset;
+ struct buffer_head * bh;
+ struct bfs_sb_info * info;
+ struct bfs_dirent * de;
+
+ *res_dir = NULL;
+ info = &dir->i_sb->u.bfs_sb;
+ if (namelen > BFS_NAMELEN)
+ return NULL;
+ bh = NULL;
+ block = offset = 0;
+ while (block * BFS_BSIZE + offset < dir->i_size) {
+ if (!bh) {
+ bh = bread(dir->i_dev, dir->iu_sblock + block, BFS_BSIZE);
+ if (!bh) {
+ block++;
+ continue;
+ }
+ }
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ offset += BFS_DIRENT_SIZE;
+ if (de->ino && bfs_namecmp(namelen, name, de->name)) {
+ *res_dir = de;
+ return bh;
+ }
+ if (offset < bh->b_size)
+ continue;
+ brelse(bh);
+ bh = NULL;
+ offset = 0;
+ block++;
+ }
+ brelse(bh);
+ return NULL;
+}
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
new file mode 100644
index 000000000..4bc1ed99a
--- /dev/null
+++ b/fs/bfs/file.c
@@ -0,0 +1,76 @@
+/*
+ * fs/bfs/file.c
+ * BFS file operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/fs.h>
+#include <linux/bfs_fs.h>
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static ssize_t bfs_file_write(struct file * f, const char * buf, size_t count, loff_t *ppos)
+{
+ return generic_file_write(f, buf, count, ppos, block_write_partial_page);
+}
+
+static struct file_operations bfs_file_operations = {
+ llseek: NULL,
+ read: generic_file_read,
+ write: bfs_file_write,
+ readdir: NULL,
+ poll: NULL,
+ ioctl: NULL,
+ mmap: generic_file_mmap,
+ open: NULL,
+ flush: NULL,
+ release: NULL,
+ fsync: NULL,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+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) {
+ 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;
+}
+
+struct inode_operations bfs_file_inops = {
+ default_file_ops: &bfs_file_operations,
+ create: NULL,
+ lookup: NULL,
+ link: NULL,
+ unlink: NULL,
+ symlink: NULL,
+ mkdir: NULL,
+ rmdir: NULL,
+ mknod: NULL,
+ rename: NULL,
+ readlink: NULL,
+ follow_link: NULL,
+ get_block: bfs_get_block,
+ readpage: block_read_full_page,
+ writepage: block_write_full_page,
+ flushpage: block_flushpage,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
new file mode 100644
index 000000000..c0ee15dc4
--- /dev/null
+++ b/fs/bfs/inode.c
@@ -0,0 +1,389 @@
+/*
+ * fs/bfs/inode.c
+ * BFS superblock and inode operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ * 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>
+#include <linux/init.h>
+#include <linux/locks.h>
+#include <linux/bfs_fs.h>
+
+#include <asm/uaccess.h>
+
+#include "bfs_defs.h"
+
+MODULE_AUTHOR("Tigran A. Aivazian");
+MODULE_DESCRIPTION("UnixWare BFS filesystem for Linux");
+EXPORT_NO_SYMBOLS;
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void dump_imap(const char *prefix, struct super_block * s);
+
+static void bfs_read_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ 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);
+ make_bad_inode(inode);
+ 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);
+ make_bad_inode(inode);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ inode->i_mode = 0x0000FFFF & di->i_mode;
+ if (di->i_vtype == BFS_VDIR) {
+ inode->i_mode |= S_IFDIR;
+ inode->i_op = &bfs_dir_inops;
+ } else if (di->i_vtype == BFS_VREG) {
+ inode->i_mode |= S_IFREG;
+ inode->i_op = &bfs_file_inops;
+ } else
+ inode->i_op = NULL;
+
+ inode->i_uid = di->i_uid;
+ inode->i_gid = di->i_gid;
+ inode->i_nlink = di->i_nlink;
+ inode->i_size = BFS_FILESIZE(di);
+ inode->i_blocks = BFS_FILEBLOCKS(di);
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_atime = di->i_atime;
+ inode->i_mtime = di->i_mtime;
+ inode->i_ctime = di->i_ctime;
+ inode->i_rdev = 0; /* BFS doesn't have special nodes */
+ inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
+ inode->iu_sblock = di->i_sblock;
+ inode->iu_eblock = di->i_eblock;
+
+ brelse(bh);
+}
+
+static void bfs_write_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ 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);
+ 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);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ if (inode->i_ino == BFS_ROOT_INO)
+ di->i_vtype = BFS_VDIR;
+ else
+ di->i_vtype = BFS_VREG;
+
+ di->i_ino = inode->i_ino;
+ di->i_mode = inode->i_mode;
+ di->i_uid = inode->i_uid;
+ di->i_gid = inode->i_gid;
+ di->i_nlink = inode->i_nlink;
+ di->i_atime = inode->i_atime;
+ di->i_mtime = inode->i_mtime;
+ di->i_ctime = inode->i_ctime;
+ di->i_sblock = inode->iu_sblock;
+ di->i_eblock = inode->iu_eblock;
+ di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
+
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+}
+
+static void bfs_delete_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ int block, off;
+ struct super_block * s = inode->i_sb;
+
+ DBG(KERN_ERR "%s(ino=%08lx)\n", __FUNCTION__, inode->i_ino);
+
+ if (!inode)
+ 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);
+ return;
+ }
+
+ inode->i_size = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ 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);
+ return;
+ }
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+ if (di->i_ino) {
+ s->su_freeb += BFS_FILEBLOCKS(di);
+ s->su_freei++;
+ clear_bit(di->i_ino, s->su_imap);
+ dump_imap("delete_inode", s);
+ }
+ di->i_ino = 0;
+ di->i_sblock = 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ clear_inode(inode);
+}
+
+static void bfs_put_super(struct super_block *s)
+{
+ brelse(s->su_sbh);
+ kfree(s->su_imap);
+ kfree(s->su_bmap);
+ MOD_DEC_USE_COUNT;
+}
+
+static int bfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = BFS_MAGIC;
+ tmp.f_bsize = s->s_blocksize;
+ tmp.f_blocks = s->su_blocks;
+ tmp.f_bfree = tmp.f_bavail = s->su_freeb;
+ tmp.f_files = s->su_lasti + 1 - BFS_ROOT_INO;
+ tmp.f_ffree = s->su_freei;
+ tmp.f_fsid.val[0] = s->s_dev;
+ tmp.f_namelen = BFS_NAMELEN;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void bfs_write_super(struct super_block *s)
+{
+ if (!(s->s_flags & MS_RDONLY))
+ mark_buffer_dirty(s->su_sbh, 1);
+ s->s_dirt = 0;
+}
+
+static struct super_operations bfs_sops = {
+ read_inode: bfs_read_inode,
+ write_inode: bfs_write_inode,
+ put_inode: NULL,
+ delete_inode: bfs_delete_inode,
+ notify_change: NULL,
+ put_super: bfs_put_super,
+ write_super: bfs_write_super,
+ statfs: bfs_statfs,
+ remount_fs: NULL,
+ clear_inode: NULL,
+ umount_begin: NULL
+};
+
+void dump_imap(const char *prefix, struct super_block * s)
+{
+#if 0
+ int i;
+ char *tmpbuf = (char *)get_free_page(GFP_KERNEL);
+
+ if (!tmpbuf)
+ return;
+ for (i=s->su_lasti; i>=0; i--) {
+ if (i>PAGE_SIZE-100) break;
+ if (test_bit(i, s->su_imap))
+ strcat(tmpbuf, "1");
+ else
+ strcat(tmpbuf, "0");
+ }
+ printk(KERN_ERR "BFS-fs: %s: lasti=%d <%s>\n", prefix, s->su_lasti, tmpbuf);
+ free_page((unsigned long)tmpbuf);
+#endif
+}
+
+static struct super_block * bfs_read_super(struct super_block * s,
+ void * data, int silent)
+{
+ kdev_t dev;
+ struct buffer_head * bh;
+ struct bfs_super_block * bfs_sb;
+ struct inode * inode;
+ int i, imap_len, bmap_len;
+
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+ dev = s->s_dev;
+ set_blocksize(dev, BFS_BSIZE);
+ 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);
+ 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);
+ goto out;
+ }
+ if (BFS_UNCLEAN(bfs_sb, s) && !silent)
+ printk(KERN_WARNING "BFS-fs: %s is unclean\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);
+ 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;
+ 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;
+ }
+
+ s->su_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */
+ s->su_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS;
+ s->su_freei = 0;
+ s->su_lf_eblk = 0;
+ s->su_lf_sblk = 0;
+ 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) {
+ s->su_freei++;
+ s->su_bmap[i].start = s->su_bmap[i].end = 0;
+ } else {
+ set_bit(i, s->su_imap);
+ s->su_freeb -= inode->i_blocks;
+ if (inode->iu_eblock > s->su_lf_eblk) {
+ s->su_lf_eblk = inode->iu_eblock;
+ 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);
+ }
+ if (!(s->s_flags & MS_RDONLY)) {
+ mark_buffer_dirty(bh, 1);
+ s->s_dirt = 1;
+ }
+ dump_imap("read_super", s);
+ unlock_super(s);
+ return s;
+
+out:
+ brelse(bh);
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static struct file_system_type bfs_fs_type = {
+ name: "bfs",
+ fs_flags: FS_REQUIRES_DEV,
+ read_super: bfs_read_super,
+ next: NULL
+};
+
+#ifdef MODULE
+#define init_bfs_fs init_module
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&bfs_fs_type);
+}
+#endif
+
+int __init init_bfs_fs(void)
+{
+ return register_filesystem(&bfs_fs_type);
+}