Date: Mon, 21 May 2007 18:52:48 +1000 From: Lawrence Stewart <lstewart@room52.net> To: Ivan Voras <ivoras@fer.hr> Cc: freebsd-hackers@freebsd.org Subject: Re: Writing a plain text file to disk from kernel space Message-ID: <46515DE0.20209@room52.net> In-Reply-To: <f2j5hf$hap$2@sea.gmane.org> References: <4649349D.4060101@room52.net> <200705150847.38838.marc.loerner@hob.de> <46499491.2010205@room52.net> <f2j5hf$hap$2@sea.gmane.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Will do Ivan as soon as I've figured everything out. However, I need some more help from you knowledgeable people. Attached is a fully self contained kernel module and associated makefile that demonstrates the problem I'm having. I've also attached a compiled version of the module for FreeBSD 6.2 RELEASE. The module does the following: - In its init function, it opens a file descriptor to /var/log/test23.log - In its init function, it writes a line of text to the opened file descriptor - In its shutdown function, writes a line of text to the opened file descriptor - In its shutdown function, closes the opened file descriptor The opening of the file descriptor and writing of text done in the module's init function works as expected. The writing of text done in the shutdown function fails with an errno of 9 (bad file descriptor) returned. The closing of the file descriptor doesn't appear to return an error, but I suspect it isn't working either. From what I've deduced so far, it appears to be a thread related issue. I have verified that the thread struct pointer pointed to by "curthread" in the module's init function is different to that in the shutdown function. I suspect that you can't use a file descriptor that was opened in one thread in a completely different thread, but I'm not sure if this is true, and if it is true, how to get around it. Any ideas, explanations, help or suggestions regarding how file IO and threading work and how I can get cross-thread file IO working would be most welcome. Cheers, Lawrence Ivan Voras wrote: > Lawrence Stewart wrote: > >> I'll have a play around and report back to the list what I find for >> archival purposes. > > Please do, and also consider writing a short and instructive tutorial > on it! Many people have asked this same question without a > to-the-point answer. > > > _______________________________________________ > freebsd-hackers@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-hackers > To unsubscribe, send any mail to > "freebsd-hackers-unsubscribe@freebsd.org" [-- Attachment #2 --] //****************************************************** // filewriter // // A FreeBSD kernel module that demonstrates how to open and // write a text file from within the kernel. // // Date: May 2007 // AUTHORS: // James Healy <jhealy@swin.edu.au> // Lawrence Stewart <lastewart@swin.edu.au> //****************************************************** #include <sys/param.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/pcpu.h> #include <sys/proc.h> #include <sys/syscallsubr.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/sysproto.h> // some simple defines to keep the code clean #define MODNAME "filewriter" #define MODVERSION "1.0" #define PATH "/var/log/test23.log" // some ugly globals vars, we may look at getting rid of these. static volatile int filewriter_hooked = 0; static int testfd = 0; static int filewriter_writelog(struct thread *td, int fd, char *line, u_int len) { struct uio auio; struct iovec aiov; int err; bzero(&aiov, sizeof(aiov)); bzero(&auio, sizeof(auio)); aiov.iov_base = line; aiov.iov_len = len; auio.uio_iov = &aiov; auio.uio_offset = 0; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_iovcnt = 1; auio.uio_resid = len; auio.uio_td = td; printf("fd: %u\n", fd); printf(aiov.iov_base); err = kern_writev(td, fd, &auio); printf("write err: %u\n", err); return err; } static int filewriter_closelog(struct thread *td, int fd) { printf("filewriter_closelog fd: %d\n", fd); if(fd) { struct close_args fdtmp; fdtmp.fd = fd; printf("filewriter_closelog thread ptr: %x\n", (unsigned int)td); return close(td, &fdtmp); } return 0; } static int filewriter_openlog(struct thread *td, int *fd, char *path) { int error; error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_APPEND, 0644); if (!error) { *fd = td->td_retval[0]; printf("openlog fd: %d\n", *fd); } else printf("openlog failed\n"); return error; } // called when the module is first loaded into the kernel, hooking our functions into // the IP stack using pfil hooks. These hooks are designed for firewall processing, // but work equally well for our purposes - we just never tell the stack to drop a packet. static int init_module(void) { char filewriter_line[128]; // if we're alredy hooked in, do nothing if (filewriter_hooked) return (0); filewriter_hooked = 1; filewriter_openlog(curthread, &testfd, PATH); sprintf(filewriter_line, "init_module()\tFile: %s\tcurthread ptr: %x\n", PATH, (unsigned int)curthread); filewriter_writelog(curthread, testfd, filewriter_line, strlen(filewriter_line)); // print message to the user's current terminal as opposed to // printf which prints to the kernel's stdout (which is attached // to getty 0) uprintf("Loaded %s %s\n", MODNAME, MODVERSION); return 0; } // called when the module is unloaded from the kernel, unhooking our functions from // the IP stacks. static int deinit_module(void) { char filewriter_line[128]; // if we're already unhooked, do nothing if (!filewriter_hooked) return (0); // let our module know we're no longer hooked in filewriter_hooked = 0; sprintf(filewriter_line, "deinit_module()\tFile: %s\tcurthread ptr: %x\n\n", PATH, (unsigned int)curthread); filewriter_writelog(curthread, testfd, filewriter_line, strlen(filewriter_line)); filewriter_closelog(curthread, testfd); uprintf("Unloaded %s %s\n", MODNAME, MODVERSION); return 0; } // This is the function that is called to load and unload the functions. It hands off // to seperate functions to do the work. static int load_handler(module_t mod, int what, void *arg) { int err = 0; switch(what) { case MOD_LOAD: err = init_module(); break; case MOD_UNLOAD: err = deinit_module(); break; default: err = EINVAL; break; } return(err); } // a struct that holds basic data on the module static moduledata_t filewriter_mod = { "filewriter", //module's name load_handler, //execution entry point for the module NULL }; //Param 1: name of the kernel module //Param 2: moduledata_t struct containing info about the kernel module and the execution entry point for the module //Param 3: Pulled from the sysinit_sub_id enumeration in /usr/include/sys/kernel.h // Seems to define the order in which modules should be initialized by the system //Param 4: Pulled from the sysinit_elem_order enumeration in /usr/include/sys/kernel.h // Defines the order of this kld's initialization within the subsystem defined by param 3 DECLARE_MODULE(filewriter, filewriter_mod, SI_SUB_KLD, SI_ORDER_ANY); [-- Attachment #3 --] ELF 4 4 ( , , , , , X X X x x ` ` L $ ( , X Z ( X ( = ( C O n $ Y a , h _DYNAMIC _GLOBAL_OFFSET_TABLE_ uprintf module_register_init bzero kern_writev kern_open sprintf strlen close __start_set_sysinit_set __stop_set_sysinit_set __start_set_modmetadata_set __stop_set_modmetadata_set _edata __bss_start _end Z , 8 = B Y g w | $ ( 8 < @ P T > F a Q G 4 UWVS(j]Sj EPWEh E̋E]ԉuEE E E E E EuEPWV(Ph( e[^_ÐUVS EtH e[ ^Ív t1e[^É d h h jh7 S PhK XZd Ph7 h[ xSd5 S$S ^Xh h h 1Nv < d Ph7 h Sd5 S$S /Y[d5 Sh XZu$h h h eh XVh Y[PVXZfilewriter fd: %u write err: %u /var/log/test23.log openlog fd: %d init_module() File: %s curthread ptr: %x 1.0 Loaded %s %s deinit_module() File: %s curthread ptr: %x filewriter_closelog fd: %d Unloaded %s %s openlog failed filewriter_closelog thread ptr: %x , H < p < ` ` L o X GCC: (GNU) 3.4.4 [FreeBSD] 20050518 .symtab .strtab .shstrtab .hash .dynsym .dynstr .rel.dyn .text .rodata set_sysinit_set set_modmetadata_set .data .dynamic .got .bss .comment ! ` ` ) ` ` 1 L L : 9 @ 2 H $ $ X ( ( l , , , r X X x { % 8 $ 1 , K < Z p g ( H ` ` L $ ( , X ( X / 5 ( L X b $ z , __set_sysinit_set_sym_filewritermodule_sys_init filewritermodule_sys_init filewriter_mod load_handler __set_modmetadata_set_sym__mod_metadata_md_filewriter _mod_metadata_md_filewriter testfd filewriter_hooked filewriter_writelog printf __start_set_modmetadata_set _DYNAMIC uprintf module_register_init bzero __stop_set_sysinit_set kern_writev kern_open __start_set_sysinit_set __bss_start sprintf _edata _GLOBAL_OFFSET_TABLE_ _end strlen __stop_set_modmetadata_set close [-- Attachment #4 --] SRCS=filewriter.c KMOD=filewriter .include <bsd.kmod.mk>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?46515DE0.20209>
