summaryrefslogtreecommitdiffstats
path: root/fs/efs
diff options
context:
space:
mode:
authorMike Shaver <shaver@ingenia.com>1998-05-23 04:48:39 +0000
committerMike Shaver <shaver@ingenia.com>1998-05-23 04:48:39 +0000
commit74c548680437147ae09d70e8505c38d9b3eadee5 (patch)
tree53839b4b36e0d54ded13c2fb23d71f63f6787cc6 /fs/efs
parentb4930b0d404da1157965de172686b7dbf14b5e99 (diff)
Some (incomplete) EFS fixes: can now walk directory trees, follow symlinks
and read files that don't have indirect extents. Unmounting the EFS partition causes hangs (deadlock with the locking of the superblock, I think), and it's nothing resembling fast or clean code. That's for tomorrow.
Diffstat (limited to 'fs/efs')
-rw-r--r--fs/efs/dir.c171
-rw-r--r--fs/efs/inode.c11
-rw-r--r--fs/efs/namei.c16
-rw-r--r--fs/efs/symlink.c21
4 files changed, 132 insertions, 87 deletions
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index a89dd304e..0fd4f3187 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -60,78 +60,109 @@ struct inode_operations efs_dir_in_ops = {
return - 0 ok, <0 error
*/
-static int efs_readdir(struct file *filp,
- void *dirent, filldir_t filldir)
+static int
+efs_readdir(struct file *filp,
+ void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
- struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i;
- struct buffer_head *bh;
- __u8 *rawdirblk;
- __u32 iteminode;
- __u16 namelen;
- __u8 *nameptr;
- __u32 numitems;
- __u16 itemnum;
- __u32 block;
- __u16 rawdepos;
-
- /* some checks */
- if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
- /* Warnings */
- if(ini->tot!=1) {
- printk("EFS: directory %s has more than one extent.\n",
- filp->f_dentry->d_name.name);
- printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n");
- return 0;
- }
- if(inode->i_size & (EFS_BLOCK_SIZE-1))
- printk("efs_readdir: dirsize != blocksize*n\n");
-
- /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */
- block = filp->f_pos >> EFS_BLOCK_SIZE_BITS;
- itemnum = filp->f_pos & 0xff;
-
- /* We found the last entry -> ready */
- if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS))
- return 0;
-
- /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */
- bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE);
- if(!bh) return 0;
-
- /* dirblock */
- rawdirblk = (__u8 *)bh->b_data;
- /* number of entries stored in this dirblock */
- numitems = rawdirblk[EFS_DB_ENTRIES];
- /* offset in block of #off diritem */
- rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+itemnum]<<1;
-
- /* diritem first contains the inode number, the namelen and the name */
- iteminode = ConvertLong(rawdirblk,rawdepos);
- namelen = (__u16)rawdirblk[rawdepos+EFS_DI_NAMELEN];
- nameptr = rawdirblk + rawdepos + EFS_DI_NAME;
-
-#ifdef DEBUG_EFS
- printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n",
- itemnum,rawdepos,iteminode,nameptr,namelen);
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i;
+ struct buffer_head *bh;
+ struct efs_dirblk *dirblk;
+ __u32 iteminode;
+ __u16 namelen;
+ char *nameptr;
+ __u16 itemnum;
+ __u32 block;
+ int db_offset;
+ int error = 0;
+ struct efs_dent *de = NULL;
+
+ /* some checks -- ISDIR should be done by upper layer */
+ if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
+ printk("EFS: bad inode for readdir!\n");
+ return -EBADF;
+ }
+
+ if(ini->tot!=1) {
+ printk("EFS: directory %s has more than one extent.\n",
+ filp->f_dentry->d_name.name);
+ printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n");
+ return -EBADF;
+ }
+
+ /* Warnings */
+ if(inode->i_size & (EFS_BLOCK_SIZE-1))
+ printk("efs_readdir: dirsize != blocksize*n\n");
+
+ /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */
+ block = filp->f_pos >> EFS_BLOCK_SIZE_BITS;
+ itemnum = filp->f_pos & 0xff;
+
+ /* We found the last entry -> ready */
+ if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS)) {
+ printk("EFS: read all entries -- done\n");
+ return 0;
+ }
+
+ /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */
+ bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE);
+ if(!bh) {
+ /* XXX try next block? */
+ return -EBADF;
+ }
+
+ /* from here on, we must exit through out: to release bh */
+
+ /* dirblock */
+ dirblk = (struct efs_dirblk *)bh->b_data;
+ if (dirblk->db_magic != EFS_DIRBLK_MAGIC) {
+ printk("EFS: bad dirblk magic %#xl\n", dirblk->db_magic);
+ error = -EBADF;
+ goto out;
+ }
+ db_offset = ((__u16)dirblk->db_space[itemnum] << 1)
+ - EFS_DIRBLK_HEADERSIZE;
+ de = (struct efs_dent *)(&dirblk->db_space[db_offset]);
+ if (dirblk->db_slots == 0) {
+ error = 0;
+ goto out;
+ }
+
+#ifdef DEBUG_EFS_DIRS
+ if (itemnum == 0) {
+ printk("efs: readdir: db %d has %d entries, starting at offset %0#x\n",
+ block, dirblk->db_slots, (__u16)dirblk->db_firstused << 1);
+ }
+#endif
+
+ /* diritem first contains the inode number, the namelen and the name */
+ iteminode = EFS_DE_GET_INUM(de);
+ namelen = de->d_namelen;
+ nameptr = de->d_name;
+
+#ifdef DEBUG_EFS_DIRS
+ printk("efs: dir #%d @ %0#x - inode %#0x %*s namelen %u\n",
+ itemnum,db_offset,iteminode, namelen,
+ nameptr ? nameptr : "(null)", namelen);
#endif
- /* copy filename and data in direntry */
- filldir(dirent,nameptr,namelen,filp->f_pos,iteminode);
-
- brelse(bh);
-
- /* store pos of next item */
- itemnum++;
- if(itemnum==numitems) {
- itemnum = 0;
- block++;
- }
- filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum;
- UPDATE_ATIME(inode);
-
- return 0;
+ /* copy filename and data in direntry */
+ error = filldir(dirent,nameptr,namelen,filp->f_pos,iteminode);
+ if (error)
+ goto out;
+
+ /* store pos of next item */
+ itemnum++;
+ if(itemnum == dirblk->db_slots) {
+ itemnum = 0;
+ block++;
+ }
+ filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum;
+ UPDATE_ATIME(inode);
+
+ out:
+ brelse(bh);
+
+ return error;
}
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 7928e45b4..a75d44956 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -17,13 +17,14 @@
/* ----- Define the operations for the Superblock ----- */
void efs_read_inode(struct inode *);
+void efs_put_inode(struct inode *);
void efs_put_super(struct super_block *);
int efs_statfs(struct super_block *, struct statfs *,int );
static struct super_operations efs_sops = {
efs_read_inode,
NULL, /* write_inode */
- NULL, /* put_inode */
+ efs_put_inode, /* put_inode */
NULL, /* delete_inode */
NULL, /* notify_change */
efs_put_super,
@@ -32,6 +33,10 @@ static struct super_operations efs_sops = {
NULL
};
+static void efs_put_inode(struct inode *i) {
+ printk("efs_put_inode: iput()ting inode %d\n", i->i_ino);
+}
+
/* ----- Conversion utilities -----
Get 16- and 32-bit unsigned values in big-endian format from a byte buffer
@@ -369,7 +374,7 @@ void efs_read_inode(struct inode *in)
/* Read the block with the inode from disk */
#ifdef DEBUG_EFS
- printk("EFS: looking for inode %#xl\n", in->i_ino);
+ printk("EFS: looking for inode %#lx\n", in->i_ino);
#endif
bh = bread(in->i_dev,blk,EFS_BLOCK_SIZE);
if(bh) {
@@ -430,7 +435,7 @@ void efs_read_inode(struct inode *in)
} else {
#ifdef DEBUG_EFS
- printk("EFS: inode %#Xl is direct (woohoo!)\n",
+ printk("EFS: inode %#lx is direct (woohoo!)\n",
in->i_ino);
#endif
/* The extends are found in the inode block */
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index 752aa5fe1..9cbdd9550 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -47,13 +47,13 @@ static struct buffer_head * efs_find_entry(struct inode *dir,
/* Search in every dirblock */
inode = 0;
blknum = dir->i_size >> EFS_BLOCK_SIZE_BITS;
-#ifdef DEBUG_EFS
+#ifdef DEBUG_EFS_DIRS
printk("EFS: directory with inode %#xd has %d blocks\n",
dir->i_ino, blknum);
#endif
for(b=0;b<blknum;b++) {
int db_offset;
-#ifdef DEBUG_EFS
+#ifdef DEBUG_EFS_DIRS
printk("EFS: trying block %d\n", b);
#endif
/* Read a raw dirblock */
@@ -69,7 +69,7 @@ static struct buffer_head * efs_find_entry(struct inode *dir,
db->db_magic);
return NULL;
}
-#ifdef DEBUG_EFS
+#ifdef DEBUG_EFS_DIRS
printk("EFS: db %d has %d entries, starting at offset %#x\n",
b, db->db_slots, (__u16)db->db_firstused << 1);
#endif
@@ -81,18 +81,18 @@ static struct buffer_head * efs_find_entry(struct inode *dir,
de = (struct efs_dent *)(&db->db_space[db_offset]);
/* inode, namelen and name of direntry */
- entry_inode = efs_swab32(de->ud_inum.l);
+ entry_inode = EFS_DE_GET_INUM(de);
namelen = de->d_namelen;
name = de->d_name;
-#ifdef 0
- printk("EFS: entry %d @ %#x has inode %#x, %s/%d\n",
- i, db_offset, entry_inode, name, namelen);
+#ifdef DEBUG_EFS_DIRS
+ printk("EFS: entry %d @ %#lx has inode %#x: \"%*s\"\n",
+ i, db_offset, entry_inode, namelen, name);
#endif
/* we found the name! */
if((namelen==onamelen)&&
(!memcmp(oname,name,onamelen))) {
res_dir->inode = entry_inode;
-#ifdef DEBUG_EFS
+#ifdef DEBUG_EFS_DIRS
printk("EFS: found inode %d\n",
entry_inode);
#endif
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 05e3c082d..8c52411a1 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -16,8 +16,8 @@
#include <linux/slab.h>
#include <asm/uaccess.h>
-static int efs_readlink(struct inode *, char *, int);
-static struct dentry * efs_follow_link(struct inode *, struct dentry *);
+static int efs_readlink(struct dentry *, char *, int);
+static struct dentry * efs_follow_link(struct dentry *, struct dentry *);
struct inode_operations efs_symlink_in_ops = {
NULL, /* no file-operations */
@@ -50,6 +50,10 @@ static char *efs_getlinktarget(struct inode *in)
__u32 size = in->i_size;
__u32 block;
+#ifdef DEBUG_EFS
+ printk("efs_getlinktarget: size of inode %#0lx is %d\n", in->i_ino,
+ size);
+#endif
/* link data longer than 1024 not supported */
if(size>2*EFS_BLOCK_SIZE) {
printk("efs_getlinktarget: name too long: %lu\n",in->i_size);
@@ -64,6 +68,7 @@ static char *efs_getlinktarget(struct inode *in)
block = efs_bmap(in,0);
bh = bread(in->i_dev,block,EFS_BLOCK_SIZE);
if(!bh) {
+ printk("efs_getlinktarget: unable to read first block (%d)\n", block);
kfree(name);
return NULL;
}
@@ -74,8 +79,9 @@ static char *efs_getlinktarget(struct inode *in)
if(size>EFS_BLOCK_SIZE) {
bh = bread(in->i_dev,block+1,EFS_BLOCK_SIZE);
if(!bh) {
- kfree(name);
- return NULL;
+ printk("efs_getlinktarget: unable to read second block (%d)\n", block);
+ kfree(name);
+ return NULL;
}
memcpy(name+EFS_BLOCK_SIZE,bh->b_data,size-EFS_BLOCK_SIZE);
brelse(bh);
@@ -90,8 +96,10 @@ static char *efs_getlinktarget(struct inode *in)
/* ----- efs_follow_link -----
get the inode of the link target
*/
-static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base)
+static struct dentry * efs_follow_link(struct dentry * dent,
+ struct dentry *base)
{
+ struct inode * dir = dent->d_inode;
char * name;
UPDATE_ATIME(dir);
name = efs_getlinktarget(dir);
@@ -107,10 +115,11 @@ static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base)
/* ----- efs_readlink -----
read the target of a link and return the name
*/
-static int efs_readlink(struct inode * dir, char * buffer, int buflen)
+static int efs_readlink(struct dentry * dent, char * buffer, int buflen)
{
int i;
struct buffer_head * bh;
+ struct inode * dir = dent->d_inode;
if (buflen > 1023)
buflen = 1023;