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 = ""> 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 = ""> 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"); |
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@xxxxxxxxxxxxxxxxx http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies