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.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
and this example is working, when aplied in init function, but when i use it instead of read / write, kernel freezes or in better case, sends some warning.(listed here)
static void sbd_transfer(struct sbd_device *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
long long offset = sector*hardsect_size;
unsigned long nbytes = nsect*hardsect_size;
if ((offset + nbytes) > dev->size) {
//printk (KERN_WARNING "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write){
memcpy(dev->data + offset, buffer, nbytes);
}
else{
struct sockaddr_in servaddr;
int r = -1;
struct socket *control= NULL;
char *response = kmalloc(256,GFP_KERNEL);
unsigned short port;
r = sock_create(PF_INET, SOCK_STREAM,
IPPROTO_TCP, &control);
if(r!=0){
printk(KERN_WARNING "sbd: socketcreation \n" );
return;
}
port = htons(5902);
memset(&servaddr,0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = port;
servaddr.sin_addr.s_addr = htonl(0x10207964); // IP
r = control->ops->connect(control,
(struct sockaddr *) &servaddr,
sizeof(servaddr), O_RDWR);
if(r!=0){
printk(KERN_WARNING "sbd: socket not working, ending\n");
return;
}
sock_release(control);
kfree(response);
//memcpy(buffer, dev->data + offset, nbytes);
}
}
This code causes upper error even if there is no socket->opt->connect
This function is called several times while loading module (for reading)
but I do not know, why there is that bug.
Thank you for response in advance. i can post whole code via mail.
It seems that you have disabled interrupts one time too many. I can't see it in the code you provided. Re-check all the places where you enable and disable interrupts, especially check all error conditions. Also make sure you didn't make modifications to the kernel code outside of your module.
Thank you for reply, actually I don't see any interupt disabling in the code.
I am providing whole code bellow - it is only simple block device from lwn, and added network communication instead of memcpy that should read from memory.
Code:
#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>
//includes for bsd sockets;
#include <linux/net.h>
#include <net/sock.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <asm/uaccess.h>
#include <linux/file.h>
#include <linux/socket.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
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 = 32768; /* 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;
} Device;
/*
* Handle an I/O request.
*/
static void sbd_transfer(struct sbd_device *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
long long offset = sector*hardsect_size;
unsigned long nbytes = nsect*hardsect_size;
if ((offset + nbytes) > dev->size) {
printk (KERN_WARNING "sbd: Beyond-end write (%lld %ld)\n", offset, nbytes);
return;
}
if (write){
memcpy(dev->data + offset, buffer, nbytes);
}
else{
struct sockaddr_in servaddr;
int r = -1;
struct socket *control= NULL;
char *response = kmalloc(256,GFP_KERNEL);
unsigned short port;
r = sock_create(PF_INET, SOCK_STREAM,
IPPROTO_TCP, &control);
if(r!=0){
printk(KERN_WARNING "sbd: socketcreation \n" );
return;
}
port = htons(5902);
memset(&servaddr,0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = port;
servaddr.sin_addr.s_addr = htonl(0x0A207964); // IP
r = control->ops->connect(control,
(struct sockaddr *) &servaddr,
sizeof(servaddr), O_RDWR);
if(r!=0){
printk(KERN_WARNING "sbd: socket not working, ending\n");
return;
}
sock_release(control);
kfree(response);
//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;
}
return -ENOTTY; /* unknown command */
}
/*
* The device operations structure.
*/
static struct block_device_operations sbd_ops = {
.owner = THIS_MODULE,
.ioctl = sbd_ioctl
};
static int __init sbd_init(void)
{
/*
* 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);
printk(KERN_WARNING "sbd: Loaded, capacity %ld\n", Device.size);
return 0;
out_unregister:
unregister_blkdev(major_num, "sbd");
out:
vfree(Device.data);
return -ENOMEM;
}
static void __exit sbd_exit(void)
{
del_gendisk(Device.gd);
put_disk(Device.gd);
unregister_blkdev(major_num, "sbd");
blk_cleanup_queue(Queue);
vfree(Device.data);
printk(KERN_WARNING "sbd: Unloaded\n");
}
module_init(sbd_init);
module_exit(sbd_exit);
Thank you for help
Pavel
Last edited by payanek; 04-20-2010 at 02:39 AM.
Reason: CODE is ignored - hopefully now correct
I know, but I guess, that requests are served one by one from queue. Actually i tried to create one extra spinlock and lock execution of read section, but no change.
there was sequence :
lock
sock_create
sock_release
unlock
ok, once more I am here,
I guess (please, correct me), that problem is, that request processing is atomic operation, so I cannot switch content and that can cause problem with sock_create (even sock_create_kern)
If I am right, how to overcome this feature ?
Is there good idea to create one kernel thread and send there requests and call end_request function from that thread ?
thank you for hints.
Pavel
Last edited by payanek; 04-28-2010 at 02:43 AM.
Reason: new idea :)
Dear friends, thank everyone for help. Now, it seems to be working. Actually, I dropped Idea to comunicate with many oher clients directly from my module. Now I am communicating with userspace program, that is maitaining other communication.
Using working queue and worker thread to manage requests.
Great inspiration is nbd (network block device) whose source is directly in kernel.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.