Portál AbcLinuxu, 12. května 2025 06:46

Dotaz: kernel loadable modul - problem s vytvorenim socketu

21.4.2010 13:01 Payanek
kernel loadable modul - problem s vytvorenim socketu
Přečteno: 216×
Odpovědět | Admin
Ahoj, snazim se napsat jednoduchy modul do jadra ktery by se choval jako sitovy disk.

nasel jsem na lwn jednoduchy ramdisk (http://lwn.net/Articles/58719/)

a sitovou komunikaci v kernelu (http://www.linuxjournal.com/node/7660)

v init metode neni zadny problem, ale pokud sitovou komunikaci dam na misto cteni, tak vznikne problem se sock_create. (null pointer, ... ) nemate nekdo zkusenost ? pripadne nejake reseni ?

kod celeho jednoducheho modulu nasleduje : (proti je jednoduchy programek ktery pouze v userspace prijima)

[code]

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); [/code]
Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

21.4.2010 18:00 Sten
Rozbalit Rozbalit vše Re: kernel loadable modul - problem s vytvorenim socketu
Odpovědět | | Sbalit | Link | Blokovat | Admin
sock_create je pro vytváření soketů, které se předají do user space, takže jsou omezeny nastavením oprávnění user space programu (třeba SELinux), pro kernel space se používá sock_create_kern. Dost možná je problém tam.

Docela ošklivě to tam leakuje s tím response, pokud se něco nepovede, zahlásí se chyba a provede se return, tak se nedealokuje. Stejně pokud socket „not working“, tak ten socket vyleakuje.

Apropos, nebylo by vhodnější pro tohle použít FUSE? ;) (Správná odpověď: bylo)
22.4.2010 10:15 payanek
Rozbalit Rozbalit vše Re: kernel loadable modul - problem s vytvorenim socketu
Diky za odpoved, v definici sock_create a sock_create_kern se vola stejna funkce, s jinym parametrem, kazdopadne vysledek je stejny - tuto cestu jsem jiz zkousel.

tato implementace je pouze pro ukazku, takze tam neni vse osetreno, kazdopadne v kodu ktery to ma osetrene se to chova stejne.

fuse je take cesta, ale me zajima KLM, proste jak se to chova, ... co je potreba a tak. proto tato cesta.

Diky Pavel
8.5.2010 17:26 Payanek
Rozbalit Rozbalit vše Re: kernel loadable modul - problem s vytvorenim socketu
takze problem byl vyresen oklikou.

Zjistil jsem, ze problem je vytvareni socketu casteji nez 1x za 1s(+-) duvod neznam. Dalsim problem je to, ze transfer je aromicka funkce, takze zalezi i na casu jejiho ukonceni.

Cestou je pouzit jeden socket - napriklad netlink socket a presunout pozadavky do userspace. Samozrejme toto bychom nemeli delat primo, ale napr pres worker queue, a pridruzene nove vlakno.

Treba to nekomu pomuze. Pavel

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.