Commit 7de9a85a authored by Alessandro Rubini's avatar Alessandro Rubini

sdbfs/kernel: first working (read-only) implementation

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 3994fe19
......@@ -27,12 +27,13 @@ struct fakedev {
static struct fakedev fakedev_devs[8];
static struct device fakedev_device;
static ssize_t fakedev_read(struct sdbfs_dev *sd, uint32_t begin, u8 *buf,
static ssize_t fakedev_read(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count)
{
struct fakedev *fd;
int len;
printk("%s: %08x - %i\n", __func__, (int)begin, count);
fd = container_of(sd, struct fakedev, sd);
len = fd->fw->size;
if (begin > len)
......@@ -68,6 +69,7 @@ static int fakedev_init(void)
for (i = 0; i < nimg; i++) {
d = fakedev_devs + i;
printk("request for %i -- n %i\n", i, nimg);
if (request_firmware(&d->fw, fsimg[i], &fakedev_device) < 0) {
printk("%s: can't load %s\n", KBUILD_MODNAME,
fsimg[i]);
......
......@@ -10,46 +10,149 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/sdb.h> /* in ../include, by now */
#include <linux/uaccess.h>
#include "sdbfs.h"
#include "sdbfs-int.h"
#define SDB_SIZE (sizeof(struct sdb_device))
static int sdbfs_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
struct inode *ino = filp->f_dentry->d_inode;
struct sdbfs_inode *inode;
struct sdb_device *s_d;
unsigned long file_off = filp->f_pos;
unsigned long offset = ino->i_ino & ~1;
int i, j, n;
printk("%s\n", __func__);
return -ENOENT;
if (file_off != 0)
return 0;
inode = container_of(ino, struct sdbfs_inode, ino);
n = be16_to_cpu(inode->s_i.sdb_records) - 1;
/* FIXME: use file_off */
for (i = 0; i < n; i++) {
char s[20];
offset += SDB_SIZE;
s_d = (struct sdb_device *)inode->files + i;
strncpy(s, s_d->sdb_component.product.name, 19);
for (j = 19; j; j--) {
s[j] = '\0';
if (s[j-1] != ' ')
break;
}
if (filldir(dirent, s, j, offset, offset, DT_UNKNOWN) < 0)
return i;
filp->f_pos++;
}
return i;
}
static const struct file_operations sdbfs_dir_operations = {
static const struct file_operations sdbfs_dir_fops = {
.read = generic_read_dir,
.readdir = sdbfs_readdir,
.llseek = default_llseek,
};
static ssize_t sdbfs_read(struct file *f, char __user *buf, size_t count,
loff_t *offp)
{
struct inode *ino = f->f_dentry->d_inode;
struct super_block *sb = ino->i_sb;
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode;
char kbuf[16];
unsigned long start, size;
ssize_t ret;
inode = container_of(ino, struct sdbfs_inode, ino);
start = be64_to_cpu(inode->s_d.sdb_component.addr_first);
size = be64_to_cpu(inode->s_d.sdb_component.addr_last) + 1 - start;
/* Horribly inefficient, who cares... */
if (*offp > size)
return 0;
if (*offp + count > size)
count = size - *offp;
ret = count;
while (count) {
int n = sizeof(kbuf) > count ? count : sizeof(kbuf);
/* FIXME: error checking */
sd->ops->read(sd, start + *offp, kbuf, n);
if (copy_to_user(buf, kbuf, n))
return -EFAULT;
count -= n;
buf += n;
*offp += n;
}
return ret;
}
static const struct file_operations sdbfs_fops = {
.read = sdbfs_read,
};
static struct inode *sdbfs_iget(struct super_block *sb, int inum);
static struct dentry *sdbfs_lookup(struct inode *dir,
struct dentry *dentry, struct nameidata *nd)
{
printk("%s\n", __func__);
return NULL;
struct inode *ino = NULL;
struct sdbfs_inode *inode = container_of(dir, struct sdbfs_inode, ino);
struct sdb_device *s_d;
unsigned long inum = dir->i_ino & ~1;
int i, n, len;
n = be16_to_cpu(inode->s_i.sdb_records) - 1;
for (i = 0; i < n; i++) {
s_d = (struct sdb_device *)inode->files + i;
len = strlen(s_d->sdb_component.product.name);
if (len != dentry->d_name.len)
continue;
if (!strncmp(s_d->sdb_component.product.name,
dentry->d_name.name, len))
break;
}
if (i != n)
ino = sdbfs_iget(dir->i_sb, inum + SDB_SIZE * (i+1));
d_add(dentry, ino);
return 0;
}
static const struct inode_operations sdbfs_dir_inode_operations = {
static const struct inode_operations sdbfs_dir_iops = {
.lookup = sdbfs_lookup,
};
static struct kmem_cache *sdbfs_inode_cache;
static struct inode *sdbfs_alloc_inode(struct super_block *sb)
{
struct sdbfs_inode *inode;
printk("%s\n", __func__);
return NULL;
inode = kmem_cache_alloc(sdbfs_inode_cache, GFP_KERNEL);
if (!inode)
return NULL;
inode_init_once(&inode->ino);
printk("%s: return %p\n", __func__, &inode->ino);
return &inode->ino;
}
static void sdbfs_destroy_inode(struct inode *ino)
{
struct sdbfs_inode *inode;
printk("%s\n", __func__);
inode = container_of(ino, struct sdbfs_inode, ino);
kmem_cache_free(sdbfs_inode_cache, inode);
}
static const struct super_operations sdbfs_super_ops = {
......@@ -57,6 +160,72 @@ static const struct super_operations sdbfs_super_ops = {
.destroy_inode = sdbfs_destroy_inode,
};
static struct inode *sdbfs_iget(struct super_block *sb, int inum)
{
struct inode *ino;
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode;
uint32_t offset;
int i, j, n, len;
uint8_t *s;
printk("%s: inum %i\n", __func__, inum);
ino = iget_locked(sb, inum);
if (!ino)
return ERR_PTR(-ENOMEM);
if (!(ino->i_state & I_NEW))
return ino;
/* The inode number is the offset, but root ino is currently 1 */
offset = inum & ~1;
inode = container_of(ino, struct sdbfs_inode, ino);
n = sd->ops->read(sd, offset, &inode->s_d, SDB_SIZE);
if (n != SDB_SIZE)
return ERR_PTR(-EIO);
set_nlink(ino, 1);
ino->i_size = be64_to_cpu(inode->s_d.sdb_component.addr_last)
- be64_to_cpu(inode->s_d.sdb_component.addr_first) + 1;
ino->i_mtime.tv_sec = ino->i_atime.tv_sec = ino->i_ctime.tv_sec = 0;
ino->i_mtime.tv_nsec = ino->i_atime.tv_nsec = ino->i_ctime.tv_nsec = 0;
switch (inode->s_d.sdb_component.product.record_type) {
case sdb_type_interconnect:
printk("%s: interconnect\n", __func__);
ino->i_mode = S_IFDIR | 0555;
ino->i_op = &sdbfs_dir_iops;
ino->i_fop = &sdbfs_dir_fops;
/* We are an interconnect, so read the other records too */
len = be16_to_cpu(inode->s_i.sdb_records) * SDB_SIZE;
inode->files = kmalloc(len, GFP_KERNEL);
BUG_ON(!inode->files);
n = sd->ops->read(sd, offset + SDB_SIZE, inode->files, len);
BUG_ON(n != len);
for (i = 0; i < len / SDB_SIZE; i++) {
/* zero-terminate: the lost type is not a problem */
s = (struct sdb_device *)(inode->files)[i]
.sdb_component.product.name;
for (j = 19; j; j--) {
s[j] = '\0';
if (s[j-1] != ' ')
break;
}
}
break;
case sdb_type_device:
printk("%s: device\n", __func__);
/* FIXME: Which bus type is this? */
ino->i_mode = S_IFREG | 0444;
ino->i_fop = &sdbfs_fops;
break;
default:
BUG();
}
unlock_new_inode(ino);
return ino;
}
static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
......@@ -76,10 +245,10 @@ static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = SDB_MAGIC;
sb->s_op = &sdbfs_super_ops;
inode = iget_locked(sb, 1 /* FIXME: inode number */);
if (!inode) {
printk("no inode\n");
return -ENOMEM;
inode = sdbfs_iget(sb, 1 /* FIXME: root inode */);
if (IS_ERR(inode)) {
sdbfs_put(sd);
return PTR_ERR(inode);
}
/*
......@@ -87,8 +256,11 @@ static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
* after 3.2, but d_alloc_root was killed soon after 3.3
*/
root = d_make_root(inode);
if (!root)
if (!root) {
sdbfs_put(sd);
/* FIXME: release inode? */
return -ENOMEM;
}
root->d_fsdata = NULL; /* FIXME: d_fsdata */
sb->s_root = root;
return 0;
......@@ -97,15 +269,20 @@ static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
static struct dentry *sdbfs_mount(struct file_system_type *type, int flags,
const char *name, void *data)
{
struct dentry *ret;
char *fakedata = (char *)name;
/* HACK: use "name" as data, to use the mount_single helper */
return mount_single(type, flags, fakedata, sdbfs_fill_super);
ret = mount_single(type, flags, fakedata, sdbfs_fill_super);
printk("%s: %p\n", __func__, ret);
return ret;
}
static void sdbfs_kill_sb(struct super_block *sb)
{
struct sdbfs_dev *sd = sb->s_fs_info;
printk("%s\n", __func__);
kill_anon_super(sb);
if (sd)
sdbfs_put(sd);
......@@ -120,6 +297,9 @@ static struct file_system_type sdbfs_fs_type = {
static int sdbfs_init(void)
{
sdbfs_inode_cache = KMEM_CACHE(sdbfs_inode, 0);
if (!sdbfs_inode_cache)
return -ENOMEM;
return register_filesystem(&sdbfs_fs_type);
return 0;
}
......@@ -127,6 +307,7 @@ static int sdbfs_init(void)
static void sdbfs_exit(void)
{
unregister_filesystem(&sdbfs_fs_type);
kmem_cache_destroy(sdbfs_inode_cache);
}
module_init(sdbfs_init);
......
......@@ -49,6 +49,11 @@ int sdbfs_register_device(struct sdbfs_dev *sd)
if (!strcmp(osd->name, sd->name))
return -EBUSY;
list_add(&sd->list, &sdbfs_devlist);
list_for_each_entry(osd, &sdbfs_devlist, list)
printk("list entry %p\n", osd);
return 0;
}
EXPORT_SYMBOL(sdbfs_register_device);
......@@ -57,8 +62,14 @@ void sdbfs_unregister_device(struct sdbfs_dev *sd)
{
struct sdbfs_dev *osd;
list_for_each_entry(osd, &sdbfs_devlist, list)
printk("list entry %p\n", osd);
printk("removing %p\n", sd);
list_for_each_entry(osd, &sdbfs_devlist, list)
if (osd == sd)
list_del(&sd->list);
break;
if (osd == sd)
list_del(&sd->list);
}
EXPORT_SYMBOL(sdbfs_unregister_device);
......@@ -9,5 +9,17 @@
*/
#ifndef __SDBFS_INT_H__
#define __SDBFS_INT_H__
#include <linux/fs.h>
#include <linux/sdb.h>
struct sdbfs_inode {
union {
struct sdb_device s_d;
struct sdb_interconnect s_i;
struct sdb_bridge s_b;
};
struct sdb_device *files; /* Only used for directories */
struct inode ino;
};
#endif /* __SDBFS_INT_H__ */
......@@ -21,10 +21,10 @@ struct sdbfs_dev;
*/
struct sdbfs_dev_ops {
struct module *owner;
int (*erase)(struct sdbfs_dev *d, uint32_t begin, uint32_t end);
ssize_t (*read)(struct sdbfs_dev *d, uint32_t begin, u8 *buf,
int (*erase)(struct sdbfs_dev *sd, uint32_t begin, uint32_t end);
ssize_t (*read)(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count);
ssize_t (*write)(struct sdbfs_dev *d, uint32_t begin, u8 *buf,
ssize_t (*write)(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count);
};
......@@ -36,11 +36,11 @@ struct sdbfs_dev {
struct list_head list;
};
/* Internal inter-file calls */
struct sdbfs_dev *sdbfs_get_by_name(char *name);
void sdbfs_put(struct sdbfs_dev *sd);
/* Exported to other modules */
int sdbfs_register_device(struct sdbfs_dev *sd);
void sdbfs_unregister_device(struct sdbfs_dev *sd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment