tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Locking question



Following up on Mark's query where ip6_output was called without
softnet_lock via a callchain of:

  ip6_output()
  mld_sendpkt()
  mld_start_listening()
  in6_addmulti()
  in6_joingroup()
  in6_update_ifa1()
  in6_update_ifa()
  in6_control1()
  in6_control()
  udp6_usrreq_wrapper()
  compat_ifioctl()
  ifioctl()
  soo_ioctl()
  sys_ioctl()
  sy_call()
  syscall()

I looked at where softnet_lock is and isn't acquired in the kernel.   I
think this is a simple case of mld_start_listening failing to acquire
the lock.

So I'd suggest just acquiring/releasing at start/end of
mld_{start,stop}_listening, as shown below.  However,
mld_start_listening can call mld_sendpkt, which acquires softnet_lock.
And, in6_addmulti does splsoftnet, but doesn't acquire softnet_lock.

From the mutex man page, it seems that it's not acceptable to enter a
mutex that one already holds.

It's also not clear to me why the kernel lock is involved.

wrong patch that will mutex_enter an already held mutex:

--- mld6.c.~1.55.~      2011-11-21 16:32:25.000000000 -0500
+++ mld6.c      2013-06-17 13:34:43.000000000 -0400
@@ -271,6 +271,9 @@ mld_start_listening(struct in6_multi *in
 {
        struct in6_addr all_in6;
 
+       mutex_enter(softnet_lock);
+       KERNEL_LOCK(1, NULL);
+
        /*
         * RFC2710 page 10:
         * The node never sends a Report or Done for the link-scope all-nodes
@@ -296,6 +299,9 @@ mld_start_listening(struct in6_multi *in
 
                mld_starttimer(in6m);
        }
+
+       KERNEL_UNLOCK_ONE(NULL);
+       mutex_exit(softnet_lock);
 }
 
 static void
@@ -303,15 +309,18 @@ mld_stop_listening(struct in6_multi *in6
 {
        struct in6_addr allnode, allrouter;
 
+       mutex_enter(softnet_lock);
+       KERNEL_LOCK(1, NULL);
+
        allnode = in6addr_linklocal_allnodes;
        if (in6_setscope(&allnode, in6m->in6m_ifp, NULL)) {
                /* XXX: this should not happen! */
-               return;
+               goto out;
        }
        allrouter = in6addr_linklocal_allrouters;
        if (in6_setscope(&allrouter, in6m->in6m_ifp, NULL)) {
                /* XXX impossible */
-               return;
+               goto out;
        }
 
        if (in6m->in6m_state == MLD_IREPORTEDLAST &&
@@ -320,6 +329,10 @@ mld_stop_listening(struct in6_multi *in6
            IPV6_ADDR_SCOPE_INTFACELOCAL) {
                mld_sendpkt(in6m, MLD_LISTENER_DONE, &allrouter);
        }
+
+ out:
+       KERNEL_UNLOCK_ONE(NULL);
+       mutex_exit(softnet_lock);
 }
 
 void

Attachment: pgp2_sJH9_Dqj.pgp
Description: PGP signature



Home | Main Index | Thread Index | Old Index