On 5/1/13, Kumar amit mehta <gmate.a...@gmail.com> wrote:
> Hi,
>
> I'm new to block layer in linux and to learn the same, I'm trying to
> come up with a sample memory based block device driver, with which I can
> experiment and learn along the way. I'm referring to sample code from
> the linux tree [1] and assorted information available over the internet.
> My current module is causing system crash as soon I load it. Please take a
> look.
>
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/sched.h>
> #include <linux/blkdev.h>
> #include <linux/fs.h>
> /*
>  * 1: register the major number
>  * 2: register callback functions for various capabilities
>  * 3: register a request function
>  * 4: disks characteristics information; gendisk
>  */
>
> #define RAMDK_MAJOR   166 //unique but static on my current machine as of
> now   
> #define BLKDEV_NAME   "ramdk"
> #define RAMDK_MINOR_NR        1
>
> #define DISKSIZE 256*1024
> #define NSECTORS 512
> char buffer[DISKSIZE];
>
> static struct gendisk *rdk = NULL;
> static DEFINE_SPINLOCK(ramdk_sp_lock);
> static struct request_queue *ramdk_queue = NULL;
>
> int ramdk_open(struct block_device *, fmode_t);
> int ramdk_release(struct gendisk *, fmode_t);
>
> int ramdk_open(struct block_device *blk, fmode_t mode)
> {
>       printk(KERN_INFO "place holder for ramdisk's open method");
>       return 0;
> }
>
> int ramdk_release(struct gendisk *gdk, fmode_t mode)
> {
>       printk(KERN_INFO "place holder for ramdisk's release method");
>       return 0;
> }
>       
> static const struct block_device_operations ramdk_op = {
>       .owner = THIS_MODULE,
>       .open = ramdk_open,
>       .release = ramdk_release,
> };
>
> /*
>  * block devices do not provide read()/write() routines like the char
>  * devices, instead they use request callback.
>  */
> static void rdk_request(struct request_queue *q)
> {
>       struct request *rq;
>
>       /*
>        * look at a request and then dequeue it
>        */
>       rq = blk_fetch_request(q);
>       while (rq) {
>               unsigned long offset = blk_rq_pos(rq);
>               unsigned long nbytes  = blk_rq_cur_bytes(rq);
>               int err = 0;
>               while (nbytes) {
>                       if (rq_data_dir(rq) == READ) {
>                               memcpy(rq->buffer, (char *)offset, nbytes);
>                       } else if (rq_data_dir(rq) == WRITE) {
>                               memcpy((char *)offset, rq->buffer, nbytes);
>                       } else {
>                               printk(KERN_ERR "unknown operation\n");
>                       }
>                       nbytes -= offset;
>               }
>               if (!__blk_end_request_cur(rq, err))
>                       rq = blk_fetch_request(q);
>       }
>       return;
> }
>
> static int __init ramdk_init(void)
> {
>       int ret = -1;
>       /*
>        * blocking call. On success, assign an unused major number and add a
> entry in
>        * /proc/devices.
>        */
>       if (register_blkdev(RAMDK_MAJOR, BLKDEV_NAME))
>               return -EBUSY;
>
>         printk(KERN_INFO "registered block device %s with major: %d",
>               BLKDEV_NAME, RAMDK_MAJOR);
>
>       rdk = alloc_disk(RAMDK_MINOR_NR);
>       if (!rdk) {
>               ret = -ENOMEM;
>               goto disk_alloc_fail;
>       }
>
>       rdk->fops = &ramdk_op;
>       /*
>        * HW perform I/O in the multiples of sectors(512Bytes, typically),
> whereas SW(FS, etc)
>        * will work on block size(4k, typically). Therefore we need to tell the
> upper layers
>        * about the capability of the hardware. This also sets the maximum 
> number
> of sectors
>        * that my hardware can receive per request.
>        */
>       set_capacity(rdk, DISKSIZE*2); //Capacity, in terms of sectors
>       /*
>          * returns request queue for the block device. protected using spin
> lock
>          */
>       ramdk_queue = blk_init_queue(rdk_request, &ramdk_sp_lock);
>       if (!ramdk_queue)
>               goto queue_fail;
>
>       rdk->queue = ramdk_queue;
>       rdk->major = RAMDK_MAJOR;
>       rdk->first_minor = 0;
>       sprintf(rdk->disk_name, BLKDEV_NAME);
>       rdk->private_data = buffer;
>       /*
>        * Going live now!!!
>        */     
>       add_disk(rdk);
>       
>       return 0;
>
> queue_fail:
>       printk(KERN_ERR "failed to allocate queue for %s",BLKDEV_NAME);
>
> disk_alloc_fail:
>       unregister_blkdev(RAMDK_MAJOR, BLKDEV_NAME);
>       
>       return ret;
> }
>
> static void __exit ramdk_exit(void)
> {
>         del_gendisk(rdk);
>       put_disk(rdk);
>       blk_cleanup_queue(ramdk_queue);
>       unregister_blkdev(RAMDK_MAJOR, BLKDEV_NAME);
>       printk(KERN_INFO "%s is offline now!!!",BLKDEV_NAME);
> }
>
> module_init(ramdk_init);
> module_exit(ramdk_exit);
> MODULE_LICENSE("GPL v2");
> MODULE_AUTHOR("goon");
>
> Once this issue is fixed, I plan to add support for filesystem related
> operations such as mkfs, mount, etc.
>
> [1] drivers/block/z2ram.c
>
> -Amit
>
> _______________________________________________
> Kernelnewbies mailing list
> Kernelnewbies@kernelnewbies.org
> http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>

Hey Amit,

I'm not sure about what's wrong with it, but why not try to process
each segment separately. i know it's more work but you should plan for
that too.
In the mean time you can look at

https://github.com/pranjas/block_driver

I wrote this sometime back and its commented heavily. its also for in
memory disk but you can set the block device sector size other than
512 bytes.

You might get a freeze kernel or crash when u unload it lemme know if
that happens, or change the blk_end_request call to
blk_end_request_all.

Hope it helps
                   -P.K.S


-- 
Pranay Srivastava

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

Reply via email to