Changeset 1579

Show
Ignore:
Timestamp:
03/04/10 11:28:10 (5 months ago)
Author:
marek
Message:

batman-adv: don't have interrupts disabled while sending.

send_vis_packets() would disable interrupts before calling
dev_queue_xmit() which resulting in a backtrace in local_bh_enable().
Fix this by using kref on the vis_info object so that we can call
send_vis_packets() without holding vis_hash_lock. vis_hash_lock also
used to protect recv_list, so we now need a new lock to protect that
instead of vis_hash_lock.

Also a few checkpatch cleanups.

Reported-by: Linus Luessing <linus.luessing@…>
Signed-off-by: Andrew Lunn <andrew@…>
Signed-off-by: Marek Lindner <lindner_marek@…>
Signed-off-by: Simon Wunderlich <siwu@…>

Location:
trunk/batman-adv-kernelland
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/batman-adv-kernelland/vis.c

    r1557 r1579  
    3131struct hashtable_t *vis_hash; 
    3232DEFINE_SPINLOCK(vis_hash_lock); 
     33static DEFINE_SPINLOCK(recv_list_lock); 
    3334static struct vis_info *my_vis_info; 
    3435static struct list_head send_list;      /* always locked with vis_hash_lock */ 
     
    3738 
    3839/* free the info */ 
    39 static void free_info(void *data) 
    40 { 
    41         struct vis_info *info = data; 
     40static void free_info(struct kref *ref) 
     41{ 
     42        struct vis_info *info = container_of(ref, struct vis_info, refcount); 
    4243        struct recvlist_node *entry, *tmp; 
     44        unsigned long flags; 
    4345 
    4446        list_del_init(&info->send_list); 
     47        spin_lock_irqsave(&recv_list_lock, flags); 
    4548        list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { 
    4649                list_del(&entry->list); 
    4750                kfree(entry); 
    4851        } 
     52        spin_unlock_irqrestore(&recv_list_lock, flags); 
    4953        kfree(info); 
    5054} 
     
    144148} 
    145149 
     150/* add the info packet to the send list, if it was not 
     151 * already linked in. */ 
     152static void send_list_add(struct vis_info *info) 
     153{ 
     154        if (list_empty(&info->send_list)) { 
     155                kref_get(&info->refcount); 
     156                list_add_tail(&info->send_list, &send_list); 
     157        } 
     158} 
     159 
     160/* delete the info packet from the send list, if it was 
     161 * linked in. */ 
     162static void send_list_del(struct vis_info *info) 
     163{ 
     164        if (!list_empty(&info->send_list)) { 
     165                list_del_init(&info->send_list); 
     166                kref_put(&info->refcount, free_info); 
     167        } 
     168} 
     169 
    146170/* tries to add one entry to the receive list. */ 
    147171static void recv_list_add(struct list_head *recv_list, char *mac) 
    148172{ 
    149173        struct recvlist_node *entry; 
     174        unsigned long flags; 
     175 
    150176        entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); 
    151177        if (!entry) 
     
    153179 
    154180        memcpy(entry->mac, mac, ETH_ALEN); 
     181        spin_lock_irqsave(&recv_list_lock, flags); 
    155182        list_add_tail(&entry->list, recv_list); 
     183        spin_unlock_irqrestore(&recv_list_lock, flags); 
    156184} 
    157185 
     
    160188{ 
    161189        struct recvlist_node *entry; 
    162  
     190        unsigned long flags; 
     191 
     192        spin_lock_irqsave(&recv_list_lock, flags); 
    163193        list_for_each_entry(entry, recv_list, list) { 
    164                 if (memcmp(entry->mac, mac, ETH_ALEN) == 0) 
     194                if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { 
     195                        spin_unlock_irqrestore(&recv_list_lock, flags); 
    165196                        return 1; 
    166         } 
    167  
     197                } 
     198        } 
     199        spin_unlock_irqrestore(&recv_list_lock, flags); 
    168200        return 0; 
    169201} 
    170202 
    171203/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, 
    172  * broken.. ).  vis hash must be locked outside.  is_new is set when the packet 
     204 * broken.. ).  vis hash must be locked outside.  is_new is set when the packet 
    173205 * is newer than old entries in the hash. */ 
    174206static struct vis_info *add_packet(struct vis_packet *vis_packet, 
    175                                    int vis_info_len, int *is_new) 
     207                                   int vis_info_len, int *is_new, 
     208                                   int make_broadcast) 
    176209{ 
    177210        struct vis_info *info, *old_info; 
     
    200233                /* remove old entry */ 
    201234                hash_remove(vis_hash, old_info); 
    202                 free_info(old_info); 
     235                send_list_del(old_info); 
     236                kref_put(&old_info->refcount, free_info); 
    203237        } 
    204238 
     
    207241                return NULL; 
    208242 
     243        kref_init(&info->refcount); 
    209244        INIT_LIST_HEAD(&info->send_list); 
    210245        INIT_LIST_HEAD(&info->recv_list); 
     
    216251        *is_new = 1; 
    217252 
     253        /* Make it a broadcast packet, if required */ 
     254        if (make_broadcast) 
     255                memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); 
     256 
    218257        /* repair if entries is longer than packet. */ 
    219258        if (info->packet.entries * sizeof(struct vis_info_entry) > vis_info_len) 
    220                 info->packet.entries = vis_info_len / sizeof(struct vis_info_entry); 
     259                info->packet.entries = vis_info_len / 
     260                        sizeof(struct vis_info_entry); 
    221261 
    222262        recv_list_add(&info->recv_list, info->packet.sender_orig); 
     
    225265        if (hash_add(vis_hash, info) < 0) { 
    226266                /* did not work (for some reason) */ 
    227                 free_info(info); 
     267                kref_put(&old_info->refcount, free_info); 
    228268                info = NULL; 
    229269        } 
     
    236276{ 
    237277        struct vis_info *info; 
    238         int is_new; 
     278        int is_new, make_broadcast; 
    239279        unsigned long flags; 
    240280        int vis_server = atomic_read(&vis_mode); 
    241281 
     282        make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); 
     283 
    242284        spin_lock_irqsave(&vis_hash_lock, flags); 
    243         info = add_packet(vis_packet, vis_info_len, &is_new); 
     285        info = add_packet(vis_packet, vis_info_len, &is_new, make_broadcast); 
    244286        if (info == NULL) 
    245287                goto end; 
     
    247289        /* only if we are server ourselves and packet is newer than the one in 
    248290         * hash.*/ 
    249         if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) { 
    250                 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); 
    251                 if (list_empty(&info->send_list)) 
    252                         list_add_tail(&info->send_list, &send_list); 
    253         } 
     291        if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) 
     292                send_list_add(info); 
    254293end: 
    255294        spin_unlock_irqrestore(&vis_hash_lock, flags); 
     
    264303        unsigned long flags; 
    265304        int vis_server = atomic_read(&vis_mode); 
     305        int are_target = 0; 
    266306 
    267307        /* clients shall not broadcast. */ 
     
    269309                return; 
    270310 
     311        /* Are we the target for this VIS packet? */ 
     312        if (vis_server == VIS_TYPE_SERVER_SYNC  && 
     313            is_my_mac(vis_packet->target_orig)) 
     314                are_target = 1; 
     315 
    271316        spin_lock_irqsave(&vis_hash_lock, flags); 
    272         info = add_packet(vis_packet, vis_info_len, &is_new); 
     317        info = add_packet(vis_packet, vis_info_len, &is_new, are_target); 
    273318        if (info == NULL) 
    274319                goto end; 
     
    277322 
    278323        /* send only if we're the target server or ... */ 
    279         if (vis_server == VIS_TYPE_SERVER_SYNC  && 
    280             is_my_mac(info->packet.target_orig) && 
    281             is_new) { 
     324        if (are_target && is_new) { 
    282325                info->packet.vis_type = VIS_TYPE_SERVER_SYNC;   /* upgrade! */ 
    283                 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); 
    284                 if (list_empty(&info->send_list)) 
    285                         list_add_tail(&info->send_list, &send_list); 
     326                send_list_add(info); 
    286327 
    287328                /* ... we're not the recipient (and thus need to forward). */ 
    288329        } else if (!is_my_mac(info->packet.target_orig)) { 
    289                 if (list_empty(&info->send_list)) 
    290                         list_add_tail(&info->send_list, &send_list); 
     330                send_list_add(info); 
    291331        } 
    292332end: 
     
    363403                orig_node = hashit_global.bucket->data; 
    364404                if (orig_node->router != NULL 
    365                         && compare_orig(orig_node->router->addr, orig_node->orig) 
     405                        && compare_orig(orig_node->router->addr, 
     406                                        orig_node->orig) 
    366407                        && orig_node->batman_if 
    367408                        && (orig_node->batman_if->if_active == IF_ACTIVE) 
     
    370411                        /* fill one entry into buffer. */ 
    371412                        entry = &entry_array[info->packet.entries]; 
    372                         memcpy(entry->src, orig_node->batman_if->net_dev->dev_addr, ETH_ALEN); 
     413                        memcpy(entry->src, 
     414                               orig_node->batman_if->net_dev->dev_addr, 
     415                               ETH_ALEN); 
    373416                        memcpy(entry->dest, orig_node->orig, ETH_ALEN); 
    374417                        entry->quality = orig_node->router->tq_avg; 
     
    402445} 
    403446 
     447/* free old vis packets. Must be called with this vis_hash_lock 
     448 * held */ 
    404449static void purge_vis_packets(void) 
    405450{ 
     
    414459                               info->first_seen + (VIS_TIMEOUT*HZ)/1000)) { 
    415460                        hash_remove_bucket(vis_hash, &hashit); 
    416                         free_info(info); 
     461                        send_list_del(info); 
     462                        kref_put(&info->refcount, free_info); 
    417463                } 
    418464        } 
     
    424470        struct orig_node *orig_node; 
    425471        unsigned long flags; 
     472        struct batman_if *batman_if; 
     473        uint8_t dstaddr[ETH_ALEN]; 
    426474 
    427475        spin_lock_irqsave(&orig_hash_lock, flags); 
     
    432480 
    433481                /* if it's a vis server and reachable, send it. */ 
    434                 if (orig_node && 
    435                     (orig_node->flags & VIS_SERVER) && 
    436                     orig_node->batman_if && 
    437                     orig_node->router) { 
    438  
    439                         /* don't send it if we already received the packet from 
    440                          * this node. */ 
    441                         if (recv_list_is_in(&info->recv_list, orig_node->orig)) 
    442                                 continue; 
    443  
    444                         memcpy(info->packet.target_orig, 
    445                                orig_node->orig, ETH_ALEN); 
    446  
    447                         send_raw_packet((unsigned char *) &info->packet, 
    448                                         packet_length, 
    449                                         orig_node->batman_if, 
    450                                         orig_node->router->addr); 
    451                 } 
    452         } 
     482                if ((!orig_node) || (!orig_node->batman_if) || 
     483                    (!orig_node->router)) 
     484                        continue; 
     485                if (!(orig_node->flags & VIS_SERVER)) 
     486                        continue; 
     487                /* don't send it if we already received the packet from 
     488                 * this node. */ 
     489                if (recv_list_is_in(&info->recv_list, orig_node->orig)) 
     490                        continue; 
     491 
     492                memcpy(info->packet.target_orig, orig_node->orig, ETH_ALEN); 
     493                batman_if = orig_node->batman_if; 
     494                memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 
     495                spin_unlock_irqrestore(&orig_hash_lock, flags); 
     496 
     497                send_raw_packet((unsigned char *)&info->packet, 
     498                                packet_length, batman_if, dstaddr); 
     499 
     500                spin_lock_irqsave(&orig_hash_lock, flags); 
     501 
     502        } 
     503        spin_unlock_irqrestore(&orig_hash_lock, flags); 
    453504        memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); 
    454         spin_unlock_irqrestore(&orig_hash_lock, flags); 
    455505} 
    456506 
     
    459509        struct orig_node *orig_node; 
    460510        unsigned long flags; 
     511        struct batman_if *batman_if; 
     512        uint8_t dstaddr[ETH_ALEN]; 
    461513 
    462514        spin_lock_irqsave(&orig_hash_lock, flags); 
     
    464516                     hash_find(orig_hash, info->packet.target_orig)); 
    465517 
    466         if ((orig_node != NULL) && 
    467             (orig_node->batman_if != NULL) && 
    468             (orig_node->router != NULL)) { 
    469                 send_raw_packet((unsigned char *) &info->packet, packet_length, 
    470                                 orig_node->batman_if, 
    471                                 orig_node->router->addr); 
    472         } 
     518        if ((!orig_node) || (!orig_node->batman_if) || (!orig_node->router)) 
     519                goto out; 
     520 
     521        /* don't lock while sending the packets ... we therefore 
     522         * copy the required data before sending */ 
     523        batman_if = orig_node->batman_if; 
     524        memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 
     525        spin_unlock_irqrestore(&orig_hash_lock, flags); 
     526 
     527        send_raw_packet((unsigned char *)&info->packet, 
     528                        packet_length, batman_if, dstaddr); 
     529        return; 
     530 
     531out: 
    473532        spin_unlock_irqrestore(&orig_hash_lock, flags); 
    474533} 
     
    504563 
    505564        spin_lock_irqsave(&vis_hash_lock, flags); 
     565 
    506566        purge_vis_packets(); 
    507567 
    508         if (generate_vis_packet() == 0) 
     568        if (generate_vis_packet() == 0) { 
    509569                /* schedule if generation was successful */ 
    510                 list_add_tail(&my_vis_info->send_list, &send_list); 
     570                send_list_add(my_vis_info); 
     571        } 
    511572 
    512573        list_for_each_entry_safe(info, temp, &send_list, send_list) { 
    513                 list_del_init(&info->send_list); 
     574 
     575                kref_get(&info->refcount); 
     576                spin_unlock_irqrestore(&vis_hash_lock, flags); 
     577 
    514578                send_vis_packet(info); 
     579 
     580                spin_lock_irqsave(&vis_hash_lock, flags); 
     581                send_list_del(info); 
     582                kref_put(&info->refcount, free_info); 
    515583        } 
    516584        spin_unlock_irqrestore(&vis_hash_lock, flags); 
     
    545613        INIT_LIST_HEAD(&my_vis_info->recv_list); 
    546614        INIT_LIST_HEAD(&my_vis_info->send_list); 
     615        kref_init(&my_vis_info->refcount); 
    547616        my_vis_info->packet.version = COMPAT_VERSION; 
    548617        my_vis_info->packet.packet_type = BAT_VIS; 
     
    558627        if (hash_add(vis_hash, my_vis_info) < 0) { 
    559628                printk(KERN_ERR 
    560                           "batman-adv:Can't add own vis packet into hash\n"); 
    561                 free_info(my_vis_info); /* not in hash, need to remove it 
    562                                          * manually. */ 
     629                       "batman-adv:Can't add own vis packet into hash\n"); 
     630                /* not in hash, need to remove it manually. */ 
     631                kref_put(&my_vis_info->refcount, free_info); 
    563632                goto err; 
    564633        } 
     
    574643} 
    575644 
     645/* Decrease the reference count on a hash item info */ 
     646static void free_info_ref(void *data) 
     647{ 
     648        struct vis_info *info = data; 
     649 
     650        send_list_del(info); 
     651        kref_put(&info->refcount, free_info); 
     652} 
     653 
    576654/* shutdown vis-server */ 
    577655void vis_quit(void) 
     
    585663        spin_lock_irqsave(&vis_hash_lock, flags); 
    586664        /* properly remove, kill timers ... */ 
    587         hash_delete(vis_hash, free_info); 
     665        hash_delete(vis_hash, free_info_ref); 
    588666        vis_hash = NULL; 
    589667        my_vis_info = NULL; 
     
    595673{ 
    596674        queue_delayed_work(bat_event_workqueue, &vis_timer_wq, 
    597                            (atomic_read(&vis_interval) * HZ ) / 1000); 
    598 } 
     675                           (atomic_read(&vis_interval) * HZ) / 1000); 
     676} 
  • trunk/batman-adv-kernelland/vis.h

    r1557 r1579  
    3030                             * from.  we should not reply to them. */ 
    3131        struct list_head send_list; 
     32        struct kref refcount; 
    3233        /* this packet might be part of the vis send queue. */ 
    3334        struct vis_packet packet;