recently i noticed a little problem with my lane interfaces not
being unregistered completely when i rmmod'ed the module -- it would
stick with a single outstanding reference to the network device. also,
if i kept ifup'ing/ifdown'ing, eventually i would get an oops in
kernel/timer.c:377.
i have tracked this down to a problem with igmp_group_dropped() and
the newish (to me anyway) igmp3 support. during ip_mc_down(), seems
like its trying to stop all the timers and drop any refs that a timer
might have to the inet device:
in_dev->mr_ifc_count = 0;
if (del_timer(&in_dev->mr_ifc_timer))
__in_dev_put(in_dev);
then it goes on to delete the multicast groups:
for (i=in_dev->mc_list; i; i=i->next)
igmp_group_dropped(i);
unfortunately igmp_group_dropped() seems to schedule the mr_ifc_timer
(via igmp_ifc_event) in an effort to inform the network its no
longer a member of the group (or so i think). this isnt a particular
problem, except that the timers use __in_dev_put(), so if the timer
is the last guy to dec the refcnt on inet device, the inet destroy
function is never called and inet never drops its last reference to
to the network interface. i am guessing that ip_mc_down() is supposed
to get the igmp stack to drop all references to the inet device.
some possible solutions (assuming the above is correct):
in igmp_group_dropped() dont bother trying to send drop messages
if !IFF_UP.
in ip_mc_down(), delete the mr_ifc_timer AFTER dropping the group
membership. i guess i would learn toward this one. however, you
might also need delete the timer again in ip_mc_destroy_dev() since
it also calls igmp_group_dropped() after its too late to send anything
to the network.
|