From 76a6e3640c7212dacd5ce3c39161921d31a69800 Mon Sep 17 00:00:00 2001 From: Mike Shaver Date: Thu, 25 Mar 1999 17:37:58 +0000 Subject: Al Smith's new EFS code, which seems to work and things --- fs/efs/Makefile | 2 - fs/efs/dir.c | 221 ++++++++++------------ fs/efs/file.c | 200 +++++--------------- fs/efs/inode.c | 549 ++++++++++++++++++++++--------------------------------- fs/efs/namei.c | 153 +++++++--------- fs/efs/symlink.c | 134 ++++++++------ 6 files changed, 515 insertions(+), 744 deletions(-) (limited to 'fs') 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 -#include -#include -#include +#include 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 +#include 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 /* module apparatus */ -#include /* __initfunc */ -#include -#include -#include - -#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 + +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 -#include - -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 + +/* 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 -#include - -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 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; +} + -- cgit v1.2.3