struct ip_sf_socklist *psl;
        struct net *net = sock_net(sk);
 
+       ASSERT_RTNL();
+
        if (!ipv4_is_multicast(addr))
                return -EINVAL;
 
-       rtnl_lock();
-
        imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
        imr.imr_address.s_addr = msf->imsf_interface;
        imr.imr_ifindex = 0;
                goto done;
        msf->imsf_fmode = pmc->sfmode;
        psl = rtnl_dereference(pmc->sflist);
-       rtnl_unlock();
        if (!psl) {
                len = 0;
                count = 0;
                return -EFAULT;
        return 0;
 done:
-       rtnl_unlock();
        return err;
 }
 
        struct inet_sock *inet = inet_sk(sk);
        struct ip_sf_socklist *psl;
 
+       ASSERT_RTNL();
+
        psin = (struct sockaddr_in *)&gsf->gf_group;
        if (psin->sin_family != AF_INET)
                return -EINVAL;
        if (!ipv4_is_multicast(addr))
                return -EINVAL;
 
-       rtnl_lock();
-
        err = -EADDRNOTAVAIL;
 
        for_each_pmc_rtnl(inet, pmc) {
                goto done;
        gsf->gf_fmode = pmc->sfmode;
        psl = rtnl_dereference(pmc->sflist);
-       rtnl_unlock();
        count = psl ? psl->sl_count : 0;
        copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
        gsf->gf_numsrc = count;
        }
        return 0;
 done:
-       rtnl_unlock();
        return err;
 }
 
 
  *     the _received_ ones. The set sets the _sent_ ones.
  */
 
+static bool getsockopt_needs_rtnl(int optname)
+{
+       switch (optname) {
+       case IP_MSFILTER:
+       case MCAST_MSFILTER:
+               return true;
+       }
+       return false;
+}
+
 static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                            char __user *optval, int __user *optlen, unsigned int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
-       int val;
+       bool needs_rtnl = getsockopt_needs_rtnl(optname);
+       int val, err = 0;
        int len;
 
        if (level != SOL_IP)
        if (len < 0)
                return -EINVAL;
 
+       if (needs_rtnl)
+               rtnl_lock();
        lock_sock(sk);
 
        switch (optname) {
        case IP_MSFILTER:
        {
                struct ip_msfilter msf;
-               int err;
 
                if (len < IP_MSFILTER_SIZE(0)) {
-                       release_sock(sk);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out;
                }
                if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
-                       release_sock(sk);
-                       return -EFAULT;
+                       err = -EFAULT;
+                       goto out;
                }
                err = ip_mc_msfget(sk, &msf,
                                   (struct ip_msfilter __user *)optval, optlen);
-               release_sock(sk);
-               return err;
+               goto out;
        }
        case MCAST_MSFILTER:
        {
                struct group_filter gsf;
-               int err;
 
                if (len < GROUP_FILTER_SIZE(0)) {
-                       release_sock(sk);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out;
                }
                if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
-                       release_sock(sk);
-                       return -EFAULT;
+                       err = -EFAULT;
+                       goto out;
                }
                err = ip_mc_gsfget(sk, &gsf,
                                   (struct group_filter __user *)optval,
                                   optlen);
-               release_sock(sk);
-               return err;
+               goto out;
        }
        case IP_MULTICAST_ALL:
                val = inet->mc_all;
                        return -EFAULT;
        }
        return 0;
+
+out:
+       release_sock(sk);
+       if (needs_rtnl)
+               rtnl_unlock();
+       return err;
 }
 
 int ip_getsockopt(struct sock *sk, int level,