diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-01-29 01:41:54 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-01-29 01:41:54 +0000 |
commit | f969d69ba9f952e5bdd38278e25e26a3e4a61a70 (patch) | |
tree | b3530d803df59d726afaabebc6626987dee1ca05 /fs/bfs | |
parent | a10ce7ef2066b455d69187643ddf2073bfc4db24 (diff) |
Merge with 2.3.27.
Diffstat (limited to 'fs/bfs')
-rw-r--r-- | fs/bfs/.cvsignore | 2 | ||||
-rw-r--r-- | fs/bfs/Makefile | 14 | ||||
-rw-r--r-- | fs/bfs/bfs_defs.h | 15 | ||||
-rw-r--r-- | fs/bfs/dir.c | 382 | ||||
-rw-r--r-- | fs/bfs/file.c | 76 | ||||
-rw-r--r-- | fs/bfs/inode.c | 389 |
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); +} |