[SOLVED] Missing /dev/ special file after I register a block device
Linux - KernelThis forum is for all discussion relating to the Linux kernel.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
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);
Am just taking a wild guess you might have already tried this.
from your code it seems you are allocating the major number statically(240) may be you can check if the number is already being used by some other driver.
regarding second post, if you are asking can we created the special files ourselves using mknod manually, then yes we sure can ( you will have to be root) .
Well, my other driver (the one I'm doing the real work on) is asking for the major number to be assigned by the kernel... and the device fails to be created there as well... so it's not because the major could be taken.
Also, I tried with mknod and apparently it works... I still have a lot to learn before I'm able to do something useful from the block layer API.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.