Source-Changes-HG archive

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

[src/trunk]: src/sys/net Replace ifnet_lock with if_get and if_put



details:   https://anonhg.NetBSD.org/src/rev/7ea6c31c4040
branches:  trunk
changeset: 815413:7ea6c31c4040
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Mon May 16 01:16:24 2016 +0000

description:
Replace ifnet_lock with if_get and if_put

ifnet_lock is a dedicated method to safely destroy an interface over running
ioctl operations. Replace it with a more generic mechanism using psref(9).

diffstat:

 sys/net/if.c |  201 +++++++++++++++++-----------------------------------------
 sys/net/if.h |   25 +------
 2 files changed, 62 insertions(+), 164 deletions(-)

diffs (truncated from 423 to 300 lines):

diff -r b92b8d623d8c -r 7ea6c31c4040 sys/net/if.c
--- a/sys/net/if.c      Mon May 16 01:06:31 2016 +0000
+++ b/sys/net/if.c      Mon May 16 01:16:24 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.c,v 1.335 2016/05/16 01:06:31 ozaki-r Exp $ */
+/*     $NetBSD: if.c,v 1.336 2016/05/16 01:16:24 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.335 2016/05/16 01:06:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.336 2016/05/16 01:16:24 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -192,10 +192,6 @@
 static kauth_listener_t if_listener;
 
 static int doifioctl(struct socket *, u_long, void *, struct lwp *);
-static int ifioctl_attach(struct ifnet *);
-static void ifioctl_detach(struct ifnet *);
-static void ifnet_lock_enter(struct ifnet_lock *);
-static void ifnet_lock_exit(struct ifnet_lock *);
 static void if_detach_queues(struct ifnet *, struct ifqueue *);
 static void sysctl_sndq_setup(struct sysctllog **, const char *,
     struct ifaltq *);
@@ -348,10 +344,6 @@
 if_nullioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
 
-       /* Wake ifioctl_detach(), who may wait for all threads to
-        * quit the critical section.
-        */
-       cv_signal(&ifp->if_ioctl_lock->il_emptied);
        return ENXIO;
 }
 
@@ -653,6 +645,7 @@
 
        PSLIST_ENTRY_INIT(ifp, if_pslist_entry);
        psref_target_init(&ifp->if_psref, ifnet_psref_class);
+       ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
 
        IFNET_LOCK();
        if_getindex(ifp);
@@ -665,8 +658,12 @@
 void
 if_register(ifnet_t *ifp)
 {
-       if (ifioctl_attach(ifp) != 0)
-               panic("%s: ifioctl_attach() failed", __func__);
+       /*
+        * If the driver has not supplied its own if_ioctl, then
+        * supply the default.
+        */
+       if (ifp->if_ioctl == NULL)
+               ifp->if_ioctl = ifioctl_common;
 
        sysctl_sndq_setup(&ifp->if_sysctl_log, ifp->if_xname, &ifp->if_snd);
 
@@ -1047,6 +1044,9 @@
        s = splnet();
 
        sysctl_teardown(&ifp->if_sysctl_log);
+       mutex_enter(ifp->if_ioctl_lock);
+       ifp->if_ioctl = if_nullioctl;
+       mutex_exit(ifp->if_ioctl_lock);
 
        IFNET_LOCK();
        ifindex2ifnet[ifp->if_index] = NULL;
@@ -1059,6 +1059,9 @@
        psref_target_destroy(&ifp->if_psref, ifnet_psref_class);
        PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry);
 
+       mutex_obj_free(ifp->if_ioctl_lock);
+       ifp->if_ioctl_lock = NULL;
+
        if (ifp->if_slowtimo != NULL) {
                ifp->if_slowtimo = NULL;
                callout_halt(ifp->if_slowtimo_ch, NULL);
@@ -1191,8 +1194,6 @@
        /* Announce that the interface is gone. */
        rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
 
-       ifioctl_detach(ifp);
-
        IF_AFDATA_LOCK_DESTROY(ifp);
 
        softint_disestablish(ifp->if_link_si);
@@ -1300,13 +1301,18 @@
 {
        struct if_clone *ifc;
        int unit;
+       struct ifnet *ifp;
+       struct psref psref;
 
        ifc = if_clone_lookup(name, &unit);
        if (ifc == NULL)
                return EINVAL;
 
-       if (ifunit(name) != NULL)
+       ifp = if_get(name, &psref);
+       if (ifp != NULL) {
+               if_put(ifp, &psref);
                return EEXIST;
+       }
 
        return (*ifc->ifc_create)(ifc, unit);
 }
@@ -1319,17 +1325,29 @@
 {
        struct if_clone *ifc;
        struct ifnet *ifp;
+       struct psref psref;
 
        ifc = if_clone_lookup(name, NULL);
        if (ifc == NULL)
                return EINVAL;
 
-       ifp = ifunit(name);
+       if (ifc->ifc_destroy == NULL)
+               return EOPNOTSUPP;
+
+       ifp = if_get(name, &psref);
        if (ifp == NULL)
                return ENXIO;
 
-       if (ifc->ifc_destroy == NULL)
-               return EOPNOTSUPP;
+       /* We have to disable ioctls here */
+       mutex_enter(ifp->if_ioctl_lock);
+       ifp->if_ioctl = if_nullioctl;
+       mutex_exit(ifp->if_ioctl_lock);
+
+       /*
+        * We cannot call ifc_destroy with holding ifp.
+        * Releasing ifp here is safe thanks to if_clone_mtx.
+        */
+       if_put(ifp, &psref);
 
        return (*ifc->ifc_destroy)(ifp);
 }
@@ -2421,32 +2439,6 @@
        }
 }
 
