source: ksyslog/trunk/ksyslog.c @ 269

Revision 269, 16.5 KB checked in by atzm, 10 years ago (diff)

optimize workqueue on smp environment

RevLine 
[232]1/*
2 * ksyslog: In-kernel syslog receiver
3 * Copyright(C) 2013 Atzm WATANABE All rights reserved
4 * Distributed under the GPL
5 */
6
[246]7#include <linux/version.h>
[232]8#include <linux/module.h>
[243]9#include <linux/inet.h>
[232]10#include <linux/ip.h>
11#include <linux/udp.h>
12#include <linux/namei.h>
[263]13#include <linux/fsnotify.h>
[246]14#include <linux/proc_fs.h>
[250]15#include <linux/u64_stats_sync.h>
16#include <linux/percpu.h>
[232]17#include <net/udp.h>
[246]18#include "compat.h"
[232]19#include "ksyslog.h"
20
[242]21static struct ksyslog_queue ksyslog_queue;
[232]22static struct socket *ksyslog_rcv_sk = NULL;
23
[269]24static struct delayed_work __percpu *ksyslog_work = NULL;
[232]25static struct workqueue_struct *ksyslog_wq = NULL;
26
27#ifdef CONFIG_PROC_FS
28static struct proc_dir_entry *ksyslog_procdir = NULL;
29static struct proc_dir_entry *ksyslog_proc_queue = NULL;
[250]30static struct proc_dir_entry *ksyslog_proc_size = NULL;
31static struct proc_dir_entry *ksyslog_proc_stats = NULL;
[232]32#endif
33
34static char *ksyslog_host = "0.0.0.0";
35static ushort ksyslog_port = 514;
36static char *ksyslog_path = "/var/log/ksyslog.log";
[250]37static ulong ksyslog_queue_size_max = 4096;
[232]38static ulong ksyslog_flush_interval = 45;  /* milliseconds */
39
[268]40static DEFINE_SPINLOCK(ksyslog_write_lock);
41
[232]42module_param(ksyslog_host, charp, 0444);
43module_param(ksyslog_port, ushort, 0444);
44module_param(ksyslog_path, charp, 0644);
[250]45module_param(ksyslog_queue_size_max, ulong, 0644);
[232]46module_param(ksyslog_flush_interval, ulong, 0644);
47
[250]48static int
[241]49ksyslog_queue_init(struct ksyslog_queue *queue)
50{
51        memset(queue, 0, sizeof(*queue));
52        INIT_LIST_HEAD(&queue->head);
[242]53        spin_lock_init(&queue->lock);
[250]54        atomic64_set(&queue->size, 0);
55        queue->stats = alloc_percpu(struct ksyslog_stats);
56        if (unlikely(queue->stats == NULL))
57                return -ENOMEM;
58        return 0;
[241]59}
60
[250]61static void
62ksyslog_queue_uninit(struct ksyslog_queue *queue)
63{
64        if (likely(queue->stats))
65                free_percpu(queue->stats);
66        queue->stats = NULL;
67}
68
[232]69static int
70ksyslog_close(struct file *file)
71{
[263]72        int err;
73        mm_segment_t oldfs;
74
75        oldfs = get_fs();
76        set_fs(get_ds());
77
78        err = filp_close(file, NULL);
79
80        set_fs(oldfs);
81        return err;
[232]82}
83
84static struct file *
85ksyslog_open(const char *path)
86{
87        struct file *file;
[243]88        struct path ppath;
[232]89        mm_segment_t oldfs;
90
91        oldfs = get_fs();
92        set_fs(get_ds());
93
[243]94        if (unlikely(kern_path(path, LOOKUP_OPEN|LOOKUP_FOLLOW, &ppath)))
[232]95                file = filp_open(path, O_CREAT|O_WRONLY|O_APPEND|O_LARGEFILE, 0600);
96        else
97                file = filp_open(path, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
98
[234]99        if (unlikely(IS_ERR(file)))
[232]100                goto out;
101
[264]102        compat_fsnotify_open(file);
[263]103
[234]104        if (unlikely(S_ISDIR(file->f_path.dentry->d_inode->i_mode))) {
[232]105                ksyslog_close(file);
106                file = ERR_PTR(-EISDIR);
107                goto out;
108        }
109
[234]110        if (unlikely(file->f_pos < 0)) {
[232]111                ksyslog_close(file);
112                file = ERR_PTR(-EIO);
113                goto out;
114        }
115
116out:
117        set_fs(oldfs);
118        return file;
119}
120
121static int
122ksyslog_write(struct file *file, const char *buf, const size_t length)
123{
124        int err;
125        mm_segment_t oldfs;
126
127        oldfs = get_fs();
128        set_fs(get_ds());
129
130        err = vfs_write(file, (__force void __user *)buf, length, &file->f_pos);
131
132        set_fs(oldfs);
133        return err;
134}
135
136static void
[234]137ksyslog_drop_warning(const struct ksyslog_entry *entry)
[232]138{
[268]139        net_warn_ratelimited("ksyslog: dropped: %llu %s.%s %u.%u.%u.%u %.*s\n",
140                             timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
141                             ksyslog_facility_str(entry->facility),
142                             ksyslog_severity_str(entry->severity),
143                             entry->saddr.addr8[0], entry->saddr.addr8[1],
144                             entry->saddr.addr8[2], entry->saddr.addr8[3],
145                             (int)entry->length, entry->data);
[232]146}
147
148static struct ksyslog_entry *
[234]149ksyslog_entry_create(const struct sk_buff *skb,
150                     const struct iphdr *iph, const struct udphdr *udph)
[232]151{
152        struct ksyslog_entry *entry;
[235]153        unsigned int priority, facility, severity, month, day, hour, minute, second;
154        unsigned char *start, month_s[4];
155        struct tm tm;
[232]156        int length, i;
157
[235]158        if (sscanf(skb->data, "<%3u>%3s %2u %2u:%2u:%2u ",
159                   &priority, month_s, &day, &hour, &minute, &second) != 6)
[232]160                return ERR_PTR(-EINVAL);
161
162        start = memchr(skb->data, '>', 5);
163        if (start == NULL)
164                return ERR_PTR(-EINVAL);
165        start++;
166
167        facility = priority >> 3;
168        severity = priority & 7;
169
170        if (facility >= __KSYSLOG_F_MAX)
171                return ERR_PTR(-EINVAL);
172        if (severity >= __KSYSLOG_S_MAX)
173                return ERR_PTR(-EINVAL);
174
[235]175        month = ksyslog_month_num(month_s);
176        if (!month)
177                return ERR_PTR(-EINVAL);
178        if (day > 31)
179                return ERR_PTR(-EINVAL);
180        if (hour > 23)
181                return ERR_PTR(-EINVAL);
182        if (minute > 59)
183                return ERR_PTR(-EINVAL);
184        if (second > 59)
185                return ERR_PTR(-EINVAL);
186
[232]187        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
[234]188        if (unlikely(entry == NULL))
[232]189                return ERR_PTR(-ENOMEM);
190
191        length = skb->len - (start - skb->data);
192        entry->data = kzalloc(length, GFP_ATOMIC);
[234]193        if (unlikely(entry->data == NULL)) {
[232]194                kfree(entry);
195                return ERR_PTR(-ENOMEM);
196        }
197
198        if (skb->tstamp.tv64)
199                entry->tv = ktime_to_timeval(skb->tstamp);
200        else
201                do_gettimeofday(&entry->tv);
202
[235]203        time_to_tm(entry->tv.tv_sec, 0, &tm);
204        entry->time = mktime(tm.tm_year + 1900, month, day, hour, minute, second);
205
206        entry->priority = priority;
[234]207        entry->facility = facility;
208        entry->severity = severity;
209
[232]210        entry->daddr.addr32 = iph->daddr;
211        entry->saddr.addr32 = iph->saddr;
212
213        entry->dport = udph->dest;
214        entry->sport = udph->source;
215
216        entry->length = length;
217        memcpy(entry->data, start, length);
218
219        for (i = 0; i < length; i++)
[234]220                if (unlikely(entry->data[i] == '\n'))
[232]221                        entry->data[i] = ' ';
222
223        return entry;
224}
225
226static void
227ksyslog_entry_free(struct rcu_head *head)
228{
229        struct ksyslog_entry *entry = container_of(head, struct ksyslog_entry, rcu);
230        kfree(entry->data);
231        kfree(entry);
232}
233
234static int
235ksyslog_entry_add(struct ksyslog_queue *queue, struct ksyslog_entry *entry)
236{
[250]237        if (unlikely(atomic64_read(&queue->size) >= ksyslog_queue_size_max))
[232]238                return -ENOBUFS;
239        list_add_tail_rcu(&entry->list, &queue->head);
[250]240        WARN_ON(atomic64_inc_return(&queue->size) > ksyslog_queue_size_max);
[232]241        return 0;
242}
243
244static void
245ksyslog_entry_del(struct ksyslog_queue *queue, struct ksyslog_entry *entry, bool free)
246{
[250]247        WARN_ON(atomic64_dec_return(&queue->size) < 0);
[232]248        list_del_rcu(&entry->list);
249        if (free)
250                call_rcu(&entry->rcu, ksyslog_entry_free);
251}
252
253static void
254ksyslog_entry_destroy(struct ksyslog_queue *queue)
255{
256        struct ksyslog_entry *entry, *next;
257
258        list_for_each_entry_safe(entry, next, &queue->head, list)
259                ksyslog_entry_del(queue, entry, true);
260}
261
[268]262static int
263ksyslog_entry_format(char **buf, const struct ksyslog_entry *entry)
[232]264{
[268]265        *buf = kzalloc(54 + entry->length + 2, GFP_ATOMIC);
266        if (unlikely(*buf == NULL))
267                return -ENOMEM;
[232]268
[268]269        return sprintf(*buf, "%llu %s.%s %u.%u.%u.%u %.*s\n",
270                       timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
271                       ksyslog_facility_str(entry->facility),
272                       ksyslog_severity_str(entry->severity),
273                       entry->saddr.addr8[0], entry->saddr.addr8[1],
274                       entry->saddr.addr8[2], entry->saddr.addr8[3],
275                       (int)entry->length, entry->data);
276}
277
278static bool
279ksyslog_entry_write(struct file *file, struct ksyslog_entry *entry)
280{
281        int length;
282        char *buf;
283
284        length = ksyslog_entry_format(&buf, entry);
285
286        if (unlikely(length < 0))
287                return false;
288
289        if (unlikely(ksyslog_write(file, buf, length) != length)) {
290                kfree(buf);
291                return false;
[232]292        }
[268]293
294        kfree(buf);
295        return true;
[232]296}
297
298static void
[269]299ksyslog_work_register_cpu(int cpu, struct delayed_work *work, unsigned long timer)
300{
301        queue_delayed_work_on(cpu, ksyslog_wq, work, timer * HZ / 1000);
302}
303
304static void
[232]305ksyslog_work_register(unsigned long timer)
306{
[269]307        int cpu;
308
309        for_each_possible_cpu(cpu)
310                ksyslog_work_register_cpu(cpu, per_cpu_ptr(ksyslog_work, cpu), timer);
[232]311}
312
313static void
314ksyslog_work_unregister(void)
315{
[269]316        int cpu;
317
318        for_each_possible_cpu(cpu)
319                cancel_delayed_work_sync(per_cpu_ptr(ksyslog_work, cpu));
[232]320}
321
322static void
323ksyslog_work_handler(struct work_struct *work)
324{
325        struct file *file = NULL;
[268]326        struct ksyslog_entry *entry;
[232]327
[268]328        file = ksyslog_open(ksyslog_path);
329        if (unlikely(IS_ERR(file)))
[250]330                goto out;
[232]331
[268]332        while (true) {
333                bool write_ok;
[232]334
[242]335                spin_lock_bh(&ksyslog_queue.lock);
[268]336                entry = list_first_or_null_rcu(&ksyslog_queue.head,
337                                               struct ksyslog_entry, list);
338                if (!entry) {
339                        spin_unlock_bh(&ksyslog_queue.lock);
340                        break;
341                }
342                ksyslog_entry_del(&ksyslog_queue, entry, false);
[242]343                spin_unlock_bh(&ksyslog_queue.lock);
[232]344
[268]345                spin_lock(&ksyslog_write_lock);
346                write_ok = ksyslog_entry_write(file, entry);
347                spin_unlock(&ksyslog_write_lock);
[232]348
[268]349                if (likely(write_ok)) {
350                        ksyslog_stats_add_write(&ksyslog_queue, entry->length);
351                } else {
[250]352                        ksyslog_stats_add_drop(&ksyslog_queue, entry->length);
[232]353                        ksyslog_drop_warning(entry);
354                }
[268]355
356                call_rcu(&entry->rcu, ksyslog_entry_free);
[232]357        }
[234]358
[232]359        ksyslog_close(file);
360
361out:
[269]362        ksyslog_work_register_cpu(smp_processor_id(),
363                                  per_cpu_ptr(ksyslog_work, smp_processor_id()),
364                                  ksyslog_flush_interval);
[232]365}
366
367static int
368ksyslog_rcv(struct sock *sk, struct sk_buff *skb)
369{
370        int err;
371        struct iphdr *iph;
372        struct udphdr *udph;
373        struct ksyslog_entry *entry;
374
[250]375        if (unlikely(skb_linearize(skb))) {
376                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
377                goto out;
378        }
[232]379
380        iph = ip_hdr(skb);
381        udph = udp_hdr(skb);
382
[250]383        if (unlikely(!skb_pull(skb, sizeof(*udph)))) {
384                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
385                goto out;
386        }
[232]387
388        entry = ksyslog_entry_create(skb, iph, udph);
[250]389        if (unlikely(IS_ERR(entry))) {
390                if (PTR_ERR(entry) == -EINVAL) {
391                        ksyslog_stats_add_discard(&ksyslog_queue, skb->len);
392                        goto out;
393                }
[232]394
[250]395                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
396                goto out;
397        }
398
[242]399        spin_lock_bh(&ksyslog_queue.lock);
[232]400        err = ksyslog_entry_add(&ksyslog_queue, entry);
[242]401        spin_unlock_bh(&ksyslog_queue.lock);
[232]402
[241]403        if (unlikely(err)) {
[250]404                ksyslog_stats_add_drop(&ksyslog_queue, entry->length);
[241]405                ksyslog_drop_warning(entry);
[232]406                ksyslog_entry_free(&entry->rcu);
[250]407                goto out;
[241]408        }
[232]409
410out:
411        consume_skb(skb);
412        return 0;
413}
414
415#ifdef CONFIG_PROC_FS
416static void *
[240]417ksyslog_rculist_seq_start(struct seq_file *seq, loff_t *pos)
[232]418{
419        struct list_head *lh, *head = seq->private;
420        loff_t ppos = *pos;
421
422        rcu_read_lock();
423
424        __list_for_each_rcu(lh, head)
425                if (ppos-- == 0)
426                        return lh;
427
428        return NULL;
429}
430
431static void *
[240]432ksyslog_rculist_seq_next(struct seq_file *seq, void *v, loff_t *pos)
[232]433{
434        struct list_head *lh = rcu_dereference(((struct list_head *)v)->next);
435        ++(*pos);
436        return lh == seq->private ? NULL : lh;
437}
438
439static void
[240]440ksyslog_rculist_seq_stop(struct seq_file *seq, void *v)
[232]441{
442        rcu_read_unlock();
443}
444
445static int
446ksyslog_queue_seq_show(struct seq_file *seq, void *v)
447{
448        const struct ksyslog_entry *entry = list_entry_rcu(v, struct ksyslog_entry, list);
449
[233]450        seq_printf(seq, "%llu %s.%s %u.%u.%u.%u %.*s\n",
[232]451                   timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
[233]452                   ksyslog_facility_str(entry->facility),
453                   ksyslog_severity_str(entry->severity),
[232]454                   entry->saddr.addr8[0], entry->saddr.addr8[1],
455                   entry->saddr.addr8[2], entry->saddr.addr8[3],
456                   (int)entry->length, entry->data);
457
458        return 0;
459}
460
461static struct seq_operations ksyslog_queue_seq_ops = {
[240]462        .start = ksyslog_rculist_seq_start,
463        .next  = ksyslog_rculist_seq_next,
464        .stop  = ksyslog_rculist_seq_stop,
[232]465        .show  = ksyslog_queue_seq_show,
466};
467
468static int
469ksyslog_queue_seq_open(struct inode *inode, struct file *file)
470{
471        int err = seq_open(file, &ksyslog_queue_seq_ops);
472
473        if (!err)
[246]474                ((struct seq_file *)file->private_data)->private = PDE_DATA(inode);
[232]475
476        return err;
477}
478
479static struct file_operations ksyslog_queue_fops = {
480        .owner   = THIS_MODULE,
481        .open    = ksyslog_queue_seq_open,
482        .read    = seq_read,
483        .llseek  = seq_lseek,
484        .release = seq_release,
485};
486
487static int
[250]488ksyslog_size_seq_show(struct seq_file *seq, void *v)
[240]489{
[250]490        seq_printf(seq, "%lu\n", atomic64_read(&ksyslog_queue.size));
[240]491        return 0;
492}
493
494static int
[250]495ksyslog_size_seq_open(struct inode *inode, struct file *file)
[240]496{
[250]497        return single_open(file, ksyslog_size_seq_show, PDE_DATA(inode));
[240]498}
499
[241]500static int
[250]501ksyslog_stats_seq_show(struct seq_file *seq, void *v)
[241]502{
[250]503        int i;
504        struct ksyslog_stats stats;
[241]505
[250]506        memset(&stats, 0, sizeof(stats));
[241]507
[250]508        for_each_possible_cpu(i) {
509                const struct ksyslog_stats *percpu_stats;
510                struct ksyslog_stats local_stats;
511                unsigned int start;
512
513                percpu_stats = per_cpu_ptr(ksyslog_queue.stats, i);
514
515                do {
516                        start = u64_stats_fetch_begin_bh(&percpu_stats->sync);
517                        local_stats = *percpu_stats;
518                } while (u64_stats_fetch_retry_bh(&percpu_stats->sync, start));
519
520                stats.write_bytes += local_stats.write_bytes;
521                stats.write_packets += local_stats.write_packets;
522                stats.drop_bytes += local_stats.drop_bytes;
523                stats.drop_packets += local_stats.drop_packets;
524                stats.discard_bytes += local_stats.discard_bytes;
525                stats.discard_packets += local_stats.discard_packets;
526        }
527
528        seq_puts(seq,   "{\n");
529        seq_puts(seq,   \"write\": {\n");
530        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.write_bytes);
531        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.write_packets);
532        seq_puts(seq,   "  },\n");
533        seq_puts(seq,   \"drop\": {\n");
534        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.drop_bytes);
535        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.drop_packets);
536        seq_puts(seq,   "  },\n");
537        seq_puts(seq,   \"discard\": {\n");
538        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.discard_bytes);
539        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.discard_packets);
540        seq_puts(seq,   "  }\n");
541        seq_puts(seq,   "}\n");
542
[241]543        return 0;
544}
545
546static int
[250]547ksyslog_stats_seq_open(struct inode *inode, struct file *file)
[241]548{
[250]549        return single_open(file, ksyslog_stats_seq_show, PDE_DATA(inode));
[241]550}
551
[250]552static struct file_operations ksyslog_size_fops = {
[240]553        .owner   = THIS_MODULE,
[250]554        .open    = ksyslog_size_seq_open,
[240]555        .read    = seq_read,
556        .llseek  = seq_lseek,
557        .release = single_release,
558};
559
[250]560static struct file_operations ksyslog_stats_fops = {
[241]561        .owner   = THIS_MODULE,
[250]562        .open    = ksyslog_stats_seq_open,
[241]563        .read    = seq_read,
564        .llseek  = seq_lseek,
565        .release = single_release,
566};
567
568static void
569ksyslog_proc_destroy(void)
570{
571        if (ksyslog_proc_queue)
[246]572                remove_proc_entry("queue", ksyslog_procdir);
[241]573        ksyslog_proc_queue = NULL;
574
[250]575        if (ksyslog_proc_size)
576                remove_proc_entry("size", ksyslog_procdir);
577        ksyslog_proc_size = NULL;
[241]578
[250]579        if (ksyslog_proc_stats)
580                remove_proc_entry("stats", ksyslog_procdir);
581        ksyslog_proc_stats = NULL;
[241]582
583        if (ksyslog_procdir)
[246]584                remove_proc_entry("ksyslog", NULL);
[241]585        ksyslog_procdir = NULL;
586}
587
[240]588static int
[232]589ksyslog_proc_init(void)
590{
591        ksyslog_procdir = proc_mkdir("ksyslog", NULL);
592        if (ksyslog_procdir == NULL) {
[250]593                pr_err("ksyslog: proc_mkdir failed\n");
[241]594                goto err;
[232]595        }
596
[239]597        ksyslog_proc_queue = proc_create_data("queue", S_IRUGO, ksyslog_procdir,
598                                              &ksyslog_queue_fops, &ksyslog_queue.head);
[232]599        if (ksyslog_proc_queue == NULL) {
[250]600                pr_err("ksyslog: proc_create(queue) failed\n");
[241]601                goto err;
[232]602        }
603
[250]604        ksyslog_proc_size = proc_create("size", S_IRUGO, ksyslog_procdir,
605                                        &ksyslog_size_fops);
606        if (ksyslog_proc_size == NULL) {
607                pr_err("ksyslog: proc_create(size) failed\n");
[241]608                goto err;
[240]609        }
610
[250]611        ksyslog_proc_stats = proc_create("stats", S_IRUGO, ksyslog_procdir,
612                                         &ksyslog_stats_fops);
613        if (ksyslog_proc_stats == NULL) {
614                pr_err("ksyslog: proc_create(stats) failed\n");
[241]615                goto err;
616        }
[232]617
[241]618        return 0;
[232]619
[241]620err:
621        ksyslog_proc_destroy();
622        return -ENOMEM;
[232]623}
624#endif
625
626static void
627ksyslog_finish(void)
628{
629        if (ksyslog_rcv_sk)
630                sock_release(ksyslog_rcv_sk);
631        ksyslog_rcv_sk = NULL;
632
[269]633        if (ksyslog_work) {
[232]634                ksyslog_work_unregister();
[269]635                free_percpu(ksyslog_work);
636        }
637        ksyslog_work = NULL;
638
639        if (ksyslog_wq)
[232]640                destroy_workqueue(ksyslog_wq);
641        ksyslog_wq = NULL;
642
643#ifdef CONFIG_PROC_FS
644        ksyslog_proc_destroy();
645#endif
646
647        ksyslog_entry_destroy(&ksyslog_queue);
[237]648        rcu_barrier();
[250]649
650        ksyslog_queue_uninit(&ksyslog_queue);
[232]651}
652
653static int __init
654ksyslog_init(void)
655{
[269]656        int cpu, err;
[232]657        struct sockaddr_in sin;
658
[250]659        err = ksyslog_queue_init(&ksyslog_queue);
660        if (err)
661                goto err;
[232]662
663#ifdef CONFIG_PROC_FS
664        err = ksyslog_proc_init();
665        if (err)
666                goto err;
667#endif
668
[268]669        ksyslog_wq = create_workqueue("ksyslog");
[232]670        if (ksyslog_wq == NULL) {
[250]671                pr_err("ksyslog: create_workqueue failed\n");
[232]672                err = -ENOMEM;
673                goto err;
674        }
675
[269]676        ksyslog_work = alloc_percpu(struct delayed_work);
677        if (!ksyslog_work) {
678                pr_err("ksyslog: alloc_percpu(ksyslog_work) failed\n");
679                err = -ENOMEM;
680                goto err;
681        }
682        for_each_possible_cpu(cpu)
683                INIT_DELAYED_WORK(per_cpu_ptr(ksyslog_work, cpu), ksyslog_work_handler);
[232]684
685        err = sock_create(AF_INET, SOCK_DGRAM, 0, &ksyslog_rcv_sk);
686        if (err) {
[250]687                pr_err("ksyslog: sock_create failed\n");
[232]688                goto err;
689        }
690
691        sin.sin_family = AF_INET;
692        sin.sin_addr.s_addr = in_aton(ksyslog_host);
693        sin.sin_port = htons(ksyslog_port);
694
695        err = kernel_bind(ksyslog_rcv_sk, (struct sockaddr *)&sin,
696                          sizeof(struct sockaddr_in));
697        if (err) {
[250]698                pr_err("ksyslog: kernel_bind failed\n");
[232]699                goto err;
700        }
701
[247]702        ksyslog_work_register(ksyslog_flush_interval);
703
[232]704        udp_sk(ksyslog_rcv_sk->sk)->encap_type = UDP_ENCAP_KSYSLOG;
705        udp_sk(ksyslog_rcv_sk->sk)->encap_rcv = ksyslog_rcv;
[247]706        udp_encap_enable();
[232]707
708        return 0;
709
710err:
711        ksyslog_finish();
712        return err;
713}
714
715static void __exit
716ksyslog_exit(void)
717{
718        ksyslog_finish();
719}
720
721module_init(ksyslog_init);
722module_exit(ksyslog_exit);
723
724MODULE_AUTHOR("Atzm WATANABE");
725MODULE_DESCRIPTION("In-kernel syslog receiver");
726MODULE_LICENSE("GPL");
Note: See TracBrowser for help on using the repository browser.