struct inode vfs_inode;
};
+static struct inode *romfs_iget(struct super_block *, unsigned long);
+
/* instead of private superblock data */
static inline unsigned long romfs_maxsize(struct super_block *sb)
{
struct buffer_head *bh;
struct romfs_super_block *rsb;
struct inode *root;
- int sz;
+ int sz, ret = -EINVAL;
/* I would parse the options here, but there are none.. :) */
& ROMFH_MASK;
s->s_op = &romfs_ops;
- root = iget(s, sz);
- if (!root)
+ root = romfs_iget(s, sz);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
goto out;
+ }
+ ret = -ENOMEM;
s->s_root = d_alloc_root(root);
if (!s->s_root)
goto outiput;
out:
brelse(bh);
outnobh:
- return -EINVAL;
+ return ret;
}
/* That's simple too. */
romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
unsigned long offset, maxoff;
- int fslen, res;
- struct inode *inode;
+ long res;
+ int fslen;
+ struct inode *inode = NULL;
char fsname[ROMFS_MAXFN]; /* XXX dynamic? */
struct romfs_inode ri;
const char *name; /* got from dentry */
offset = dir->i_ino & ROMFH_MASK;
lock_kernel();
if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
- goto out;
+ goto error;
maxoff = romfs_maxsize(dir->i_sb);
offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
for(;;) {
if (!offset || offset >= maxoff)
- goto out0;
+ goto success; /* negative success */
if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
- goto out;
+ goto error;
/* try to match the first 16 bytes of name */
fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
- if ((inode = iget(dir->i_sb, offset)))
- goto outi;
-
- /*
- * it's a bit funky, _lookup needs to return an error code
- * (negative) or a NULL, both as a dentry. ENOENT should not
- * be returned, instead we need to create a negative dentry by
- * d_add(dentry, NULL); and return 0 as no error.
- * (Although as I see, it only matters on writable file
- * systems).
- */
-
-out0: inode = NULL;
-outi: res = 0;
- d_add (dentry, inode);
+ inode = romfs_iget(dir->i_sb, offset);
+ if (IS_ERR(inode)) {
+ res = PTR_ERR(inode);
+ goto error;
+ }
-out: unlock_kernel();
+success:
+ d_add(dentry, inode);
+ res = 0;
+error:
+ unlock_kernel();
return ERR_PTR(res);
}
romfs_readpage(struct file *file, struct page * page)
{
struct inode *inode = page->mapping->host;
- loff_t offset, avail, readlen;
+ loff_t offset, size;
+ unsigned long filled;
void *buf;
int result = -EIO;
/* 32 bit warning -- but not for us :) */
offset = page_offset(page);
- if (offset < i_size_read(inode)) {
- avail = inode->i_size-offset;
- readlen = min_t(unsigned long, avail, PAGE_SIZE);
- if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) {
- if (readlen < PAGE_SIZE) {
- memset(buf + readlen,0,PAGE_SIZE-readlen);
- }
- SetPageUptodate(page);
- result = 0;
+ size = i_size_read(inode);
+ filled = 0;
+ result = 0;
+ if (offset < size) {
+ unsigned long readlen;
+
+ size -= offset;
+ readlen = size > PAGE_SIZE ? PAGE_SIZE : size;
+
+ filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen);
+
+ if (filled != readlen) {
+ SetPageError(page);
+ filled = 0;
+ result = -EIO;
}
}
- if (result) {
- memset(buf, 0, PAGE_SIZE);
- SetPageError(page);
- }
+
+ if (filled < PAGE_SIZE)
+ memset(buf + filled, 0, PAGE_SIZE-filled);
+
+ if (!result)
+ SetPageUptodate(page);
flush_dcache_page(page);
unlock_page(page);
S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
};
-static void
-romfs_read_inode(struct inode *i)
+static struct inode *
+romfs_iget(struct super_block *sb, unsigned long ino)
{
- int nextfh, ino;
+ int nextfh;
struct romfs_inode ri;
+ struct inode *i;
+
+ ino &= ROMFH_MASK;
+ i = iget_locked(sb, ino);
+ if (!i)
+ return ERR_PTR(-ENOMEM);
+ if (!(i->i_state & I_NEW))
+ return i;
- ino = i->i_ino & ROMFH_MASK;
i->i_mode = 0;
/* Loop for finding the real hard link */
for(;;) {
if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
- printk("romfs: read error for inode 0x%x\n", ino);
- return;
+ printk(KERN_ERR "romfs: read error for inode 0x%lx\n",
+ ino);
+ iget_failed(i);
+ return ERR_PTR(-EIO);
}
/* XXX: do romfs_checksum here too (with name) */
init_special_inode(i, ino,
MKDEV(nextfh>>16,nextfh&0xffff));
}
+ unlock_new_inode(i);
+ return i;
}
static struct kmem_cache * romfs_inode_cachep;
kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
}
-static void init_once(struct kmem_cache *cachep, void *foo)
+static void init_once(void *foo)
{
struct romfs_inode_info *ei = foo;
static const struct super_operations romfs_ops = {
.alloc_inode = romfs_alloc_inode,
.destroy_inode = romfs_destroy_inode,
- .read_inode = romfs_read_inode,
.statfs = romfs_statfs,
.remount_fs = romfs_remount,
};