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