Changeset 268


Ignore:
Timestamp:
05/03/14 04:14:58 (11 years ago)
Author:
atzm
Message:

optimize workqueues

Location:
ksyslog/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ksyslog/trunk/compat.h

    r264 r268  
    1313                pos != (head); \ 
    1414                pos = rcu_dereference_raw(list_next_rcu(pos))) 
     15#endif 
     16 
     17#ifndef list_first_or_null_rcu 
     18#define list_first_or_null_rcu(ptr, type, member) \ 
     19({ \ 
     20        struct list_head *__ptr = (ptr); \ 
     21        struct list_head *__next = ACCESS_ONCE(__ptr->next); \ 
     22        likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \ 
     23 }) 
    1524#endif 
    1625 
  • ksyslog/trunk/ksyslog.c

    r264 r268  
    3838static ulong ksyslog_flush_interval = 45;  /* milliseconds */ 
    3939 
     40static DEFINE_SPINLOCK(ksyslog_write_lock); 
     41 
    4042module_param(ksyslog_host, charp, 0444); 
    4143module_param(ksyslog_port, ushort, 0444); 
     
    135137ksyslog_drop_warning(const struct ksyslog_entry *entry) 
    136138{ 
    137         pr_warn("ksyslog: dropped: %llu %s.%s %u.%u.%u.%u %.*s\n", 
    138                 timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000, 
    139                 ksyslog_facility_str(entry->facility), 
    140                 ksyslog_severity_str(entry->severity), 
    141                 entry->saddr.addr8[0], entry->saddr.addr8[1], 
    142                 entry->saddr.addr8[2], entry->saddr.addr8[3], 
    143                 (int)entry->length, entry->data); 
    144 } 
    145  
    146 static int 
    147 ksyslog_format(char **buf, const struct ksyslog_entry *entry) 
     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); 
     146} 
     147 
     148static struct ksyslog_entry * 
     149ksyslog_entry_create(const struct sk_buff *skb, 
     150                     const struct iphdr *iph, const struct udphdr *udph) 
     151{ 
     152        struct ksyslog_entry *entry; 
     153        unsigned int priority, facility, severity, month, day, hour, minute, second; 
     154        unsigned char *start, month_s[4]; 
     155        struct tm tm; 
     156        int length, i; 
     157 
     158        if (sscanf(skb->data, "<%3u>%3s %2u %2u:%2u:%2u ", 
     159                   &priority, month_s, &day, &hour, &minute, &second) != 6) 
     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 
     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 
     187        entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 
     188        if (unlikely(entry == NULL)) 
     189                return ERR_PTR(-ENOMEM); 
     190 
     191        length = skb->len - (start - skb->data); 
     192        entry->data = kzalloc(length, GFP_ATOMIC); 
     193        if (unlikely(entry->data == NULL)) { 
     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 
     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; 
     207        entry->facility = facility; 
     208        entry->severity = severity; 
     209 
     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++) 
     220                if (unlikely(entry->data[i] == '\n')) 
     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{ 
     237        if (unlikely(atomic64_read(&queue->size) >= ksyslog_queue_size_max)) 
     238                return -ENOBUFS; 
     239        list_add_tail_rcu(&entry->list, &queue->head); 
     240        WARN_ON(atomic64_inc_return(&queue->size) > ksyslog_queue_size_max); 
     241        return 0; 
     242} 
     243 
     244static void 
     245ksyslog_entry_del(struct ksyslog_queue *queue, struct ksyslog_entry *entry, bool free) 
     246{ 
     247        WARN_ON(atomic64_dec_return(&queue->size) < 0); 
     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 
     262static int 
     263ksyslog_entry_format(char **buf, const struct ksyslog_entry *entry) 
    148264{ 
    149265        *buf = kzalloc(54 + entry->length + 2, GFP_ATOMIC); 
     
    160276} 
    161277 
    162 static struct ksyslog_entry * 
    163 ksyslog_entry_create(const struct sk_buff *skb, 
    164                      const struct iphdr *iph, const struct udphdr *udph) 
    165 { 
     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; 
     292        } 
     293 
     294        kfree(buf); 
     295        return true; 
     296} 
     297 
     298static void 
     299ksyslog_work_register(unsigned long timer) 
     300{ 
     301        queue_delayed_work(ksyslog_wq, &ksyslog_work, timer * HZ / 1000); 
     302} 
     303 
     304static void 
     305ksyslog_work_unregister(void) 
     306{ 
     307        cancel_delayed_work_sync(&ksyslog_work); 
     308} 
     309 
     310static void 
     311ksyslog_work_handler(struct work_struct *work) 
     312{ 
     313        struct file *file = NULL; 
    166314        struct ksyslog_entry *entry; 
    167         unsigned int priority, facility, severity, month, day, hour, minute, second; 
    168         unsigned char *start, month_s[4]; 
    169         struct tm tm; 
    170         int length, i; 
    171  
    172         if (sscanf(skb->data, "<%3u>%3s %2u %2u:%2u:%2u ", 
    173                    &priority, month_s, &day, &hour, &minute, &second) != 6) 
    174                 return ERR_PTR(-EINVAL); 
    175  
    176         start = memchr(skb->data, '>', 5); 
    177         if (start == NULL) 
    178                 return ERR_PTR(-EINVAL); 
    179         start++; 
    180  
    181         facility = priority >> 3; 
    182         severity = priority & 7; 
    183  
    184         if (facility >= __KSYSLOG_F_MAX) 
    185                 return ERR_PTR(-EINVAL); 
    186         if (severity >= __KSYSLOG_S_MAX) 
    187                 return ERR_PTR(-EINVAL); 
    188  
    189         month = ksyslog_month_num(month_s); 
    190         if (!month) 
    191                 return ERR_PTR(-EINVAL); 
    192         if (day > 31) 
    193                 return ERR_PTR(-EINVAL); 
    194         if (hour > 23) 
    195                 return ERR_PTR(-EINVAL); 
    196         if (minute > 59) 
    197                 return ERR_PTR(-EINVAL); 
    198         if (second > 59) 
    199                 return ERR_PTR(-EINVAL); 
    200  
    201         entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 
    202         if (unlikely(entry == NULL)) 
    203                 return ERR_PTR(-ENOMEM); 
    204  
    205         length = skb->len - (start - skb->data); 
    206         entry->data = kzalloc(length, GFP_ATOMIC); 
    207         if (unlikely(entry->data == NULL)) { 
    208                 kfree(entry); 
    209                 return ERR_PTR(-ENOMEM); 
    210         } 
    211  
    212         if (skb->tstamp.tv64) 
    213                 entry->tv = ktime_to_timeval(skb->tstamp); 
    214         else 
    215                 do_gettimeofday(&entry->tv); 
    216  
    217         time_to_tm(entry->tv.tv_sec, 0, &tm); 
    218         entry->time = mktime(tm.tm_year + 1900, month, day, hour, minute, second); 
    219  
    220         entry->priority = priority; 
    221         entry->facility = facility; 
    222         entry->severity = severity; 
    223  
    224         entry->daddr.addr32 = iph->daddr; 
    225         entry->saddr.addr32 = iph->saddr; 
    226  
    227         entry->dport = udph->dest; 
    228         entry->sport = udph->source; 
    229  
    230         entry->length = length; 
    231         memcpy(entry->data, start, length); 
    232  
    233         for (i = 0; i < length; i++) 
    234                 if (unlikely(entry->data[i] == '\n')) 
    235                         entry->data[i] = ' '; 
    236  
    237         return entry; 
    238 } 
    239  
    240 static void 
    241 ksyslog_entry_free(struct rcu_head *head) 
    242 { 
    243         struct ksyslog_entry *entry = container_of(head, struct ksyslog_entry, rcu); 
    244         kfree(entry->data); 
    245         kfree(entry); 
    246 } 
    247  
    248 static int 
    249 ksyslog_entry_add(struct ksyslog_queue *queue, struct ksyslog_entry *entry) 
    250 { 
    251         if (unlikely(atomic64_read(&queue->size) >= ksyslog_queue_size_max)) 
    252                 return -ENOBUFS; 
    253         list_add_tail_rcu(&entry->list, &queue->head); 
    254         WARN_ON(atomic64_inc_return(&queue->size) > ksyslog_queue_size_max); 
    255         return 0; 
    256 } 
    257  
    258 static void 
    259 ksyslog_entry_del(struct ksyslog_queue *queue, struct ksyslog_entry *entry, bool free) 
    260 { 
    261         WARN_ON(atomic64_dec_return(&queue->size) < 0); 
    262         list_del_rcu(&entry->list); 
    263         if (free) 
    264                 call_rcu(&entry->rcu, ksyslog_entry_free); 
    265 } 
    266  
    267 static void 
    268 ksyslog_entry_destroy(struct ksyslog_queue *queue) 
    269 { 
    270         struct ksyslog_entry *entry, *next; 
    271  
    272         list_for_each_entry_safe(entry, next, &queue->head, list) 
    273                 ksyslog_entry_del(queue, entry, true); 
    274 } 
    275  
    276 static void 
    277 ksyslog_entry_migrate(struct ksyslog_queue *from, struct ksyslog_queue *to) 
    278 { 
    279         struct ksyslog_entry *entry, *next; 
    280  
    281         list_for_each_entry_safe(entry, next, &from->head, list) { 
    282                 ksyslog_entry_del(from, entry, false); 
    283                 if (unlikely(ksyslog_entry_add(to, entry))) { 
    284                         ksyslog_stats_add_drop(from, entry->length); 
    285                         ksyslog_stats_add_drop(to, entry->length); 
    286                         ksyslog_drop_warning(entry); 
    287                         call_rcu(&entry->rcu, ksyslog_entry_free); 
     315 
     316        file = ksyslog_open(ksyslog_path); 
     317        if (unlikely(IS_ERR(file))) 
     318                goto out; 
     319 
     320        while (true) { 
     321                bool write_ok; 
     322 
     323                spin_lock_bh(&ksyslog_queue.lock); 
     324                entry = list_first_or_null_rcu(&ksyslog_queue.head, 
     325                                               struct ksyslog_entry, list); 
     326                if (!entry) { 
     327                        spin_unlock_bh(&ksyslog_queue.lock); 
     328                        break; 
    288329                } 
    289         } 
    290 } 
    291  
    292 static void 
    293 ksyslog_work_register(unsigned long timer) 
    294 { 
    295         queue_delayed_work(ksyslog_wq, &ksyslog_work, timer * HZ / 1000); 
    296 } 
    297  
    298 static void 
    299 ksyslog_work_unregister(void) 
    300 { 
    301         cancel_delayed_work_sync(&ksyslog_work); 
    302 } 
    303  
    304 static void 
    305 ksyslog_work_handler(struct work_struct *work) 
    306 { 
    307         struct file *file = NULL; 
    308         struct ksyslog_entry *entry, *next; 
    309         struct ksyslog_queue write_queue; 
    310  
    311         if (ksyslog_queue_init(&write_queue)) 
    312                 goto out; 
    313  
    314         spin_lock_bh(&ksyslog_queue.lock); 
    315         ksyslog_entry_migrate(&ksyslog_queue, &write_queue); 
    316         spin_unlock_bh(&ksyslog_queue.lock); 
    317  
    318         if (atomic64_read(&write_queue.size) <= 0) 
    319                 goto out; 
    320  
    321         file = ksyslog_open(ksyslog_path); 
    322         if (unlikely(IS_ERR(file))) { 
    323                 spin_lock_bh(&ksyslog_queue.lock); 
    324                 ksyslog_entry_migrate(&write_queue, &ksyslog_queue); 
     330                ksyslog_entry_del(&ksyslog_queue, entry, false); 
    325331                spin_unlock_bh(&ksyslog_queue.lock); 
    326                 goto out; 
    327         } 
    328  
    329         list_for_each_entry_safe(entry, next, &write_queue.head, list) { 
    330                 int length; 
    331                 char *buf; 
    332  
    333                 ksyslog_entry_del(&write_queue, entry, false); 
    334  
    335                 length = ksyslog_format(&buf, entry); 
    336                 if (unlikely(length < 0)) 
    337                         goto restore; 
    338  
    339                 if (unlikely(ksyslog_write(file, buf, length) != length)) { 
    340                         kfree(buf); 
    341                         goto restore; 
    342                 } 
    343  
    344                 ksyslog_stats_add_write(&ksyslog_queue, entry->length); 
    345                 kfree(buf); 
    346                 call_rcu(&entry->rcu, ksyslog_entry_free); 
    347                 continue; 
    348  
    349 restore: 
    350                 spin_lock_bh(&ksyslog_queue.lock); 
    351                 if (unlikely(ksyslog_entry_add(&ksyslog_queue, entry))) { 
     332 
     333                spin_lock(&ksyslog_write_lock); 
     334                write_ok = ksyslog_entry_write(file, entry); 
     335                spin_unlock(&ksyslog_write_lock); 
     336 
     337                if (likely(write_ok)) { 
     338                        ksyslog_stats_add_write(&ksyslog_queue, entry->length); 
     339                } else { 
    352340                        ksyslog_stats_add_drop(&ksyslog_queue, entry->length); 
    353341                        ksyslog_drop_warning(entry); 
    354                         call_rcu(&entry->rcu, ksyslog_entry_free); 
    355342                } 
    356                 spin_unlock_bh(&ksyslog_queue.lock); 
     343 
     344                call_rcu(&entry->rcu, ksyslog_entry_free); 
    357345        } 
    358346 
     
    360348 
    361349out: 
    362         ksyslog_queue_uninit(&write_queue); 
    363350        ksyslog_work_register(ksyslog_flush_interval); 
    364351} 
     
    662649#endif 
    663650 
    664         ksyslog_wq = create_singlethread_workqueue("ksyslog"); 
     651        ksyslog_wq = create_workqueue("ksyslog"); 
    665652        if (ksyslog_wq == NULL) { 
    666653                pr_err("ksyslog: create_workqueue failed\n"); 
Note: See TracChangeset for help on using the changeset viewer.