summaryrefslogtreecommitdiffstats
path: root/fs/efs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/efs/inode.c')
-rw-r--r--fs/efs/inode.c549
1 files changed, 223 insertions, 326 deletions
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;
+}
+