-static void
-ifnet_lock_enter(struct ifnet_lock *il)
-{
-       uint64_t *nenter;
-
-       /* Before trying to acquire the mutex, increase the count of threads
-        * who have entered or who wait to enter the critical section.
-        * Avoid one costly locked memory transaction by keeping a count for
-        * each CPU.
-        */
-       nenter = percpu_getref(il->il_nenter);
-       (*nenter)++;
-       percpu_putref(il->il_nenter);
-       mutex_enter(&il->il_lock);
-}
-
-static void
-ifnet_lock_exit(struct ifnet_lock *il)
-{
-       /* Increase the count of threads who have exited the critical
-        * section.  Increase while we still hold the lock.
-        */
-       il->il_nexit++;
-       mutex_exit(&il->il_lock);
-}
-
 /*
  * Interface ioctls.
  */
@@ -2465,6 +2457,8 @@
        struct oifreq *oifr = NULL;
 #endif
        int r;
+       struct psref psref;
+       int bound = curlwp->l_pflag & LP_BOUND;
 
        switch (cmd) {
 #ifdef COMPAT_OIFREQ
@@ -2493,24 +2487,29 @@
 #endif
                ifr = data;
 
-       ifp = ifunit(ifr->ifr_name);
-
        switch (cmd) {
        case SIOCIFCREATE:
        case SIOCIFDESTROY:
+               curlwp->l_pflag |= LP_BOUND;
                if (l != NULL) {
+                       ifp = if_get(ifr->ifr_name, &psref);
                        error = kauth_authorize_network(l->l_cred,
                            KAUTH_NETWORK_INTERFACE,
                            KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
                            (void *)cmd, NULL);
-                       if (error != 0)
+                       if (ifp != NULL)
+                               if_put(ifp, &psref);
+                       if (error != 0) {
+                               curlwp->l_pflag ^= bound ^ LP_BOUND;
                                return error;
+                       }
                }
                mutex_enter(&if_clone_mtx);
                r = (cmd == SIOCIFCREATE) ?
                        if_clone_create(ifr->ifr_name) :
                        if_clone_destroy(ifr->ifr_name);
                mutex_exit(&if_clone_mtx);
+               curlwp->l_pflag ^= bound ^ LP_BOUND;
                return r;
 
        case SIOCIFGCLONERS:
@@ -2521,8 +2520,12 @@
                }
        }
 
-       if (ifp == NULL)
+       curlwp->l_pflag |= LP_BOUND;
+       ifp = if_get(ifr->ifr_name, &psref);
+       if (ifp == NULL) {
+               curlwp->l_pflag ^= bound ^ LP_BOUND;
                return ENXIO;
+       }
 
        switch (cmd) {
        case SIOCALIFADDR:
@@ -2557,13 +2560,14 @@
                            KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
                            (void *)cmd, NULL);
                        if (error != 0)
-                               return error;
+                               goto out;
                }
        }
 
        oif_flags = ifp->if_flags;
 
-       ifnet_lock_enter(ifp->if_ioctl_lock);
+       mutex_enter(ifp->if_ioctl_lock);
+
        error = (*ifp->if_ioctl)(ifp, cmd, data);
        if (error != ENOTTY)
                ;
@@ -2590,100 +2594,13 @@
                ifreqn2o(oifr, ifr);
 #endif
 
-       ifnet_lock_exit(ifp->if_ioctl_lock);
+       mutex_exit(ifp->if_ioctl_lock);
+out:
+       if_put(ifp, &psref);
+       curlwp->l_pflag ^= bound ^ LP_BOUND;
        return error;
 }
 
-/* This callback adds to the sum in `arg' the number of
- * threads on `ci' who have entered or who wait to enter the
- * critical section.
- */
-static void
-ifnet_lock_sum(void *p, void *arg, struct cpu_info *ci)
-{
-       uint64_t *sum = arg, *nenter = p;
-
-       *sum += *nenter;
-}
-
-/* Return the number of threads who have entered or who wait
- * to enter the critical section on all CPUs.
- */
-static uint64_t
-ifnet_lock_entrances(struct ifnet_lock *il)
-{
-       uint64_t sum = 0;
-
-       percpu_foreach(il->il_nenter, ifnet_lock_sum, &sum);
-
-       return sum;
-}
-
-static int
-ifioctl_attach(struct ifnet *ifp)
-{
-       struct ifnet_lock *il;
-
-       /* If the driver has not supplied its own if_ioctl, then
-        * supply the default.
-        */
-       if (ifp->if_ioctl == NULL)
-               ifp->if_ioctl = ifioctl_common;
-
-       /* Create an ifnet_lock for synchronizing ifioctls. */



Home | Main Index | Thread Index | Old Index