Simulating the REMOVABLE media - Could any one please suggest me.

From: Srinivas G.
Date: Wed Apr 26 2006 - 02:37:55 EST


Dear All,

I am facing a problem while simulating a removable media via simple
block driver. But if I remove the floppy disk after mounting it, I could
not get any problem with the floppy disk. But I do not understand why I
am facing the problem with my device.

I prepared an IOCTL to simulate the removable media to the kernel.
When the applications issues IOCTL, it removes the device from the
kernel space.

when I issue #ls /mnt (mount point) ( i.e. after the application issues
the IOCTL) the CONSOLE crashes, OR it crashes when tried to unload the
module.

I have been trying hard to understand the real problem with this module.

What wrong am I doing in this module?
Could any body explain the problem? Thanks in advance.

Thanks and Regards,
Srinivas G


Here is the module code for your reference.
-------------------------------------------

/*
* A sample, extra-simple block driver.
*
* Copyright 2003 Eklektix, Inc. Redistributable under the terms
* of the GNU GPL.
*/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/buffer_head.h> /* for invalidate_bdev */

#include "sbd_drv.h"

MODULE_LICENSE("Dual BSD/GPL");
//static char *Version = "0.1";

static int major_num = 0;
module_param(major_num, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);

/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512

/*
* Our request queue.
*/
static struct request_queue *Queue;

/*
* The internal representation of our device.
*/
static struct sbd_device {
unsigned long size;
spinlock_t lock;
u8 *data;
struct gendisk *gd;
struct block_device *bdev;
} Device;

static int
sbd_open(struct inode *inode, struct file *filp)
{
printk("<%s> invoked\n",__FUNCTION__);

Device.bdev=inode->i_bdev;

return 0;
}

static int
sbd_close(struct inode *inode, struct file *filp)
{
printk("<%s> invoked\n",__FUNCTION__);

Device.bdev=NULL;

return 0;
}

/*
* Handle an I/O request.
*/
static void sbd_transfer(struct sbd_device *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*hardsect_size;
unsigned long nbytes = nsect*hardsect_size;

if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset,
nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else
memcpy(buffer, dev->data + offset, nbytes);
}

static void sbd_request(request_queue_t *q)
{
struct request *req;

while ((req = elv_next_request(q)) != NULL) {
if (! blk_fs_request(req)) {
printk (KERN_NOTICE "Skip non-CMD request\n");
end_request(req, 0);
continue;
}
sbd_transfer(&Device, req->sector, req->current_nr_sectors,
req->buffer, rq_data_dir(req));
end_request(req, 1);
}
}



/*
* Ioctl.
*/
int sbd_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;

switch(cmd) {
/*
* The only command we need to interpret is HDIO_GETGEO, since
* we can't partition the drive otherwise. We have no real
* geometry, of course, so make something up.
*/
case HDIO_GETGEO:
size = Device.size*(hardsect_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;

case REMOVE_MOUNTED_DISK:
if(Device.bdev)
invalidate_bdev(Device.bdev,1);

del_gendisk(Device.gd);
put_disk(Device.gd);
blk_cleanup_queue(Queue);
vfree(Device.data);
return 0;
}

return -ENOTTY; /* unknown command */
}

/*
* The device operations structure.
*/
static struct block_device_operations sbd_ops = {
.owner = THIS_MODULE,
.ioctl = sbd_ioctl,
.open = sbd_open,
.release = sbd_close
};

static int __init sbd_init(void)
{
printk("<%s> invoked\n",__FUNCTION__);

/*
* Set up our internal device.
*/
Device.size = nsectors*hardsect_size;
spin_lock_init(&Device.lock);
Device.data = vmalloc(Device.size);
if (Device.data == NULL)
return -ENOMEM;
/*
* Get a request queue.
*/
Queue = blk_init_queue(sbd_request, &Device.lock);
if (Queue == NULL)
goto out;
blk_queue_hardsect_size(Queue, hardsect_size);

/*
* Get registered.
*/
major_num = register_blkdev(major_num, "sbd");
if (major_num <= 0) {
printk(KERN_WARNING "sbd: unable to get major number\n");
goto out;
}

/*
* And the gendisk structure.
*/
Device.gd = alloc_disk(16);
if (! Device.gd)
goto out_unregister;

Device.gd->major = major_num;
Device.gd->first_minor = 0;
Device.gd->fops = &sbd_ops;
Device.gd->private_data = &Device;
strcpy (Device.gd->disk_name, "sbd0");
set_capacity(Device.gd,
nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
Device.gd->queue = Queue;

add_disk(Device.gd);

return 0;

out_unregister:
unregister_blkdev(major_num, "sbd");
out:
vfree(Device.data);
return -ENOMEM;
}

static void __exit sbd_exit(void)
{
printk("<%s> invoked\n",__FUNCTION__);

del_gendisk(Device.gd);
put_disk(Device.gd);
unregister_blkdev(major_num, "sbd");
blk_cleanup_queue(Queue);
vfree(Device.data);
}

module_init(sbd_init);
module_exit(sbd_exit);

************************************************************************
***

.h file
-------
include <asm/ioctl.h>

#define SBD_MAJOR 'b'
#define REMOVE_MOUNTED_DISK _IO(SBD_MAJOR,0x01)

************************************************************************
***
Makefile
--------
#
# Makefile for the simple hello world program
# Author: Srinivas G. Date: 17th April 2006
#
DEVICE:=sbd
MAJOR:=230

KDIR:=/lib/modules/$(shell uname -r)/build
TRGT:=sbd
OBJS:=sbd_drv.o

obj-m += $(TRGT).o
$(TRGT)-objs := $(OBJS)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

************************************************************************
***
app.c file to issue an IOCTL
----------------------------
#include <fcntl.h>
#include <stdio.h>

#include "sbd_drv.h"

main()
{
int fd;

fd = open("/dev/sbd0",O_RDONLY);
if(fd == -1)
{
printf("Open failed\n");
exit(0);
}

ioctl(fd,REMOVE_MOUNTED_DISK);

close(fd);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/