summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMike Shaver <shaver@ingenia.com>1999-03-25 17:37:58 +0000
committerMike Shaver <shaver@ingenia.com>1999-03-25 17:37:58 +0000
commit76a6e3640c7212dacd5ce3c39161921d31a69800 (patch)
treec67f026bd5cba1d1dc9efaf240b0ee8b62e47f68 /fs
parentae9d38e9ea2cb7f28e757975537dabe5fb2f145d (diff)
Al Smith's new EFS code, which seems to work and things
Diffstat (limited to 'fs')
-rw-r--r--fs/efs/Makefile2
-rw-r--r--fs/efs/dir.c221
-rw-r--r--fs/efs/file.c200
-rw-r--r--fs/efs/inode.c549
-rw-r--r--fs/efs/namei.c153
-rw-r--r--fs/efs/symlink.c134
6 files changed, 515 insertions, 744 deletions
diff --git a/fs/efs/Makefile b/fs/efs/Makefile
index 1a0435ed3..af04e0324 100644
--- a/fs/efs/Makefile
+++ b/fs/efs/Makefile
@@ -7,8 +7,6 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-EXTRA_CFLAGS +=-g -DDEBUG_EFS
-
O_TARGET := efs.o
O_OBJS := dir.o file.o inode.o namei.o \
symlink.o
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index a31f6784a..483efd85a 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -1,146 +1,119 @@
/*
- * linux/fs/efs/dir.c
+ * dir.c
*
- * Copyright (C) 1998 Mike Shaver
+ * Copyright (c) 1999 Al Smith
*
- * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
- * ``Inspired by'' fs/minix/dir.c.
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/efs_fs.h>
-#include <asm/uaccess.h>
+#include <linux/efs.h>
static int efs_readdir(struct file *, void *, filldir_t);
-int efs_lookup(struct inode *, struct dentry *);
-static ssize_t
-efs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-static struct file_operations efs_dir_ops = {
- NULL, /* lseek */
- efs_dir_read,
- NULL, /* write */
- efs_readdir,
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL /* fsync */
+static struct file_operations efs_dir_operations = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ efs_readdir,
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* no special open code */
+ NULL, /* flush */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
struct inode_operations efs_dir_inode_operations = {
- &efs_dir_ops,
- NULL, /* create */
- efs_lookup,
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* readpage */
- NULL, /* writepage */
- efs_bmap,
- NULL, /* truncate */
- NULL /* permission */
+ &efs_dir_operations,
+ NULL, /* create */
+ efs_lookup,
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ efs_bmap,
+ NULL, /* truncate */
+ NULL /* permission */
};
-static int
-efs_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
- struct inode *in = filp->f_dentry->d_inode;
- struct efs_inode_info *ini = &in->u.efs_i;
- struct buffer_head *bh;
- __u16 item;
- __u32 block;
- __u16 offset;
- struct efs_dirblk *dirblk;
- struct efs_dir_entry *entry;
-
- if (!in || !in->i_sb || !S_ISDIR(in->i_mode) || !ini->tot)
- return -EBADF;
-
- if (ini->tot > 1) {
- printk("EFS: ERROR: directory %s has %d extents\n",
- filp->f_dentry->d_name.name, ini->tot);
- printk("EFS: ERROR: Mike is lazy, so this is NYI.\n");
- return 0;
- };
-
- if (in->i_size & (EFS_BLOCK_SIZE - 1))
- printk("EFS: readdir: dirsize %#lx not block multiple\n", in->i_size);
-
- /* filp->f_pos is (block << BLOCK_SIZE | item) */
- block = filp->f_pos >> EFS_BLOCK_SIZE_BITS;
- item = filp->f_pos & 0xFF;
-
- start_block:
- if (block == (in->i_size >> EFS_BLOCK_SIZE_BITS))
- return 0; /* all done! */
-
- bh = bread(in->i_dev, efs_bmap(in, block), EFS_BLOCK_SIZE);
- if (!bh) {
- printk("EFS: ERROR: readdir: bread of %#lx/%#x\n",
- in->i_ino, efs_bmap(in, block));
- return 0;
- }
+/* read the next entry for a given directory */
+
+static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct efs_in_info *ini = (struct efs_in_info *) &inode->u.generic_ip;
+ struct buffer_head *bh;
+
+ struct efs_dir *dirblock;
+ struct efs_dentry *dirslot;
+ efs_ino_t inodenum;
+ efs_block_t block;
+ int slot, namelen, numslots;
+ char *nameptr;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+
+ if (ini->numextents != 1)
+ printk("EFS: WARNING: readdir(): more than one extent\n");
+
+ if (inode->i_size & (EFS_BLOCKSIZE-1))
+ printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_BLOCKSIZE\n");
+
+ /* work out the block where this entry can be found */
+ block = filp->f_pos >> EFS_BLOCKSIZE_BITS;
+
+ /* don't read past last entry */
+ if (block > inode->i_blocks) return 0;
+
+ /* read the dir block */
+ bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_BLOCKSIZE);
+
+ if (!bh) {
+ printk("EFS: readdir(): failed to read dir block %d\n", block);
+ return 0;
+ }
- dirblk = (struct efs_dirblk *)bh->b_data;
+ dirblock = (struct efs_dir *) bh->b_data;
- /* skip empty slots */
- do {
- offset = EFS_SLOT2OFF(dirblk, item);
- if (!offset) {
- DB(("EFS: skipping empty slot %d\n", item));
- }
- item++;
- if (item == dirblk->db_slots) {
- item = 0;
- block++;
- if (!offset) {
+ if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
+ printk("EFS: readdir(): invalid directory block\n");
brelse(bh);
- goto start_block;
- }
+ return(0);
}
- } while(!offset);
-
- entry = EFS_DENT4OFF(dirblk, offset);
- /*
- DB(("EFS_SLOT2OFF(%d) -> %d, EFS_DENT4OFF(%p, %d) -> %p) || ",
- item-1, offset, dirblk, offset, entry));
-#ifdef DEBUG_EFS
- {
- __u8 *rawdirblk, nameptr;
- __u32 iteminode;
- __u16 namelen, rawdepos;
- rawdirblk = (__u8*)bh->b_data;
- rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+item-1] << 1;
- DB(("OLD_WAY: offset = %d, dent = %p ||", rawdepos,
- (struct efs_dir_entry *)(rawdirblk + rawdepos)));
- }
+
+ slot = filp->f_pos & 0xff;
+
+ dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
+
+ numslots = dirblock->slots;
+ inodenum = be32_to_cpu(dirslot->inode);
+ namelen = dirslot->namelen;
+ nameptr = dirslot->name;
+
+#ifdef DEBUG
+ printk("EFS: dent #%d: inode %u, name \"%s\", namelen %u\n", slot, inodenum, nameptr, namelen);
#endif
- DB(("EFS: filldir(dirent, \"%.*s\", %d, %d, %d)\n",
- entry->d_namelen, entry->d_name, entry->d_namelen,
- filp->f_pos, efs_swab32(entry->ud_inum.l)));
- */
- filldir(dirent, entry->d_name, entry->d_namelen, filp->f_pos,
- efs_swab32(entry->ud_inum.l));
-
- brelse(bh);
+ /* copy filename and data in dirslot */
+ filldir(dirent, nameptr, namelen, filp->f_pos, inodenum);
- filp->f_pos = (block << EFS_BLOCK_SIZE_BITS) | item;
- UPDATE_ATIME(in);
+ brelse(bh);
- return 0;
+ /* store position of next slot */
+ if (++slot == numslots) {
+ slot = 0;
+ block++;
+ }
+
+ filp->f_pos = (block << EFS_BLOCKSIZE_BITS) | slot;
+
+ return 0;
}
+
diff --git a/fs/efs/file.c b/fs/efs/file.c
index e30ac301b..405143225 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -1,169 +1,65 @@
/*
- * linux/fs/efs/file.c
+ * file.c
*
- * Copyright (C) 1998 Mike Shaver
+ * Copyright (c) 1999 Al Smith
*
- * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
- * ``Inspired by'' fs/minix/file.c.
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
-#include <linux/efs_fs.h>
+#include <linux/efs.h>
static struct file_operations efs_file_operations = {
- NULL, /* lseek */
- generic_file_read,
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL /* fsync */
+ NULL, /* lseek */
+ generic_file_read,
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ generic_file_mmap,
+ NULL, /* flush */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
struct inode_operations efs_file_inode_operations = {
- &efs_file_operations, /* default file ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- generic_readpage, /* readpage */
- NULL, /* writepage */
- efs_bmap, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
+ &efs_file_operations,
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ generic_readpage,
+ NULL, /* writepage */
+ efs_bmap,
+ NULL, /* truncate */
+ NULL /* permission */
};
+
+int efs_bmap(struct inode *inode, efs_block_t block) {
-static inline __u32
-check_extent(union efs_extent *ext, int blk, int fs_start)
-{
- int eblk, epos, elen;
-
- eblk = ext->ex_bytes[0]; /* start disk block of the extent */
- epos = ext->ex_bytes[1] & 0xFFFFFF; /* starting logical block */
- elen = ext->ex_bytes[1] >> 24; /* length of the extent */
-
- if ( (blk >= epos) && (blk < epos+elen) )
- return blk - epos + eblk + fs_start;
- return 0;
-}
-
-#define CHECK(index) (check_extent(&ini->extents[index], blk, sbi->fs_start))
-
-static __u32
-efs_getblk(struct inode *in, __u32 blk)
-{
- struct efs_sb_info *sbi = &in->i_sb->u.efs_sb;
- struct efs_inode_info *ini = &in->u.efs_i;
- int iter;
-
- __u32 diskblk, total = ini->tot, current = ini->cur;
-
- if (total <= EFS_MAX_EXTENTS) {
- diskblk = CHECK(current);
- if (diskblk)
- return diskblk;
-
- if (total == 1)
- return 0;
-
- /*
- * OPT: start with current and then wrap, to optimize for
- * read-forward pattern.
- */
- for (iter = 0; iter < total; iter++) {
- if (iter == current)
- continue; /* already checked the current extent */
- diskblk = CHECK(iter);
- if (diskblk) {
- ini->cur = iter;
- DB(("EFS: inode %ld: found block %d as %d in ext %d\n",
- in->i_ino, blk, diskblk, iter));
- return diskblk;
- }
+ if (block < 0) {
+ printk("EFS: efs_bmap(): block < 0\n");
+ return 0;
}
- DB(("EFS: block %d not found in direct inode %ld (size %ld)\n",
- blk, in->i_ino, (long)in->i_size));
- return 0;
-
- } else {
- int indirext = 0, total_extents_checked = 0;
-
- /* indirect inode */
- DB(("EFS: inode %ld is indirect (total %d, indir ", in->i_ino, total));
- total = ini->extents[0].ex_ex.ex_offset;
- DB(("%d)\n", total));
-
- for (indirext = 0; indirext < total; indirext++) {
- struct buffer_head *extbh;
- union efs_extent *ptr;
- int indirblk, indirbn, indirlen;
- /*
- * OPT: copy the current direct extent into the inode info for a
- * quick check before we start reading blocks.
- * OPT: copy _10_ into the inode info, like the old code did.
- */
-
- indirbn = ini->extents[indirext].ex_ex.ex_bn;
- indirlen = ini->extents[indirext].ex_ex.ex_length;
- for (indirblk = indirbn;
- indirblk < indirbn + indirlen;
- indirblk++) {
- extbh = bread(in->i_dev, indirblk, EFS_BLOCK_SIZE);
- if (!extbh) {
- printk("EFS: ERROR: inode %ld bread of extent block %d failed\n",
- in->i_ino, indirblk);
- return 0;
- }
-
- for (ptr = (union efs_extent *)extbh->b_data;
- ptr < (union efs_extent *)(extbh->b_data+EFS_BLOCK_SIZE);
- ptr++, ++total_extents_checked) {
-
- diskblk = check_extent(ptr, blk, sbi->fs_start);
- if (diskblk || total_extents_checked > ini->tot) {
- brelse(extbh);
- return diskblk;
- }
- }
-
- brelse(extbh);
- }
+ /* are we about to read past the end of a file ? */
+ if (block > inode->i_blocks) {
+#ifdef DEBUG
+ /* dunno why this happens */
+ printk("EFS: efs_bmap(): block %d > last block %ld (filesize %ld)\n",
+ block,
+ inode->i_blocks,
+ inode->i_size);
+#endif
+ return 0;
}
- DB(("EFS: inode %ld: didn't find block %d (indir search, size %ld)\n",
- in->i_ino, blk, (long)in->i_size));
- return 0;
- }
-}
-
-int efs_bmap(struct inode *in, int block)
-{
- if (block < 0)
- return 0;
-
- if (!in->i_size) {
- DB(("EFS: um, inode %ld has size 0. What up?\n", in->i_ino));
- }
- /*
- * the kernel wants a full page (== 4K == 8 EFS blocks), so be sure that
- * the block number isn't too large for that.
- */
- if (block > ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS)) {
- DB(("EFS: wacky: block %d > max %ld\n", block,
- ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS)));
- return 0;
- }
-
- return efs_getblk(in, block);
+ return efs_read_block(inode, block);
}
+
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index f00b06520..9e7da7934 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -1,348 +1,245 @@
/*
- * linux/fs/efs/inode.c
+ * inode.c
*
- * Copyright (C) 1998 Mike Shaver
+ * Copyright (c) 1999 Al Smith
*
- * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
- * ``Inspired by'' fs/minix/inode.c.
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang,
+ * and from work (c) 1998 Mike Shaver.
*/
-#include <linux/module.h> /* module apparatus */
-#include <linux/init.h> /* __initfunc */
-#include <linux/efs_fs.h>
-#include <linux/locks.h>
-#include <asm/uaccess.h>
-
-#define COPY_EXTENT(from, to) \
-{ \
- to.ex_bytes[0] = efs_swab32(from.ex_bytes[0]); \
- to.ex_bytes[1] = efs_swab32(from.ex_bytes[1]); \
-}
-
-void
-efs_put_super(struct super_block *sb)
-{
- MOD_DEC_USE_COUNT;
-}
+#include <linux/efs.h>
+
+void efs_read_inode(struct inode *in) {
+ int i, extents, inode_index;
+ dev_t device;
+ struct buffer_head *bh;
+ struct efs_spb *sbp = (struct efs_spb *)&in->i_sb->u.generic_sbp;
+ struct efs_in_info *ini = (struct efs_in_info *)&in->u.generic_ip;
+ efs_block_t block, offset;
+ struct efs_dinode *efs_inode;
+
+ /*
+ ** EFS layout:
+ **
+ ** | cylinder group | cylinder group | cylinder group ..etc
+ ** |inodes|data |inodes|data |inodes|data ..etc
+ **
+ ** work out the inode block index, (considering initially that the
+ ** inodes are stored as consecutive blocks). then work out the block
+ ** number of that inode given the above layout, and finally the
+ ** offset of the inode within that block.
+ */
+
+ /* four inodes are stored in one block */
+ inode_index = in->i_ino / (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
+
+ block = sbp->fs_start + sbp->first_block +
+ (sbp->group_size * (inode_index / sbp->inode_blocks)) +
+ (inode_index % sbp->inode_blocks);
+
+ offset = (in->i_ino % (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) << 7;
+
+ bh = bread(in->i_dev, block, EFS_BLOCKSIZE);
+ if (!bh) {
+ printk("EFS: bread() failed at block %d\n", block);
+ goto read_inode_error;
+ }
-static struct super_operations efs_sops = {
- efs_read_inode,
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- efs_put_super,
- NULL, /* write_super */
- efs_statfs,
- NULL, /* remount */
-};
-
-static const char *
-efs_checkroot(struct super_block *sb, struct inode *dir)
-{
- struct buffer_head *bh;
-
- if (!S_ISDIR(dir->i_mode))
- return "root directory is not a directory";
-
- bh = bread(dir->i_dev, efs_bmap(dir, 0), EFS_BLOCK_SIZE);
- if (!bh)
- return "unable to read root directory";
-
- /* XXX check sanity of root directory */
+ efs_inode = (struct efs_dinode *) (bh->b_data + offset);
- brelse(bh);
- return NULL;
-}
+ /* fill in standard inode infos */
+ in->i_mode = be16_to_cpu(efs_inode->di_mode);
+ in->i_nlink = be16_to_cpu(efs_inode->di_nlink);
+ in->i_uid = be16_to_cpu(efs_inode->di_uid);
+ in->i_gid = be16_to_cpu(efs_inode->di_gid);
+ in->i_size = be32_to_cpu(efs_inode->di_size);
+ in->i_atime = be32_to_cpu(efs_inode->di_atime);
+ in->i_mtime = be32_to_cpu(efs_inode->di_mtime);
+ in->i_ctime = be32_to_cpu(efs_inode->di_ctime);
+
+ /* this is last valid block in the file */
+ in->i_blocks = ((in->i_size - 1) >> EFS_BLOCKSIZE_BITS);
+
+ device = be32_to_cpu(efs_inode->di_u.di_dev);
+
+ /* The following values are stored in my private part of the Inode.
+ They are necessary for further operations with the file */
+
+ /* get the number of extents for this object */
+ extents = be16_to_cpu(efs_inode->di_numextents);
+
+ /* copy the first 12 extents directly from the inode */
+ for(i = 0; i < EFS_DIRECTEXTENTS; i++) {
+ /* ick. horrible (ab)use of union */
+ ini->extents[i].u1.l = be32_to_cpu(efs_inode->di_u.di_extents[i].u1.l);
+ ini->extents[i].u2.l = be32_to_cpu(efs_inode->di_u.di_extents[i].u2.l);
+ if (i < extents && ini->extents[i].u1.s.ex_magic != 0) {
+ printk("EFS: extent %d has bad magic number in inode %lu\n", i, in->i_ino);
+ brelse(bh);
+ goto read_inode_error;
+ }
+ }
+ ini->numextents = extents;
+ ini->lastextent = 0;
+
+ brelse(bh);
+
+#ifdef DEBUG
+ printk("EFS: efs_read_inode(): inode %lu, extents %d\n",
+ in->i_ino, extents);
+#endif
-struct super_block *
-efs_read_super(struct super_block *s, void *data, int silent)
-{
- struct buffer_head *bh;
- struct efs_disk_sb *efs_sb;
- struct efs_sb_info *sbi;
- kdev_t dev = s->s_dev;
- const char *errmsg = "default error message";
- struct inode *root;
- __u32 magic;
-
- DB(("read_super on dev %s\n", kdevname(dev)));
- MOD_INC_USE_COUNT;
-
- lock_super(s);
- set_blocksize(dev, EFS_BLOCK_SIZE);
-
- /*
- * XXXshaver
- * If this is a CDROM, then there's a volume descriptor at block
- * EFS_BLK_VOLDESC. What's there if it's just a disk partition?
- */
-
- bh = bread(dev, EFS_BLK_SUPER, EFS_BLOCK_SIZE);
- if (!bh)
- goto out_bad_sb;
-
- efs_sb = (struct efs_disk_sb *)bh->b_data;
- sbi = &s->u.efs_sb;
- sbi->total_blocks = efs_sb->s_size;
- sbi->first_block = efs_sb->s_firstcg;
- sbi->group_size = efs_sb->s_cgfsize;
- sbi->inode_blocks = efs_sb->s_cgisize;
- sbi->total_groups = efs_sb->s_ncg;
- magic = efs_sb->s_magic;
- brelse(bh);
-
- if (magic == EFS_MAGIC1 || magic == EFS_MAGIC2) {
- DB(("EFS: valid superblock magic\n"));
- } else {
- goto out_no_fs;
- }
-
- if (efs_sb->s_dirty != EFS_CLEAN) {
- switch(efs_sb->s_dirty) {
- case EFS_ACTIVE:
- errmsg = "Partition was not unmounted properly, but is clean";
- break;
- case EFS_ACTIVEDIRT:
- errmsg = "Partition was mounted dirty and not cleanly unmounted";
- break;
- case EFS_DIRTY:
- errmsg = "Partition was not umounted properly, and is dirty";
- break;
- default:
- errmsg = "unknown!\n";
- break;
+ /* Install the filetype Handler */
+ switch (in->i_mode & S_IFMT) {
+ case S_IFDIR:
+ in->i_op = &efs_dir_inode_operations;
+ break;
+ case S_IFREG:
+ in->i_op = &efs_file_inode_operations;
+ break;
+ case S_IFLNK:
+ in->i_op = &efs_symlink_inode_operations;
+ break;
+ case S_IFCHR:
+ in->i_rdev = device;
+ in->i_op = &chrdev_inode_operations;
+ break;
+ case S_IFBLK:
+ in->i_rdev = device;
+ in->i_op = &blkdev_inode_operations;
+ break;
+ case S_IFIFO:
+ init_fifo(in);
+ break;
+ default:
+ printk("EFS: unsupported inode mode %o\n",in->i_mode);
+ goto read_inode_error;
+ break;
}
- if (!silent)
- printk("EFS: ERROR: cleanliness is %#04x: %s\n", efs_sb->s_dirty,
- errmsg);
- goto out_unlock;
- }
-
- s->s_blocksize = EFS_BLOCK_SIZE;
- s->s_blocksize_bits = EFS_BLOCK_SIZE_BITS;
- s->s_magic = EFS_SUPER_MAGIC;
- s->s_op = &efs_sops;
- DB(("getting root inode (%d)\n", EFS_ROOT_INODE));
- root = iget(s, EFS_ROOT_INODE);
-
- if (!root->i_size)
- goto out_bad_root;
- DB(("checking root inode\n"));
- errmsg = efs_checkroot(s, root);
- if (errmsg)
- goto out_bad_root;
-
- DB(("root inode OK\n"));
-
- s->s_root = d_alloc_root(root, NULL);
- if (!s->s_root)
- goto out_iput;
-
- /* we only do RO right now */
- if (!(s->s_flags & MS_RDONLY)) {
- if (!silent)
- printk("EFS: forcing read-only: RW access not supported\n");
- s->s_flags |= MS_RDONLY;
- }
-
- unlock_super(s);
- return s;
-
- /* error-handling exit paths */
- out_bad_root:
- if (!silent && errmsg)
- printk("EFS: bad_root ERROR: %s\n", errmsg);
-
- out_iput:
- iput(root);
- brelse(bh);
- goto out_unlock;
-
- out_no_fs:
- printk("EFS: ERROR: bad magic\n");
- goto out_unlock;
-
- out_bad_sb:
- printk("EFS: unable to read superblock\n");
-
- out_unlock:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return NULL;
-}
-int
-efs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
-{
- struct statfs tmp;
-
- DB(("statfs\n"));
- tmp.f_type = sb->s_magic;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = sb->u.efs_sb.total_blocks;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0; /* XXX? */
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ return;
+
+read_inode_error:
+ printk("EFS: failed to read inode %lu\n", in->i_ino);
+ in->i_mode = S_IFREG;
+ in->i_atime = 0;
+ in->i_ctime = 0;
+ in->i_mtime = 0;
+ in->i_nlink = 1;
+ in->i_size = 0;
+ in->i_blocks = 0;
+ in->i_uid = 0;
+ in->i_gid = 0;
+ in->i_op = NULL;
+
+ return;
}
-void
-efs_read_inode(struct inode *in)
-{
- struct efs_sb_info *efs_sb = &in->i_sb->u.efs_sb;
- struct buffer_head *bh;
- struct efs_disk_inode *di;
- struct efs_inode_info *ini = &in->u.efs_i;
- int block, ino = in->i_ino, offset;
- __u16 numext;
- __u32 rdev;
-
- DB(("read_inode\n"));
-
- /*
- * Calculate the disk block and offset for the inode.
- * There are 4 inodes per block.
- */
- block = ino / EFS_INODES_PER_BLOCK;
-
- /*
- * Inodes are stored at the beginning of every cylinder group.
- *
- * We find the block containing the inode like so:
- * - block is set above to the ``logical'' block number
- * - first_block is the start of the FS
- * - (block / inode_blocks) is the cylinder group that the inode is in.
- * - (block % inode_blocks) is the block offset within the cg
- *
- */
- block = efs_sb->first_block +
- (efs_sb->group_size * (block / efs_sb->inode_blocks)) +
- (block % efs_sb->inode_blocks);
-
- /* find the offset */
- offset = (ino % EFS_INODES_PER_BLOCK) << 7;
-
- DB(("EFS: looking for inode #%xl in blk %d offset %d\n",
- ino, block, offset));
-
- bh = bread(in->i_dev, block, EFS_BLOCK_SIZE);
-
- if (!bh) {
- printk("EFS: failed to bread blk #%xl for inode %#xl\n", block, ino);
- goto error;
- }
-
- di = (struct efs_disk_inode *)(bh->b_data + offset);
-
- /* standard inode info */
- in->i_mtime = efs_swab32(di->di_mtime);
- in->i_ctime = efs_swab32(di->di_ctime);
- in->i_atime = efs_swab32(di->di_atime);
- in->i_size = efs_swab32(di->di_size);
- in->i_nlink = efs_swab16(di->di_nlink);
- in->i_uid = efs_swab16(di->di_uid);
- in->i_gid = efs_swab16(di->di_gid);
- in->i_mode = efs_swab16(di->di_mode);
-
- DB(("INODE %ld: mt %ld ct %ld at %ld sz %ld nl %ld uid %ld gid %ld mode %lo\n",
- in->i_ino,
- in->i_mtime, in->i_ctime, in->i_atime, in->i_size, in->i_nlink,
- in->i_uid, in->i_gid, in->i_mode));
-
- rdev = efs_swab32(*(__u32 *) &di->di_u.di_dev);
- numext = efs_swab16(di->di_numextents);
-
- if (numext > EFS_MAX_EXTENTS) {
- DB(("EFS: inode %#0x is indirect (%d)\n", ino, numext));
+static inline efs_block_t
+efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_spb *sbi, struct efs_in_info *ini) {
+ efs_block_t start;
+ efs_block_t length;
+ efs_block_t offset;
/*
- * OPT: copy the first 10 extents in here?
- */
- } else {
- int i;
-
- DB(("EFS: inode %#lx is direct (%d). Happy day!\n", in->i_ino,
- numext));
- ini->extblk = block;
-
- /* copy extents into inode_info */
- for (i = 0; i < numext; i++) {
- COPY_EXTENT(di->di_u.di_extents[i], ini->extents[i]);
+ ** given an extent and a logical block within a file,
+ ** can this block be found within this extent ?
+ */
+ start = ptr->u1.s.ex_bn;
+ length = ptr->u2.s.ex_length;
+ offset = ptr->u2.s.ex_offset;
+
+ if ((block >= offset) && (block < offset+length)) {
+ return(sbi->fs_start + start + block - offset);
+ } else {
+ return 0;
}
-
- }
- ini->tot = numext;
- ini->cur = 0;
- brelse(bh);
-
- if (S_ISDIR(in->i_mode))
- in->i_op = &efs_dir_inode_operations;
- else if (S_ISREG(in->i_mode))
- in->i_op = &efs_file_inode_operations;
- else if (S_ISLNK(in->i_mode))
- in->i_op = &efs_symlink_inode_operations;
- else if (S_ISCHR(in->i_mode)) {
- in->i_rdev = rdev;
- in->i_op = &chrdev_inode_operations;
- } else if (S_ISBLK(in->i_mode)) {
- in->i_rdev = rdev;
- in->i_op = &blkdev_inode_operations;
- } else if (S_ISFIFO(in->i_mode))
- init_fifo(in);
- else {
- printk("EFS: ERROR: unsupported inode mode %#lo (dir is %#lo) =? %d\n",
- (in->i_mode & S_IFMT), (long)S_IFDIR,
- in->i_mode & S_IFMT == S_IFDIR);
- goto error;
- }
-
- return;
-
- error:
- DB(("ERROR: INODE %ld: mt %ld ct %ld at %ld sz %ld nl %ld uid %ld "
- "gid %ld mode %lo\n", in->i_ino,
- in->i_mtime, in->i_ctime, in->i_atime, in->i_size, in->i_nlink,
- in->i_uid, in->i_gid, in->i_mode));
- in->i_mtime = in->i_atime = in->i_ctime = 0;
- in->i_size = 0;
- in->i_nlink = 1;
- in->i_uid = in->i_gid = 0;
- in->i_mode = S_IFREG;
- in->i_op = NULL;
}
-static struct file_system_type efs_fs_type = {
- "efs",
- FS_REQUIRES_DEV,
- efs_read_super,
- NULL
-};
-
-__initfunc(int
-init_efs_fs(void))
-{
- return register_filesystem(&efs_fs_type);
-}
+/* find the disk block number for a given logical file block number */
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
+efs_block_t efs_read_block(struct inode *inode, efs_block_t block) {
+ struct efs_spb *sbi = (struct efs_spb *) &inode->i_sb->u.generic_sbp;
+ struct efs_in_info *ini = (struct efs_in_info *) &inode->u.generic_ip;
+ struct buffer_head *bh;
-int
-init_module(void)
-{
- DB(("loading EFS module\n"));
- return init_efs_fs();
-}
+ efs_block_t result = 0;
+ int indirexts, indirext, imagic;
+ efs_block_t istart, iblock, ilen;
+ int i, last, total, checked;
+ efs_extent *exts;
+ efs_extent tmp;
-void
-cleanup_module(void)
-{
- DB(("removing EFS module\n"));
- unregister_filesystem(&efs_fs_type);
-}
+ last = ini->lastextent;
+ total = ini->numextents;
+ if (total <= EFS_DIRECTEXTENTS) {
+ /* first check the last extent we returned */
+ if ((result = efs_extent_check(&ini->extents[last], block, sbi, ini)))
+ return result;
+
+ /* if we only have one extent then nothing can be found */
+ if (total == 1) {
+ printk("EFS: read_block() failed to map (1 extent)\n");
+ return 0;
+ }
+
+ /* check the stored extents in the inode */
+ /* start with next extent and check forwards */
+ for(i = 0; i < total - 1; i++) {
+ if ((result = efs_extent_check(&ini->extents[(last + i) % total], block, sbi, ini))) {
+ ini->lastextent = i;
+ return result;
+ }
+ }
+
+ printk("EFS: read_block() failed to map for direct extents\n");
+ return 0;
+ }
+
+#ifdef DEBUG
+ printk("EFS: indirect search for logical block %u\n", block);
#endif
+ indirexts = ini->extents[0].u2.s.ex_offset;
+ checked = 0;
+
+ for(indirext = 0; indirext < indirexts; indirext++) {
+ imagic = ini->extents[indirext].u1.s.ex_magic;
+ istart = ini->extents[indirext].u1.s.ex_bn + sbi->fs_start;
+ ilen = ini->extents[indirext].u2.s.ex_length;
+
+ for(iblock = istart; iblock < istart + ilen; iblock++) {
+ bh = bread(inode->i_dev, iblock, EFS_BLOCKSIZE);
+ if (!bh) {
+ printk("EFS: bread() failed at block %d\n", block);
+ return 0;
+ }
+
+ exts = (struct extent *) bh->b_data;
+ for(i = 0; i < EFS_BLOCKSIZE / sizeof(efs_extent) && checked < total; i++, checked++) {
+ tmp.u1.l = be32_to_cpu(exts[i].u1.l);
+ tmp.u2.l = be32_to_cpu(exts[i].u2.l);
+
+ if (tmp.u1.s.ex_magic != 0) {
+ printk("EFS: extent %d has bad magic number in block %d\n", i, iblock);
+ brelse(bh);
+ return 0;
+ }
+
+ if ((result = efs_extent_check(&tmp, block, sbi, ini))) {
+ brelse(bh);
+ return result;
+ }
+ }
+ brelse(bh);
+ /* shouldn't need this if the FS is consistent */
+ if (checked == total) {
+ printk("EFS: unable to map (checked all extents)\n");
+ return 0;
+ }
+ }
+ }
+ printk("EFS: unable to map (fell out of loop)\n");
+ return 0;
+}
+
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index eba441e5a..5d7cc9aa1 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -1,96 +1,83 @@
/*
- * linux/fs/efs/namei.c
+ * namei.c
*
- * Copyright (C) 1998 Mike Shaver
+ * Copyright (c) 1999 Al Smith
*
- * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
- * ``Inspired by'' fs/minix/namei.c.
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
-#include <linux/efs_fs.h>
-#include <linux/errno.h>
-
-static struct buffer_head *
-efs_find_entry(struct inode *dir, const char *oname, int onamelen,
- struct efs_dir_entry **res_dir)
-{
- struct buffer_head *bh;
- struct efs_sb_info *sbi;
- struct efs_dirblk *dirblk;
- __u32 offset, block, maxblk;
- __u16 i, namelen;
- char *name;
-
- *res_dir = NULL;
- if (!dir || !dir->i_sb)
- return NULL;
- sbi = &dir->i_sb->u.efs_sb;
- bh = NULL;
- block = offset = 0;
- maxblk = dir->i_size >> EFS_BLOCK_SIZE_BITS;
- DB(("EFS: dir has %d blocks\n", maxblk));
- for (block = 0; block < maxblk; block++) {
-
- bh = bread(dir->i_dev, efs_bmap(dir, block), EFS_BLOCK_SIZE);
- if (!bh) {
- DB(("EFS: find_entry: skip blk %d (ino %#lx): bread\n",
- block, dir->i_ino));
- continue;
- }
+#include <linux/efs.h>
+
+/* search an efs directory inode for the given name */
+
+static uint32_t efs_find_entry(struct inode *inode, const char *name, int len) {
+ struct efs_in_info *ini = (struct efs_in_info *) &inode->u.generic_ip;
+ struct buffer_head *bh;
+
+ int slot, namelen;
+ char *nameptr;
+ struct efs_dir *dirblock;
+ struct efs_dentry *dirslot;
+ efs_ino_t inodenum;
+ efs_block_t block;
+
+ if (ini->numextents != 1)
+ printk("EFS: WARNING: readdir(): more than one extent\n");
+
+ if (inode->i_size & (EFS_BLOCKSIZE-1))
+ printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_BLOCKSIZE\n");
+
+ for(block = 0; block <= inode->i_blocks; block++) {
+
+ bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_BLOCKSIZE);
+ if (!bh) {
+ printk("EFS: find_entry(): failed to read dir block %d\n", block);
+ return 0;
+ }
+
+ dirblock = (struct efs_dir *) bh->b_data;
+
+ if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
+ printk("EFS: readdir(): invalid directory block\n");
+ brelse(bh);
+ return(0);
+ }
+
+ for(slot = 0; slot < dirblock->slots; slot++) {
+ dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
- dirblk = (struct efs_dirblk *)bh->b_data;
+ namelen = dirslot->namelen;
+ nameptr = dirslot->name;
- if (efs_swab32(dirblk->db_magic) != EFS_DIRBLK_MAGIC) {
- printk("EFS: dirblk %d (ino %#lx) has bad magic (%#x)!\n",
- block, dir->i_ino, efs_swab32(dirblk->db_magic));
- brelse(bh);
- continue;
+ if ((namelen == len) && (!memcmp(name, nameptr, len))) {
+ inodenum = be32_to_cpu(dirslot->inode);
+ brelse(bh);
+ return(inodenum);
+ }
+ }
+ brelse(bh);
}
+ return(0);
+}
+
+
+/* get inode associated with directory entry */
+
+int efs_lookup(struct inode *dir, struct dentry *dentry) {
+ int ino;
+ struct inode * inode;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) return -ENOENT;
- DB(("EFS: db %d has %d entries\n", block, dirblk->db_slots));
-
- for (i = 0; i < dirblk->db_slots; i++) {
- struct efs_dir_entry *dent;
- __u16 off = EFS_SLOT2OFF(dirblk, i);
- if (!off) {
- DB(("skipping empty slot %d\n", i));
- continue; /* skip empty slot */
- }
- dent = EFS_DENT4OFF(dirblk, off);
- namelen = dent->d_namelen;
- name = dent->d_name;
-
- if ((namelen == onamelen) &&
- !memcmp(oname, name, onamelen)) {
- *res_dir = dent;
- return bh;
- }
+ inode = NULL;
+
+ ino = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
+ if (ino) {
+ if (!(inode = iget(dir->i_sb, ino)))
+ return -EACCES;
}
- brelse(bh);
- }
- DB(("EFS: find_entry didn't find inode for \"%s\"/%d\n",
- oname, onamelen));
- return NULL;
+ d_add(dentry, inode);
+ return 0;
}
-int
-efs_lookup(struct inode *dir, struct dentry *dentry)
-{
- struct buffer_head *bh;
- struct inode *in = NULL;
- struct efs_dir_entry *dent;
-
- bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &dent);
- if (bh) {
- int ino = efs_swab32(dent->ud_inum.l);
-
- brelse(bh);
- in = iget(dir->i_sb, ino);
- if (!in)
- return -EACCES;
- }
-
- d_add(dentry, in);
- return 0;
-}
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index cd69ef5fc..f5c11792b 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -1,63 +1,17 @@
/*
- * linux/fs/efs/symlink.c
+ * symlink.c
*
- * Copyright (C) 1998 Mike Shaver
+ * Copyright (c) 1999 Al Smith
*
- * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
- * ``Inspired by'' fs/ext2/symlink.c.
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
-#include <linux/efs_fs.h>
-#include <asm/uaccess.h>
-
-static struct dentry *
-efs_follow_link(struct dentry *dentry, struct dentry *base,
- unsigned int follow)
-{
- struct inode *in = dentry->d_inode;
- struct buffer_head *bh;
-
- bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE);
- if (!bh) {
- dput(base);
- return ERR_PTR(-EIO);
- }
- UPDATE_ATIME(in);
- base = lookup_dentry(bh->b_data, base, follow);
- brelse(bh);
- return base;
-}
+#include <linux/efs.h>
static int
-efs_readlink(struct dentry *dentry, char * buffer, int buflen)
-{
- int i;
- struct buffer_head *bh;
- struct inode *in = dentry->d_inode;
-
- if (buflen > 1023)
- buflen = 1023;
-
- if (in->i_size < buflen)
- buflen = in->i_size;
-
- bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE);
- if (!bh)
- return 0;
- i = 0;
-
- /* XXX need strncpy_to_user */
- while (i < buflen && bh->b_data[i])
- i++;
-
- if (copy_to_user(buffer, bh->b_data, i))
- i = -EFAULT;
-
- UPDATE_ATIME(in);
-
- brelse(bh);
- return i;
-}
+ efs_readlink(struct dentry *, char *, int);
+static struct dentry *
+ efs_follow_link(struct dentry *, struct dentry *, unsigned int);
struct inode_operations efs_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -70,12 +24,78 @@ struct inode_operations efs_symlink_inode_operations = {
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- efs_readlink,
- efs_follow_link,
+ efs_readlink, /* readlink */
+ efs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL, /* permission */
- NULL /* smap */
+ NULL /* permission */
};
+
+static char *efs_linktarget(struct inode *in) {
+ char *name;
+ struct buffer_head * bh;
+ efs_block_t size = in->i_size;
+
+ if (size > 2 * EFS_BLOCKSIZE) {
+ printk("EFS: efs_linktarget: name too long: %lu\n", in->i_size);
+ return NULL;
+ }
+
+ if (!(name = kmalloc(size + 1, GFP_KERNEL)))
+ return NULL;
+
+ /* read first 512 bytes of link target */
+ bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCKSIZE);
+ if (!bh) {
+ kfree(name);
+ printk("EFS: efs_linktarget: couldn't read block %d\n", efs_bmap(in, 0));
+ return NULL;
+ }
+
+ memcpy(name, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size);
+ brelse(bh);
+
+ if (size > EFS_BLOCKSIZE) {
+ bh = bread(in->i_dev, efs_bmap(in, 1), EFS_BLOCKSIZE);
+ if (!bh) {
+ kfree(name);
+ printk("EFS: efs_linktarget: couldn't read block %d\n", efs_bmap(in, 1));
+ return NULL;
+ }
+ memcpy(name + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE);
+ brelse(bh);
+ }
+
+ name[size] = (char) 0;
+
+ return name;
+}
+
+static struct dentry *efs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) {
+ char *name;
+ struct inode *inode = dentry->d_inode;
+
+ name = efs_linktarget(inode);
+ base = lookup_dentry(name, base, follow);
+ kfree(name);
+
+ return base;
+}
+
+static int efs_readlink(struct dentry * dir, char * buf, int bufsiz) {
+ int rc;
+ char *name;
+ struct inode *inode = dir->d_inode;
+
+ if (bufsiz > 1023) bufsiz = 1023;
+
+ if (!(name = efs_linktarget(inode))) return 0;
+
+ rc = copy_to_user(buf, name, bufsiz) ? -EFAULT : 0;
+ kfree(name);
+
+ return rc;
+}
+