kernel panic in sample block device driver
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
kernel panic logs? On Wed, May 1, 2013 at 10:57 AM, Kumar amit mehta <gmate.amit@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
On 5/1/13, Kumar amit mehta <gmate.amit@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
On Wed, May 01, 2013 at 10:24:40PM +0530, Pranay Srivastava wrote:
Thank you so much, looks pretty heavy-duty right now though!!!
participants (3)
-
anish singh -
Kumar amit mehta -
Pranay Srivastava