add_disk() make my driver's initialisation, thus kernel stall.
张云
zyunone at 163.com
Sun Mar 20 04:38:12 EDT 2016
Hi,
My memory disk block driver was compiled successfully.
But when I insmod my module, initialisation stall at add_disk in setup_dev function.
What’s wrong with my gendisk setup code?
Thanks.
static void setup_dev(struct blkplay_dev *dev, int which)
{
// setup disk size
memset(dev, 0, sizeof(struct blkplay_dev));
dev->size = nsectors * hardsect_size;
dev->data = vmalloc(dev->size);
if (dev->data == NULL) {
printk(KERN_NOTICE "vmalloc failure.\n");
return;
}
// init request queue
spin_lock_init(&dev->lock);
dev->queue = blk_init_queue(blkplay_request, &dev->lock);
if (dev->queue == NULL) {
printk(KERN_NOTICE "init queue failure.\n");
goto out_vfree;
}
//blk_queue_logical_block_size(dev->queue, hardsect_size);
dev->queue->queuedata = dev;
dev->gd = alloc_disk(BLKPLAY_MINORS);
if (!dev->gd) {
printk(KERN_NOTICE "alloc_disk failure!\n");
goto out_vfree;
}
dev->gd->major = major;
dev->gd->first_minor = which * BLKPLAY_MINORS;
dev->gd->fops = &blkplay_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
snprintf(dev->gd->disk_name, 32, "blkplay%c", which + 'a');
set_capacity(dev->gd, nsectors * (hardsect_size/KERNEL_SECTOR_SIZE));
printk(KERN_ALERT "5\n”);
// *********************************************
// initialisation stall at the statement below.
// *********************************************
add_disk(dev->gd);
printk(KERN_ALERT "6\n");
return;
out_vfree:
if (dev->data)
vfree(dev->data);
}
The whole module code:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/bio.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "debug.h"
#define BLKPLAY_MINORS 16
#define KERNEL_SECTOR_SIZE 512
#define DEVICE_NUMBER 1
int major = 0;
int nsectors = 1024;
int hardsect_size = 512;
static const char *module_name = "blkplay";
struct blkplay_dev {
int size;
uint8_t *data;
spinlock_t lock;
struct request_queue *queue;
struct gendisk *gd;
};
struct blkplay_dev * devices;
int blkplay_open(struct block_device *dev, fmode_t mode)
{
return 0;
}
void blkplay_release(struct gendisk *disk, fmode_t mode)
{
}
/*
* Handle an I/O request.
*/
static void blkplay_transfer(struct blkplay_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*KERNEL_SECTOR_SIZE;
unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;
if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else
memcpy(buffer, dev->data + offset, nbytes);
}
/*
* Transfer a single BIO.
*/
static int vmem_disk_xfer_bio(struct blkplay_dev *dev, struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
sector_t sector = bio->bi_iter.bi_sector;
bio_for_each_segment(bvec, bio, iter) {
char *buffer = __bio_kmap_atomic(bio, iter);
blkplay_transfer(dev, sector, bio_cur_bytes(bio) >> 9,
buffer, bio_data_dir(bio) == WRITE);
sector += bio_cur_bytes(bio) >> 9;
__bio_kunmap_atomic(buffer);
}
return 0;
}
void blkplay_request(struct request_queue *q)
{
struct request *req;
struct bio *bio;
while (!blk_queue_stopped(q) &&
(req = blk_peek_request(q)) != NULL) {
struct blkplay_dev *dev = req->rq_disk->private_data;
blk_start_request(req);
if (req->cmd_type != REQ_TYPE_FS) {
printk (KERN_NOTICE "Skip non-fs request\n");
blk_end_request_all(req, -EIO);
continue;
}
__rq_for_each_bio(bio, req)
vmem_disk_xfer_bio(dev, bio);
blk_end_request_all(req, 0);
}
}
const struct block_device_operations blkplay_ops = {
//.owner = THIS_MODULE,
//.open = blkplay_open,
//.release = blkplay_release,
};
static void release_dev(struct blkplay_dev *dev)
{
del_gendisk(dev->gd);
put_disk(dev->gd);
blk_cleanup_queue(dev->queue);
vfree(dev->data);
}
static void setup_dev(struct blkplay_dev *dev, int which)
{
// setup disk size
memset(dev, 0, sizeof(struct blkplay_dev));
dev->size = nsectors * hardsect_size;
dev->data = vmalloc(dev->size);
if (dev->data == NULL) {
printk(KERN_NOTICE "vmalloc failure.\n");
return;
}
// init request queue
spin_lock_init(&dev->lock);
dev->queue = blk_init_queue(blkplay_request, &dev->lock);
if (dev->queue == NULL) {
printk(KERN_NOTICE "init queue failure.\n");
goto out_vfree;
}
//blk_queue_logical_block_size(dev->queue, hardsect_size);
dev->queue->queuedata = dev;
dev->gd = alloc_disk(BLKPLAY_MINORS);
if (!dev->gd) {
printk(KERN_NOTICE "alloc_disk failure!\n");
goto out_vfree;
}
dev->gd->major = major;
dev->gd->first_minor = which * BLKPLAY_MINORS;
dev->gd->fops = &blkplay_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
snprintf(dev->gd->disk_name, 32, "blkplay%c", which + 'a');
set_capacity(dev->gd, nsectors * (hardsect_size/KERNEL_SECTOR_SIZE));
printk(KERN_ALERT "5\n");
add_disk(dev->gd);
printk(KERN_ALERT "6\n");
return;
out_vfree:
if (dev->data)
vfree(dev->data);
}
static int __init blkplay_init(void)
{
int i;
int ret;
major = register_blkdev(major, module_name);
if (0 >= major )
{
goto reg_blkplay_fail;
} else {
printk(KERN_ALERT "Allocate major number %d\n", major);
}
PDEBUG("Init success!\n");
devices = kmalloc(DEVICE_NUMBER * sizeof(struct blkplay_dev), GFP_KERNEL);
if (devices == NULL) {
printk(KERN_ALERT "Allocate memory for devices failure.\n");
}
for (i = 0; i < DEVICE_NUMBER; i++)
{
printk(KERN_ALERT "Set up device for %d\n", i);
setup_dev(devices + i, i);
}
return 0;
reg_blkplay_fail:
PDEBUG("Init Error!\n");
return ret;
}
static void __exit blkplay_exit(void)
{
int i;
for (i = 0; i < DEVICE_NUMBER; i++)
{
release_dev(&devices[i]);
}
unregister_blkdev(major, module_name);
kfree(devices);
PDEBUG("Exit.\n");
}
module_init(blkplay_init);
module_exit(blkplay_exit);
MODULE_LICENSE("Dual GPL/BSD");
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20160320/c38d4d40/attachment-0001.html
More information about the Kernelnewbies
mailing list