Commit 69de5015 authored by Alessandro Rubini's avatar Alessandro Rubini

sdbfs/kernel: major restructuring of the code


This a major thing, that changes a lot. However, now directories work
properly and the code is generally cleaner. This is what I get,
for example, for the wr-nic release gateware on a SPEC:

  spusa.root# find /mnt
  /mnt
  /mnt/WB4-Crossbar-GSI
  /mnt/WR-CORE
  /mnt/WR-CORE/WB4-Crossbar-GSI
  /mnt/WR-CORE/WB4-BlockRAM
  /mnt/WR-CORE/WB4-Bridge-GSI
  /mnt/WR-CORE/WB4-Bridge-GSI/WB4-Crossbar-GSI
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Mini-NIC
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Endpoint
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Soft-PLL
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-PPS-Generator
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Periph-Syscon
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Periph-UART
  /mnt/WR-CORE/WB4-Bridge-GSI/WR-Periph-1Wire
  /mnt/WR-CORE/WB4-Bridge-GSI/WB4-Streaming-DMA_0
  /mnt/WR-NIC
  /mnt/WB-VIC-Int.Control
  /mnt/WR-TXTSU
  /mnt/WR-DIO-Core
  /mnt/WR-DIO-Core/WB4-Crossbar-GSI
  /mnt/WR-DIO-Core/WR-1Wire-master
  /mnt/WR-DIO-Core/WB-I2C-Master
  /mnt/WR-DIO-Core/WB-GPIO-Port
  /mnt/WR-DIO-Core/WR-DIO-Registers
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 2ddf00b9
......@@ -35,31 +35,120 @@ static void sdbfs_fix_endian(struct sdbfs_dev *sd, void *ptr, int len)
p[i] = htonl(p[i]);
}
/* This is called by readdir and by lookup, when needed */
static int sdbfs_read_whole_dir(struct sdbfs_inode *inode)
{
struct sdbfs_info *info;
struct super_block *sb = inode->ino.i_sb;
struct sdbfs_dev *sd = sb->s_fs_info;
unsigned long offset;
int i, j, n;
if (inode->nfiles)
return 0;
printk("%s\n", __func__);
/* Get the interconnect and see how many */
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
n = sd->ops->read(sd, inode->base_sdb, &info->s_i, SDB_SIZE);
if (n != SDB_SIZE) {
kfree(info);
return -EIO;
}
sdbfs_fix_endian(sd, &info->s_i, SDB_SIZE);
if (info->s_i.sdb_magic != htonl(SDB_MAGIC)) {
pr_err("%s: wrong magic (%08x) at offset 0x%lx\n", __func__,
info->s_i.sdb_magic, inode->base_sdb);
kfree(info);
return -EINVAL;
}
inode->nfiles = be16_to_cpu(info->s_i.sdb_records);
kfree(info);
printk("nfiles %i\n", inode->nfiles);
info = kmalloc(sizeof(*info) * inode->nfiles, GFP_KERNEL);
if (!info) {
inode->nfiles = 0;
return -ENOMEM;
}
offset = inode->base_sdb;
printk("reading at 0x%lx\n", offset);
inode->files = info;
for (i = 0; i < inode->nfiles; i++) {
info = inode->files + i;
n = sd->ops->read(sd, offset, &info->s_d, SDB_SIZE);
if (n != SDB_SIZE) {
/* FIXME: iput? */
kfree(inode->files);
inode->nfiles = 0;
return -EIO;
}
sdbfs_fix_endian(sd, &info->s_d, SDB_SIZE);
strncpy(info->name,
info->s_d.sdb_component.product.name, 19);
for (j = 19; j; j--) {
info->name[j] = '\0';
if (info->name[j-1] != ' ')
break;
}
info->namelen = j;
offset += SDB_SIZE;
}
return 0;
}
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 sdbfs_info *info;
unsigned long file_off = filp->f_pos;
unsigned long offset = ino->i_ino & ~1;
int i, n;
unsigned long offset;
int i, type, done = 0;
printk("%s\n", __func__);
inode = container_of(ino, struct sdbfs_inode, ino);
n = inode->nfiles;
/* dot and dotdot are special */
if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, 0, ino->i_ino, DT_DIR) < 0)
return done;
done++;
filp->f_pos++;
}
if (filp->f_pos == 1) {
if (filldir(dirent, "..", 2, 1,
parent_ino(filp->f_dentry), DT_DIR) < 0)
return done;
done++;
filp->f_pos++;
}
for (i = file_off; i < n; i++) {
/* Then our stuff */
inode = container_of(ino, struct sdbfs_inode, ino);
sdbfs_read_whole_dir(inode);
offset = inode->base_sdb;
offset += SDB_SIZE; /* new inode number */
for (i = filp->f_pos - 2; i < inode->nfiles; i++) {
info = inode->files + i;
if (info->s_e.record_type == sdb_type_bridge)
type = DT_DIR;
else
type = DT_REG;
if (filldir(dirent, info->name, info->namelen,
offset, offset, DT_UNKNOWN) < 0)
return i;
SDBFS_INO(offset), i + 2 /* ? */, type) < 0)
return done;
filp->f_pos++;
done++;
}
return i;
return done;
}
static const struct file_operations sdbfs_dir_fops = {
......@@ -115,7 +204,8 @@ static ssize_t sdbfs_read(struct file *f, char __user *buf, size_t count,
static const struct file_operations sdbfs_fops = {
.read = sdbfs_read,
};
static struct inode *sdbfs_iget(struct super_block *sb, int inum);
static struct inode *sdbfs_iget(struct sdbfs_inode *parent,
struct super_block *sb, unsigned long inum);
static struct dentry *sdbfs_lookup(struct inode *dir,
struct dentry *dentry, struct nameidata *nd)
......@@ -123,9 +213,11 @@ static struct dentry *sdbfs_lookup(struct inode *dir,
struct inode *ino = NULL;
struct sdbfs_inode *inode = container_of(dir, struct sdbfs_inode, ino);
struct sdbfs_info *info;
unsigned long inum = dir->i_ino & ~1;
unsigned long offset = inode->base_sdb;
int i, n, len;
printk("%s\n", __func__);
sdbfs_read_whole_dir(inode);
n = inode->nfiles;
len = dentry->d_name.len;
for (i = 0; i < n; i++) {
......@@ -135,8 +227,10 @@ static struct dentry *sdbfs_lookup(struct inode *dir,
if (!strncmp(info->name, dentry->d_name.name, len))
break;
}
if (i != n)
ino = sdbfs_iget(dir->i_sb, inum + SDB_SIZE * (i+1));
if (i != n) {
offset = offset + SDB_SIZE * i;
ino = sdbfs_iget(inode, dir->i_sb, SDBFS_INO(offset));
}
d_add(dentry, ino);
return 0;
}
......@@ -174,86 +268,92 @@ static const struct super_operations sdbfs_super_ops = {
.destroy_inode = sdbfs_destroy_inode,
};
static struct inode *sdbfs_iget(struct super_block *sb, int inum)
static struct inode *sdbfs_iget_root(struct super_block *sb,
struct inode *ino)
{
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode = container_of(ino, struct sdbfs_inode, ino);
struct sdb_bridge *b = &inode->info.s_b;
/* The root directory is a fake "bridge" structure */
memset(b, 0, sizeof(*b));
b->sdb_child = cpu_to_be64(sd->entrypoint);
b->sdb_component.addr_first = 0;
b->sdb_component.addr_last = cpu_to_be64(sd->size);
b->sdb_component.product.record_type = sdb_type_bridge;
/* So, this is a directory, and it links to the first interconnect */
inode->base_data = 0;
inode->base_sdb = sd->entrypoint;
ino->i_size = sd->size;
ino->i_mode = S_IFDIR | 0555;
ino->i_op = &sdbfs_dir_iops;
ino->i_fop = &sdbfs_dir_fops;
return ino;
}
static struct inode *sdbfs_iget(struct sdbfs_inode *parent,
struct super_block *sb, unsigned long inum)
{
struct inode *ino;
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode;
struct sdbfs_info *info;
uint32_t offset;
int i, j, n, len;
unsigned long size, base_data; /* target offset */
int n;
int type;
printk("%s: inum %i\n", __func__, inum);
printk("%s: inum 0x%lx\n", __func__, inum);
ino = iget_locked(sb, inum);
if (!ino)
return ERR_PTR(-ENOMEM);
if (!(ino->i_state & I_NEW))
return ino;
/* The inum is the offset, but to avoid 0 we set the LSB */
offset = inum & ~1;
/* general setup; no link concept: the structure is immutable */
set_nlink(ino, 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;
if (unlikely(!parent)) { /* inum == SDBFS_ROOT */
sdbfs_iget_root(sb, ino);
unlock_new_inode(ino);
return ino;
}
inode = container_of(ino, struct sdbfs_inode, ino);
offset = SDBFS_OFFSET(inum);
n = sd->ops->read(sd, offset, &inode->info.s_d, SDB_SIZE);
if (n != SDB_SIZE)
return ERR_PTR(-EIO);
sdbfs_fix_endian(sd, &inode->info.s_d, SDB_SIZE);
set_nlink(ino, 1);
ino->i_size = be64_to_cpu(inode->info.s_d.sdb_component.addr_last)
- be64_to_cpu(inode->info.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;
type = inode->info.s_d.sdb_component.product.record_type;
base_data = be64_to_cpu(inode->info.s_d.sdb_component.addr_first);
size = be64_to_cpu(inode->info.s_d.sdb_component.addr_last)
- base_data + 1;
type = inode->info.s_e.record_type;
switch (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 */
inode->nfiles = be16_to_cpu(inode->info.s_i.sdb_records);
len = inode->nfiles * sizeof(*info);
inode->files = kzalloc(len, GFP_KERNEL);
if (!inode->files) {
/* FIXME: iput? */
return ERR_PTR(-ENOMEM);
}
/* FIXME: add dot and dotdot, and maybe named-dot */
for (i = 0; i < inode->nfiles; i++) {
offset += SDB_SIZE;
info = inode->files + i;
n = sd->ops->read(sd, offset, &info->s_d, SDB_SIZE);
if (n != SDB_SIZE) {
/* FIXME: iput? */
kfree(inode->files);
return ERR_PTR(-EIO);
}
sdbfs_fix_endian(sd, &info->s_d, SDB_SIZE);
strncpy(info->name,
info->s_d.sdb_component.product.name, 19);
for (j = 19; j; j--) {
info->name[j] = '\0';
if (info->name[j-1] != ' ')
break;
}
info->namelen = j;
}
break;
case sdb_type_device:
printk("%s: device\n", __func__);
/* FIXME: Which bus type is this? */
/* You can access internal registers/data */
ino->i_fop = &sdbfs_fops; /* FIXME: Which bus type? */
ino->i_mode = S_IFREG | 0444;
ino->i_fop = &sdbfs_fops;
ino->i_size = size;
inode->base_data = parent->base_data + base_data;
break;
case sdb_type_bridge:
printk("%s: bridge to %llx (unsupported yet)\n", __func__,
ntohll(inode->info.s_b.sdb_child));
/* A bridge is a subdirectory */
ino->i_mode = S_IFDIR | 0555;
ino->i_op = &sdbfs_dir_iops;
ino->i_fop = &sdbfs_dir_fops;
inode->base_data = parent->base_data + base_data;
inode->base_sdb = parent->base_data
+ be64_to_cpu(inode->info.s_b.sdb_child);
break;
default:
......@@ -276,6 +376,8 @@ static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
struct sdbfs_dev *sd;
uint32_t magic;
printk("%s\n", __func__);
/* HACK: this data is really a name */
sd = sdbfs_get_by_name(data);
if (IS_ERR(sd))
......@@ -301,7 +403,8 @@ 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 = sdbfs_iget(sb, sd->entrypoint + 1 /* can't be zero */);
/* The root inode is 1. It is a fake bridge and has no parent. */
inode = sdbfs_iget(NULL, sb, SDBFS_ROOT);
if (IS_ERR(inode)) {
sdbfs_put(sd);
return PTR_ERR(inode);
......
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