[Netadm-devel] gwc/pf sysklog.c,1.5,1.6 sysklog.h,1.1,1.2
Status: Beta
Brought to you by:
linuxpark
From: linuxpark <lin...@us...> - 2006-05-08 17:04:01
|
Update of /cvsroot/netadm/gwc/pf In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5677/pf Modified Files: sysklog.c sysklog.h Log Message: ADD: register_gwcklog_chrdev (major, devname); unregister_gwcklog_chrdev (major, devname); When you want more chrdevs for any other classified log type. follow these step. [ kernel module ] 1. register character log modules only with calling register_gwcklog_chrdev (major number, device name); [ user layer ] 2. make /dev node with mknod command. note! major number and its name. 3. call open chrdev with RD_ONLY 4. select the event from the device above, and read data. Index: sysklog.c =================================================================== RCS file: /cvsroot/netadm/gwc/pf/sysklog.c,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** sysklog.c 8 May 2006 07:05:59 -0000 1.5 --- sysklog.c 8 May 2006 16:53:27 -0000 1.6 *************** *** 30,33 **** --- 30,34 ---- #include <linux/poll.h> #include <linux/fs.h> + #include <linux/mount.h> #include <asm/io.h> #include <linux/proc_fs.h> *************** *** 36,39 **** --- 37,41 ---- #include "../include/global.h" + static const char gwc_klog_driver_name[] = "gwc-klog"; static const char gwc_klog_driver_string[] = "gwc kernel log module"; *************** *** 55,59 **** * 3. Add proc handlers * ! * --LP */ #ifndef SET_MODULE_OWNER --- 57,61 ---- * 3. Add proc handlers * ! * --LP (LinuxPark, Jeho-Park) */ #ifndef SET_MODULE_OWNER *************** *** 69,91 **** #endif ! static spinlock_t logbuf_lock [MAXSYSIDX]; ! static wait_queue_head_t log_wait [MAXSYSIDX]; ! ! static spinlock_t ratelimit_lock [MAXSYSIDX]; ! static unsigned long last_msg [MAXSYSIDX]; ! ! static unsigned long toks [MAXSYSIDX]; ! static int missed [MAXSYSIDX]; ! /* ! * The indices into log_buf are not constrained to log_buf_len - they ! * must be masked before subscripting ! */ ! static unsigned long log_start [MAXSYSIDX]; ! static unsigned long log_end [MAXSYSIDX]; ! static char __log_buf[MAXSYSIDX][__SYS_LOG_BUFLEN]; ! static char *log_buf [MAXSYSIDX]; ! static int log_buf_len = __SYS_LOG_BUFLEN; ! static unsigned long logged_chars[MAXSYSIDX]; static void init_gwc_logbuf (void ) { --- 71,119 ---- #endif ! static int gwcklog_chrdevtab_slot = 0; ! struct gwcklog_chrdev { ! int idx; ! unsigned int major; ! char *devname; ! }; ! ! static struct gwcklog_chrdev gwcklog_chrdevtab [MAXSYSIDX]; ! ! typedef struct { ! ! unsigned long log_start; ! unsigned long log_end; ! ! char __log_buf [__SYS_LOG_BUFLEN]; ! char *log_buf; ! int log_buf_len; ! unsigned long logged_chars; ! ! spinlock_t logbuf_lock; ! spinlock_t ratelimit_lock; ! ! wait_queue_head_t log_wait; ! ! unsigned long last_msg; ! ! unsigned long toks; ! ! int missed; ! ! } gwcklog_t; ! ! static gwcklog_t gwcklog [MAXSYSIDX]; ! ! ! static inline int get_gwcklog_idx (const char *devname) { ! int i = -1; ! ! for (i = 0; i < gwcklog_chrdevtab_slot; i++) ! if ( !strcmp (gwcklog_chrdevtab [i].devname, devname)) ! break; ! ! return i; ! } static void init_gwc_logbuf (void ) { *************** *** 93,116 **** for (i = 0; i < MAXSYSIDX; i++) { ! logbuf_lock [i] = SPIN_LOCK_UNLOCKED; ! log_buf [i] = __log_buf [i]; ! ratelimit_lock [i] = SPIN_LOCK_UNLOCKED; ! toks [i] = 10 * 5 * HZ; } } #undef LOG_BUF_MASK ! #define LOG_BUF_MASK (log_buf_len-1) #undef LOG_BUF ! #define LOG_BUF(idx, w) (log_buf[idx][(w) & LOG_BUF_MASK]) ! static void init_gwc_wait_queue_heads (wait_queue_head_t *wq, int max) { int i; ! for (i = 0; i < max; i++) { ! wq[i].lock = SPIN_LOCK_UNLOCKED; ! wq[i].task_list.next = wq[i].task_list.prev = &wq[i].task_list; } } /* * Commands to do_gwc_sysklog: --- 121,148 ---- for (i = 0; i < MAXSYSIDX; i++) { ! gwcklog [i].logbuf_lock = SPIN_LOCK_UNLOCKED; ! gwcklog [i].ratelimit_lock = SPIN_LOCK_UNLOCKED; ! gwcklog [i].log_buf_len = __SYS_LOG_BUFLEN; ! gwcklog [i].log_buf = gwcklog [i].__log_buf; ! gwcklog [i].toks = 10 * 5 * HZ; } } #undef LOG_BUF_MASK ! #define LOG_BUF_MASK(idx) (gwcklog [idx].log_buf_len-1) #undef LOG_BUF ! #define LOG_BUF(idx, w) gwcklog [idx].log_buf [(w) & LOG_BUF_MASK (idx)] ! static void init_gwc_wait_queue_heads (void ) { int i; ! for (i = 0; i < MAXSYSIDX; i++) { ! gwcklog [i].log_wait.lock = SPIN_LOCK_UNLOCKED; ! gwcklog [i].log_wait.task_list.next = ! gwcklog [i].log_wait.task_list.prev = ! &gwcklog [i].log_wait.task_list; } } + /* * Commands to do_gwc_sysklog: *************** *** 128,132 **** * 10 -- Return size of the log buffer */ - int do_gwc_sysklog(int idx, int type, char __user * buf, int len) { --- 160,163 ---- *************** *** 174,193 **** goto out; } ! error = wait_event_interruptible(log_wait[idx], (log_start[idx] - log_end[idx])); if (error) goto out; i = 0; ! spin_lock_irq(&logbuf_lock[idx]); ! while (!error && (log_start[idx] != log_end[idx]) && i < len) { ! c = LOG_BUF(idx, log_start[idx]); ! log_start[idx]++; ! spin_unlock_irq(&logbuf_lock[idx]); error = __put_user(c,buf); buf++; i++; cond_resched(); ! spin_lock_irq(&logbuf_lock[idx]); } ! spin_unlock_irq(&logbuf_lock[idx]); if (!error) error = i; --- 205,225 ---- goto out; } ! error = wait_event_interruptible (gwcklog [idx].log_wait, ! (gwcklog [idx].log_start - gwcklog [idx].log_end)); if (error) goto out; i = 0; ! spin_lock_irq(&gwcklog [idx].logbuf_lock); ! while (!error && (gwcklog [idx].log_start != gwcklog [idx].log_end) && i < len) { ! c = LOG_BUF(idx, gwcklog [idx].log_start); ! gwcklog [idx].log_start++; ! spin_unlock_irq(&gwcklog [idx].logbuf_lock); error = __put_user(c,buf); buf++; i++; cond_resched(); ! spin_lock_irq(&gwcklog [idx].logbuf_lock); } ! spin_unlock_irq(&gwcklog [idx].logbuf_lock); if (!error) error = i; *************** *** 208,219 **** } count = len; ! if (count > log_buf_len) ! count = log_buf_len; ! spin_lock_irq(&logbuf_lock[idx]); ! if (count > logged_chars[idx]) ! count = logged_chars[idx]; if (do_clear) ! logged_chars[idx] = 0; ! limit = log_end [idx]; /* * __put_user() could sleep, and while we sleep --- 240,251 ---- } count = len; ! if (count > gwcklog [idx].log_buf_len) ! count = gwcklog [idx].log_buf_len; ! spin_lock_irq(&gwcklog [idx].logbuf_lock); ! if (count > gwcklog [idx].logged_chars) ! count = gwcklog [idx].logged_chars; if (do_clear) ! gwcklog [idx].logged_chars = 0; ! limit = gwcklog [idx].log_end; /* * __put_user() could sleep, and while we sleep *************** *** 224,236 **** for(i = 0; i < count && !error; i++) { j = limit-1-i; ! if (j + log_buf_len < log_end [idx]) break; c = LOG_BUF(idx, j); ! spin_unlock_irq(&logbuf_lock[idx]); error = __put_user(c,&buf[count-1-i]); cond_resched(); ! spin_lock_irq(&logbuf_lock [idx]); } ! spin_unlock_irq(&logbuf_lock[idx]); if (error) break; --- 256,268 ---- for(i = 0; i < count && !error; i++) { j = limit-1-i; ! if (j + gwcklog [idx].log_buf_len < gwcklog [idx].log_end) break; c = LOG_BUF(idx, j); ! spin_unlock_irq(&gwcklog [idx].logbuf_lock); error = __put_user(c,&buf[count-1-i]); cond_resched(); ! spin_lock_irq(&gwcklog [idx].logbuf_lock); } ! spin_unlock_irq(&gwcklog [idx].logbuf_lock); if (error) break; *************** *** 250,261 **** break; case 5: /* Clear ring buffer */ ! logged_chars[idx] = 0; break; case 9: /* Number of chars in the log buffer */ ! error = log_end[idx] - log_start[idx]; break; case 10: /* Size of the log buffer */ ! error = log_buf_len; break; default: --- 282,293 ---- break; case 5: /* Clear ring buffer */ ! gwcklog [idx].logged_chars = 0; break; case 9: /* Number of chars in the log buffer */ ! error = gwcklog[idx].log_end - gwcklog [idx].log_start; break; case 10: /* Size of the log buffer */ ! error = gwcklog [idx].log_buf_len; break; default: *************** *** 269,279 **** static void emit_log_char(int idx, char c) { ! LOG_BUF(idx, log_end[idx]) = c; ! log_end[idx]++; ! if (log_end[idx] - log_start[idx] > log_buf_len) ! log_start[idx] = log_end[idx] - log_buf_len; ! if (logged_chars[idx] < log_buf_len) ! logged_chars[idx]++; } --- 301,311 ---- static void emit_log_char(int idx, char c) { ! LOG_BUF(idx, gwcklog [idx].log_end) = c; ! gwcklog [idx].log_end++; ! if (gwcklog [idx].log_end - gwcklog [idx].log_start > gwcklog [idx].log_buf_len) ! gwcklog[idx].log_start = gwcklog [idx].log_end - gwcklog [idx].log_buf_len; ! if (gwcklog [idx].logged_chars < gwcklog [idx].log_buf_len) ! gwcklog [idx].logged_chars++; } *************** *** 294,298 **** /* If a crash is occurring, make sure we can't deadlock */ ! spin_lock_init(&logbuf_lock [idx]); } --- 326,330 ---- /* If a crash is occurring, make sure we can't deadlock */ ! spin_lock_init(&gwcklog [idx].logbuf_lock); } *************** *** 316,335 **** unsigned long now = jiffies; ! spin_lock_irqsave(&ratelimit_lock[idx], flags); ! toks[idx] += now - last_msg [idx]; ! last_msg [idx] = now; ! if (toks[idx] > (ratelimit_burst * ratelimit_jiffies)) ! toks [idx] = ratelimit_burst * ratelimit_jiffies; ! if (toks [idx] >= ratelimit_jiffies) { ! int lost = missed [idx]; ! missed [idx] = 0; ! toks [idx] -= ratelimit_jiffies; ! spin_unlock_irqrestore(&ratelimit_lock[idx], flags); if (lost) gwc_printk (idx, "gwc_printk: %d messages suppressed.\n", lost); return 1; } ! missed [idx]++; ! spin_unlock_irqrestore(&ratelimit_lock[idx], flags); return 0; } --- 348,367 ---- unsigned long now = jiffies; ! spin_lock_irqsave(&gwcklog [idx].ratelimit_lock, flags); ! gwcklog [idx].toks += now - gwcklog [idx].last_msg; ! gwcklog [idx].last_msg = now; ! if (gwcklog [idx].toks > (ratelimit_burst * ratelimit_jiffies)) ! gwcklog [idx].toks = ratelimit_burst * ratelimit_jiffies; ! if (gwcklog [idx].toks >= ratelimit_jiffies) { ! int lost = gwcklog [idx].missed; ! gwcklog [idx].missed = 0; ! gwcklog [idx].toks -= ratelimit_jiffies; ! spin_unlock_irqrestore(&gwcklog [idx].ratelimit_lock, flags); if (lost) gwc_printk (idx, "gwc_printk: %d messages suppressed.\n", lost); return 1; } ! gwcklog [idx].missed ++; ! spin_unlock_irqrestore(&gwcklog [idx].ratelimit_lock, flags); return 0; } *************** *** 375,379 **** /* This stops the holder of console_sem just where we want him */ ! spin_lock_irqsave(&logbuf_lock[idx], flags); printk_cpu = smp_processor_id(); --- 407,411 ---- /* This stops the holder of console_sem just where we want him */ ! spin_lock_irqsave(&gwcklog [idx].logbuf_lock, flags); printk_cpu = smp_processor_id(); *************** *** 446,455 **** */ printk_cpu = UINT_MAX; ! spin_unlock_irqrestore(&logbuf_lock, flags); goto out; } printk_cpu = UINT_MAX; ! spin_unlock_irqrestore(&logbuf_lock, flags); out: --- 478,487 ---- */ printk_cpu = UINT_MAX; ! spin_unlock_irqrestore(&gwcklog [idx].logbuf_lock, flags); goto out; } printk_cpu = UINT_MAX; ! spin_unlock_irqrestore(&gwcklog [idx].logbuf_lock, flags); out: *************** *** 478,482 **** va_end(args); ! wake_up_interruptible (&log_wait[idx]); return r; } --- 510,514 ---- va_end(args); ! wake_up_interruptible (&gwcklog [idx].log_wait); return r; } *************** *** 484,561 **** /* ! * gwc kctl file handler lists * - * @sys_xxxmsg_{open|release|read|poll|} */ ! static int gwc_pf_open(struct inode * inode, struct file * file) { ! return do_gwc_sysklog(GWC_PF_IDX, 1, NULL, 0); } ! static int gwc_pf_release(struct inode * inode, struct file * file) { ! (void) do_gwc_sysklog(GWC_PF_IDX, 0, NULL, 0); ! return 0; } ! static ssize_t gwc_pf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ! if ((file->f_flags & O_NONBLOCK) && !do_gwc_sysklog(GWC_PF_IDX, 9, NULL, 0)) ! return -EAGAIN; ! return do_gwc_sysklog(GWC_PF_IDX, 2, buf, count); } ! static unsigned int gwc_pf_poll(struct file *file, poll_table *wait) { ! poll_wait(file, &log_wait[GWC_PF_IDX], wait); ! if (do_gwc_sysklog(GWC_PF_IDX, 9, NULL, 0)) ! return POLLIN | POLLRDNORM; ! return 0; } ! struct file_operations gwc_pf_operations = { ! .read = gwc_pf_read, ! .poll = gwc_pf_poll, ! .open = gwc_pf_open, ! .release = gwc_pf_release, }; ! static int gwc_sys_open(struct inode * inode, struct file * file) ! { ! return do_gwc_sysklog(GWC_KSYS_IDX, 1, NULL, 0); ! } ! static int gwc_sys_release(struct inode * inode, struct file * file) ! { ! (void) do_gwc_sysklog(GWC_KSYS_IDX, 0, NULL, 0); ! return 0; ! } ! static ssize_t gwc_sys_read(struct file *file, char __user *buf, ! size_t count, loff_t *ppos) ! { ! if ((file->f_flags & O_NONBLOCK) && !do_gwc_sysklog(GWC_KSYS_IDX, 9, NULL, 0)) ! return -EAGAIN; ! return do_gwc_sysklog(GWC_KSYS_IDX, 2, buf, count); } ! static unsigned int gwc_sys_poll(struct file *file, poll_table *wait) ! { ! poll_wait(file, &log_wait[GWC_KSYS_IDX], wait); ! if (do_gwc_sysklog(GWC_KSYS_IDX, 9, NULL, 0)) ! return POLLIN | POLLRDNORM; ! return 0; ! } ! struct file_operations gwc_sys_operations = { ! .read = gwc_sys_read, ! .poll = gwc_sys_poll, ! .open = gwc_sys_open, ! .release = gwc_sys_release, ! }; static void init_gwc_kctl (void) { --- 516,626 ---- /* ! * gwc klog generic file handler lists * */ ! static int gwcklog_generic_open(struct inode * inode, struct file * file) { ! int idx = get_gwcklog_idx ( file->f_dentry->d_iname ); ! if ( idx < 0 ) ! return -ENXIO; ! ! return do_gwc_sysklog(idx, 1, NULL, 0); } ! static int gwcklog_generic_release(struct inode * inode, struct file * file) { ! int idx = get_gwcklog_idx ( file->f_dentry->d_iname ); ! if ( idx < 0 ) ! return -ENXIO; ! ! (void) do_gwc_sysklog(idx, 0, NULL, 0); ! return 0; } ! static ssize_t gwcklog_generic_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ! int idx = get_gwcklog_idx ( file->f_dentry->d_iname ); ! if ( idx < 0 ) ! return -ENXIO; ! ! if ((file->f_flags & O_NONBLOCK) && !do_gwc_sysklog(idx, 9, NULL, 0)) ! return -EAGAIN; ! ! return do_gwc_sysklog(idx, 2, buf, count); } ! static unsigned int gwcklog_generic_poll(struct file *file, poll_table *wait) { ! int idx = get_gwcklog_idx ( file->f_dentry->d_iname ); ! if ( idx < 0 ) ! return -ENXIO; ! ! poll_wait(file, &gwcklog [idx].log_wait, wait); ! if (do_gwc_sysklog(idx, 9, NULL, 0)) ! return POLLIN | POLLRDNORM; ! ! return 0; } ! struct file_operations gwcklog_generic_operations = { ! .read = gwcklog_generic_read, ! .poll = gwcklog_generic_poll, ! .open = gwcklog_generic_open, ! .release = gwcklog_generic_release, }; + int register_gwcklog_chrdev (unsigned int major, const char *devname) { + int ret; ! if (gwcklog_chrdevtab_slot + MINGWCLOG_MAJORNUM > MAXGWCLOG_MAJORNUM ) { ! printk (KERN_ERR "chrdevtab overflow\n"); ! return -EMFILE; ! } ! gwcklog_chrdevtab[gwcklog_chrdevtab_slot].idx = gwcklog_chrdevtab_slot; ! gwcklog_chrdevtab[gwcklog_chrdevtab_slot].major = major; ! gwcklog_chrdevtab[gwcklog_chrdevtab_slot].devname = ! (char *)kmalloc (strlen (devname), GFP_KERNEL); ! ! if (!gwcklog_chrdevtab [gwcklog_chrdevtab_slot].devname) { ! printk (KERN_ERR "Failed to alloc mem\n"); ! return -ENOMEM; ! } ! strcpy (gwcklog_chrdevtab [gwcklog_chrdevtab_slot].devname, devname); ! ! if ((ret = register_chrdev(gwcklog_chrdevtab [gwcklog_chrdevtab_slot].major, ! gwcklog_chrdevtab [gwcklog_chrdevtab_slot].devname, ! &gwcklog_generic_operations)) < 0 ) { ! printk ("Failed to register gwc chrdev [%s]: %d\n", ! gwcklog_chrdevtab [gwcklog_chrdevtab_slot].devname, ret); ! kfree (gwcklog_chrdevtab [gwcklog_chrdevtab_slot].devname); ! return ret; ! } ! ++gwcklog_chrdevtab_slot; ! return ret; } + EXPORT_SYMBOL_GPL (register_gwcklog_chrdev); ! int unregister_gwcklog_chrdev (unsigned int major, const char *devname) { ! int ret; ! if (gwcklog_chrdevtab_slot - 1 < 0 ) { ! printk (KERN_ERR "gwcklog_chrdevtab underflow\n"); ! return -ENODEV; ! } ! ! if ((ret = unregister_chrdev(major, devname) < 0)) { ! printk(KERN_WARNING "%s: Failed to Unregister %s: %d\n", ! gwc_klog_driver_name, devname, ret); ! return ret; ! } ! kfree (gwcklog_chrdevtab [--gwcklog_chrdevtab_slot].devname); ! return ret; ! } ! EXPORT_SYMBOL_GPL (unregister_gwcklog_chrdev); static void init_gwc_kctl (void) { *************** *** 591,595 **** int i; ! if (register_chrdev(GWC_PF_MAJORNUM, GWC_PF_DNAME, &gwc_pf_operations) < 0) { printk(KERN_WARNING "%s: Failed to Registrate %s\n", gwc_klog_driver_name, GWC_PF_DNAME); --- 656,660 ---- int i; ! if (register_gwcklog_chrdev (GWC_PF_MAJORNUM, GWC_PF_DNAME) < 0 ) { printk(KERN_WARNING "%s: Failed to Registrate %s\n", gwc_klog_driver_name, GWC_PF_DNAME); *************** *** 597,601 **** } ! if (register_chrdev(GWC_SYS_MAJORNUM, GWC_SYS_DNAME, &gwc_sys_operations) < 0) { printk(KERN_WARNING "%s: Failed to Registrate %s\n", gwc_klog_driver_name, GWC_SYS_DNAME); --- 662,666 ---- } ! if (register_gwcklog_chrdev (GWC_SYS_MAJORNUM, GWC_SYS_DNAME) < 0 ) { printk(KERN_WARNING "%s: Failed to Registrate %s\n", gwc_klog_driver_name, GWC_SYS_DNAME); *************** *** 617,631 **** #else ! printk (KERN_INFO "%s: Unloading gwc kctl module ...\n", gwc_klog_driver_name); ! if (unregister_chrdev(GWC_PF_MAJORNUM, GWC_PF_DNAME) < 0) { printk(KERN_WARNING "%s: Failed to Unregister %s\n", gwc_klog_driver_name, GWC_PF_DNAME); } ! if (unregister_chrdev(GWC_SYS_MAJORNUM, GWC_SYS_DNAME) < 0) { printk(KERN_WARNING "%s: Failed to Unregister %s\n", gwc_klog_driver_name, GWC_SYS_DNAME); } - printk (KERN_INFO "%s: Success to unregister gwc kctl module ...\n", gwc_klog_driver_name); #endif --- 682,694 ---- #else ! if ( unregister_gwcklog_chrdev (GWC_PF_MAJORNUM, GWC_PF_DNAME) < 0 ) { printk(KERN_WARNING "%s: Failed to Unregister %s\n", gwc_klog_driver_name, GWC_PF_DNAME); } ! if (unregister_gwcklog_chrdev(GWC_SYS_MAJORNUM, GWC_SYS_DNAME) < 0) { printk(KERN_WARNING "%s: Failed to Unregister %s\n", gwc_klog_driver_name, GWC_SYS_DNAME); } #endif *************** *** 639,643 **** gwc_klog_driver_version); ! init_gwc_wait_queue_heads (log_wait, MAXSYSIDX); init_gwc_logbuf (); init_gwc_kctl (); --- 702,706 ---- gwc_klog_driver_version); ! init_gwc_wait_queue_heads (); init_gwc_logbuf (); init_gwc_kctl (); Index: sysklog.h =================================================================== RCS file: /cvsroot/netadm/gwc/pf/sysklog.h,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** sysklog.h 6 May 2006 15:17:47 -0000 1.1 --- sysklog.h 8 May 2006 16:53:27 -0000 1.2 *************** *** 41,48 **** * 10 -- Return size of the log buffer */ - #if 0 - int do_gwc_sysklog(int idx, int type, char __user * buf, int len); - #endif - #ifdef CONFIG_GWC_SYSLOG_SYSCALL asmlinkage long sys_gwc_syslog(int idx, int type, char __user * buf, int len); --- 41,44 ---- *************** *** 63,66 **** --- 59,78 ---- asmlinkage int gwc_printk(int idx, const char *fmt, ...); + /* + * This is register_gwcklog_chrdev + * + * If you want to use, first mknod your chrdev in user layer then call this + * function with only major number and the name of that device file. + */ + int register_gwcklog_chrdev (unsigned int major, const char *devname); + + /* + * This is unregister_gwcklog_chrdev + * + * when you unload sysklog modules and If you register chrdev with register_gwcklog_chrdev () + * you must call this function. + */ + int unregister_gwcklog_chrdev (unsigned int major, const char *devname); + #if 0 /* TODO: compile error --LP */ static inline int gwc_pflog ( const char *fmt, args...) { |