Hi,
On Sun, 13 Jan 2008, Petr Stehlik wrote:
Stephen R Marenka píše v So 12. 01. 2008 v 09:55 -0600:
Hopefully this patch includes all the of feedback from the last one.
This patch adds a character device driver to allow user space access
to the aranym natfeats nfstderr.
BTW, I am amazed by simplicity of the patch and am wondering if it is
similarly simple to write a disk driver (to avoid the IDE emulation in
ARAnyM).
Below is my last version I was experimenting with. There is still
somewhere a stack corruption or overflow (it's easy to trigger with
"hdparm -tT /dev/...").
That reminds me, that aranym needs a fix here in src/natfeat/xhdi.cpp
(fseeko instead of fseek) so devices larger than 2GB aren't corrupted.
The speed doesn't seem to be drastically faster (only twice as fast last I
tested with a simple dd). One reason may be that xhdi.cpp opens the file
for every single request and asynchronous requests might help too.
bye, Roman
---
arch/m68k/emu/Makefile | 1
arch/m68k/emu/nfblock.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 217 insertions(+)
Index: linux-2.6/arch/m68k/emu/Makefile
===================================================================
--- linux-2.6.orig/arch/m68k/emu/Makefile
+++ linux-2.6/arch/m68k/emu/Makefile
@@ -3,5 +3,6 @@
#
obj-y += natfeat.o
+obj-y += nfblock.o
obj-$(CONFIG_NFETH) += nfeth.o
Index: linux-2.6/arch/m68k/emu/nfblock.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/m68k/emu/nfblock.c
@@ -0,0 +1,216 @@
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <asm/natfeat.h>
+
+static long nfhd_id;
+
+static LIST_HEAD(nfhd_list);
+
+static int major_num = 0;
+module_param(major_num, int, 0);
+
+struct nfhd_device {
+ struct list_head list;
+ int id;
+ u32 blocks, bsize;
+ int bshift;
+ struct request_queue *queue;
+ struct gendisk *disk;
+};
+
+#if 0
+static void nfhd_request(request_queue_t *q)
+{
+ struct nfhd_device *dev;
+ struct gendisk *disk;
+ struct request *req;
+ long res;
+
+ while ((req = elv_next_request(q)) != NULL) {
+ if (!blk_fs_request(req)) {
+ printk(KERN_NOTICE "Skip non-CMD request\n");
+ end_request(req, 0);
+ continue;
+ }
+ disk = req->rq_disk;
+ dev = disk->private_data;
+ res = nf_call(nfhd_id + 10, dev->id, 0, rq_data_dir(req), req->sector, req->current_nr_sectors, req->buffer);
+ end_request(req, res == 0);
+ }
+}
+#endif
+
+static int nfhd_make_request(request_queue_t *queue, struct bio *bio)
+{
+ struct nfhd_device *dev = queue->queuedata;
+ struct bio_vec *bvec;
+ int i, dir, len, size, shift;
+ sector_t sec = bio->bi_sector;
+
+ dir = bio_data_dir(bio);
+ shift = dev->bshift;
+ size = 0;
+ bio_for_each_segment(bvec, bio, i) {
+ len = bvec->bv_len;
+ size += len;
+ len >>= 9;
+ //printk("io: %u,%lu,%u\n", dir, sec, len);
+ nf_call(nfhd_id + 10, dev->id, 0, dir,
+ sec >> shift, len >> shift, bvec_to_phys(bvec));
+ sec += len;
+ }
+ bio_endio(bio, size, 0);
+ return 0;
+}
+
+int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct nfhd_device *dev = bdev->bd_disk->private_data;
+
+ geo->cylinders = dev->blocks / (64 >> dev->bshift);
+ geo->heads = 4;
+ geo->sectors = 16;
+
+ return 0;
+}
+
+#if 0
+int nfhd_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct nfhd_device *dev;
+ struct gendisk *disk;
+ struct hd_geometry geo;
+ long size;
+
+ disk = I_BDEV(inode)->bd_disk;
+ dev = disk->private_data;
+
+ switch (cmd) {
+ case HDIO_GETGEO:
+ size = dev->blocks * (dev->bsize / 512);
+ geo.cylinders = size / 64;
+ geo.heads = 4;
+ geo.sectors = 16;
+ geo.start = 4;
+ if (copy_to_user((void *) arg, &geo, sizeof(geo)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -ENOTTY;
+}
+#endif
+
+static struct block_device_operations nfhd_ops = {
+ .owner = THIS_MODULE,
+ .ioctl = blkdev_ioctl,
+ .getgeo = nfhd_getgeo,
+};
+
+static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
+{
+ struct nfhd_device *dev;
+ int dev_id = id - 8;
+
+ printk(KERN_INFO "nfhd%u: found device with %u blocks (%u bytes)\n", dev_id, blocks, bsize);
+
+ if (bsize < 512 || (bsize & (bsize - 1))) {
+ printk(KERN_WARNING "nfhd%u: invalid block size\n", dev_id);
+ return -EINVAL;
+ }
+
+ dev = kmalloc(sizeof(struct nfhd_device), GFP_KERNEL);
+ if (!dev)
+ goto out;
+
+ dev->id = id;
+ dev->blocks = blocks;
+ dev->bsize = bsize;
+ dev->bshift = ffs(bsize) - 10;
+
+ dev->queue = blk_alloc_queue(GFP_KERNEL);
+ if (dev->queue == NULL)
+ goto free_dev;
+
+ dev->queue->queuedata = dev;
+ blk_queue_make_request(dev->queue, nfhd_make_request);
+ blk_queue_hardsect_size(dev->queue, bsize);
+
+ dev->disk = alloc_disk(16);
+ if (!dev->disk)
+ goto free_queue;
+
+ dev->disk->major = major_num;
+ dev->disk->first_minor = dev_id * 16;
+ dev->disk->fops = &nfhd_ops;
+ dev->disk->private_data = dev;
+ sprintf(dev->disk->disk_name, "nfhd%u", dev_id);
+ set_capacity(dev->disk, blocks * (bsize / 512));
+ dev->disk->queue = dev->queue;
+
+ add_disk(dev->disk);
+
+ list_add_tail(&dev->list, &nfhd_list);
+
+ return 0;
+
+free_queue:
+ blk_cleanup_queue(dev->queue);
+free_dev:
+ kfree(dev);
+out:
+ return -ENOMEM;
+}
+
+static int __init nfhd_init(void)
+{
+ u32 blocks, bsize;
+ int i;
+
+ nfhd_id = nf_get_id("XHDI");
+ if (!nfhd_id)
+ return -ENODEV;
+
+ major_num = register_blkdev(major_num, "nfhd");
+ if (major_num <= 0) {
+ printk(KERN_WARNING "nfhd: unable to get major number\n");
+ return -ENODEV;
+ }
+
+ for (i = 8; i < 24; i++) {
+ if (nf_call(nfhd_id + 14, i, 0, &blocks, &bsize))
+ continue;
+ nfhd_init_one(i, blocks, bsize);
+ }
+
+ return 0;
+}
+
+static void __exit nfhd_exit(void)
+{
+ struct nfhd_device *dev, *next;
+
+ list_for_each_entry_safe(dev, next, &nfhd_list, list) {
+ del_gendisk(dev->disk);
+ put_disk(dev->disk);
+ blk_cleanup_queue(dev->queue);
+ kfree(dev);
+ }
+ unregister_blkdev(major_num, "nfhd");
+}
+
+late_initcall(nfhd_init);
+module_exit(nfhd_exit);
+
+MODULE_LICENSE("GPL");