eantoranz |
04-16-2011 12:35 PM |
Missing /dev/ special file after I register a block device
Hi!
I'm working on a block device of my own. I'm playing with it inside UML (had to compile UML by hand in order to have module support) and I realized that when I load it, I don't get to see the /dev/ special file I create for it. Just in case, I revisited the sbull driver and it failed to create the special device as well... and then, just to make sure the problem is in UML, I tried loading the sbull driver on the UML host (ubuntu maverick) and the device does show up... so it's something in UML, right? What did I miss when I compiled it?
Thanks in advance.
Here's the sbull code I'm using:
Code:
/*
* Mini-block driver.
*
* Este código está basado en el ejemplo de LWN.NET: http://lwn.net/Articles/31513/
*
* Copyright 2003 Eklektix, Inc. Redistributable under the terms
* of the GNU GPL.
*
* Actualizacion por parte de Edmundo Carmona <eantoranz@gmail.com>
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
MODULE_LICENSE("Dual BSD/GPL");
/*
* Algunos valores que podrian haber
* sido parametrizables.
*/
#define KERNEL_SECTOR_SIZE 512
#define MAJOR_NUM 240 /* un major number libre, segun devices.txt */
#define MINIBD_MINORS 16 /* numero de particiones posibles */
#define N_SECTORS 1024 /* el numero de sectores de nuestro block device */
#define MINIBLOCK_SECTOR_SIZE 512 /* nuestro tammanyo de sector */
/*
* La cola de peticiones del mini-block.
*/
static struct request_queue *miniblock_queue;
/*
* Representacion interna de nuestro device.
*/
static struct miniblock_device {
unsigned long size;
spinlock_t lock;
u8 *data;
struct gendisk *gd;
};
static struct miniblock_device *Miniblock = NULL;
/*
* Manipulacion real en nuestro dispositivo de las I/O request.
*/
static void miniblock_transfer(struct miniblock_device *dev, struct request * req)
{
unsigned long offset = blk_rq_pos(req) * MINIBLOCK_SECTOR_SIZE;
unsigned long nbytes = blk_rq_cur_sectors(req) * MINIBLOCK_SECTOR_SIZE;
printk(KERN_ERR "minibd: desplazamiento peticion: %d tama\%o: %d\n", offset, nbytes);
if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "minibd: escritura por encima del final (%ld %ld)\n", offset, nbytes);
return;
}
if (rq_data_dir(req))
memcpy(dev->data + offset, req->buffer, nbytes);
else
memcpy(req->buffer, dev->data + offset, nbytes);
}
/*
* Manipulacion de las I/O request.
*/
static void miniblock_request(struct request_queue *q)
{
struct request *req;
while ((req = blk_fetch_request(q)) != NULL) {
if (!req->cmd_type != REQ_TYPE_FS) {
printk (KERN_NOTICE "Skip non-CMD request\n");
__blk_end_request_all(req, 0);
continue;
}
miniblock_transfer(Miniblock, req);
__blk_end_request_all(req, 1);
}
}
/*
* Ioctls perosonalizadas para nuestro device.
*/
int miniblock_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;
switch(cmd) {
case HDIO_GETGEO:
size = Miniblock->size*(MINIBLOCK_SECTOR_SIZE/KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}
return -ENOTTY;
}
/*
* Operaciones asociadas a nuestro dispositivo.
*/
static struct block_device_operations miniblock_ops = {
.owner = THIS_MODULE,
.ioctl = miniblock_ioctl
};
/*
* Inicializacion del modulo.
*/
static int __init miniblock_init(void)
{
static int ret;
ret = register_blkdev(MAJOR_NUM, "minibd");
if (ret < 0) {
printk(KERN_WARNING "minibd: error en asignacion de major number\n");
return -EBUSY;
}
printk(KERN_DEBUG "minibd: registrado con exito\n");
Miniblock = kmalloc(sizeof(struct miniblock_device), GFP_KERNEL);
if (Miniblock == NULL) {
printk(KERN_WARNING "minidb: error asignando memoria con kmalloc\n");
goto out_unregister;
}
/*
* Inicializamos nuestro device.
*/
memset(Miniblock, 0, sizeof(struct miniblock_device));
Miniblock->size = N_SECTORS*MINIBLOCK_SECTOR_SIZE;
Miniblock->data = vmalloc(Miniblock->size);
if (Miniblock->data == NULL) {
printk(KERN_WARNING "minidb: error asignando memoria con vmalloc\n");
kfree(Miniblock);
goto out_unregister;
}
spin_lock_init(&Miniblock->lock);
/*
* Creamos nuestra request queue asociada (una por block device).
*/
miniblock_queue = blk_init_queue(miniblock_request, &Miniblock->lock);
if (miniblock_queue == NULL) {
printk(KERN_WARNING "minibd: error en blk_init_queue\n");
goto out_free;
}
blk_queue_logical_block_size(miniblock_queue, MINIBLOCK_SECTOR_SIZE);
/*
* Rellenamos nuestra gendisk structure.
*/
Miniblock->gd = alloc_disk(MINIBD_MINORS);
if (!Miniblock->gd) {
printk(KERN_WARNING "minibd: error en alloc_disk\n");
goto out_free;
}
Miniblock->gd->major = MAJOR_NUM;
Miniblock->gd->first_minor = 0;
Miniblock->gd->fops = &miniblock_ops;
Miniblock->gd->private_data = Miniblock;
snprintf(Miniblock->gd->disk_name, 10, "%s", "minibd0");
set_capacity(Miniblock->gd, N_SECTORS*(MINIBLOCK_SECTOR_SIZE/KERNEL_SECTOR_SIZE));
Miniblock->gd->queue = miniblock_queue;
add_disk(Miniblock->gd); // <- Here is where the registration takes place
return 0;
out_free:
vfree(Miniblock->data);
kfree(Miniblock);
out_unregister:
unregister_blkdev(MAJOR_NUM, "minibd");
return -ENOMEM;
}
/*
* Descarga del modulo.
*/
static void __exit miniblock_exit(void)
{
del_gendisk(Miniblock->gd);
put_disk(Miniblock->gd);
unregister_blkdev(MAJOR_NUM, "minibd");
blk_cleanup_queue(miniblock_queue);
vfree(Miniblock->data);
kfree(Miniblock);
printk(KERN_DEBUG "minibd: descargado con exito\n");
}
module_init(miniblock_init);
module_exit(miniblock_exit);
Thanks in advance.
|