On Thu, Jul 14, 2022 at 01:46:14PM +0200, Alexander Bluhm wrote:
> Hi,
> 
> Protect all writers to ifm_cur with a mutex.  ifmedia_match() does
> not return any pointers without lock anymore.
> 
> ok?

I like to use fmedia_get() instead fmedia_match_get(). With this change
ok mvs@.

> 
> bluhm
> 
> Index: dev/ic/if_wi.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/ic/if_wi.c,v
> retrieving revision 1.176
> diff -u -p -r1.176 if_wi.c
> --- dev/ic/if_wi.c    9 Jan 2022 05:42:38 -0000       1.176
> +++ dev/ic/if_wi.c    13 Jul 2022 14:15:18 -0000
> @@ -2707,7 +2707,7 @@ wi_sync_media(struct wi_softc *sc, int p
>       }
>       media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
>       IFM_INST(media));
> -     if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
> +     if (!ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask))
>               return (EINVAL);
>       ifmedia_set(&sc->sc_media, media);
>       sc->wi_ptype = ptype;
> Index: net/if_media.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_media.c,v
> retrieving revision 1.35
> diff -u -p -r1.35 if_media.c
> --- net/if_media.c    12 Jul 2022 22:27:38 -0000      1.35
> +++ net/if_media.c    13 Jul 2022 14:19:29 -0000
> @@ -105,6 +105,8 @@ static    void ifmedia_printword(uint64_t);
>  
>  struct mutex ifmedia_mtx = MUTEX_INITIALIZER(IPL_NET);
>  
> +struct       ifmedia_entry *ifmedia_match_get(struct ifmedia *, uint64_t, 
> uint64_t);
> +
>  /*
>   * Initialize if_media struct for a specific interface instance.
>   */
> @@ -181,7 +183,8 @@ ifmedia_set(struct ifmedia *ifm, uint64_
>  {
>       struct ifmedia_entry *match;
>  
> -     match = ifmedia_match(ifm, target, ifm->ifm_mask);
> +     mtx_enter(&ifmedia_mtx);
> +     match = ifmedia_match_get(ifm, target, ifm->ifm_mask);
>  
>       /*
>        * If we didn't find the requested media, then we try to fall
> @@ -201,15 +204,20 @@ ifmedia_set(struct ifmedia *ifm, uint64_
>               printf("%s: no match for 0x%llx/0x%llx\n", __func__,
>                   target, ~ifm->ifm_mask);
>               target = (target & IFM_NMASK) | IFM_NONE;
> -             match = ifmedia_match(ifm, target, ifm->ifm_mask);
> +             match = ifmedia_match_get(ifm, target, ifm->ifm_mask);
>               if (match == NULL) {
> +                     mtx_leave(&ifmedia_mtx);
>                       ifmedia_add(ifm, target, 0, NULL);
> -                     match = ifmedia_match(ifm, target, ifm->ifm_mask);
> -                     if (match == NULL)
> +                     mtx_enter(&ifmedia_mtx);
> +                     match = ifmedia_match_get(ifm, target, ifm->ifm_mask);
> +                     if (match == NULL) {
> +                             mtx_leave(&ifmedia_mtx);
>                               panic("ifmedia_set failed");
> +                     }
>               }
>       }
>       ifm->ifm_cur = match;
> +     mtx_leave(&ifmedia_mtx);
>  
>  #ifdef IFMEDIA_DEBUG
>       if (ifmedia_debug) {
> @@ -245,8 +253,10 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
>               uint64_t oldmedia;
>               uint64_t newmedia = ifr->ifr_media;
>  
> -             match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
> +             mtx_enter(&ifmedia_mtx);
> +             match = ifmedia_match_get(ifm, newmedia, ifm->ifm_mask);
>               if (match == NULL) {
> +                     mtx_leave(&ifmedia_mtx);
>  #ifdef IFMEDIA_DEBUG
>                       if (ifmedia_debug) {
>                               printf("%s: no media found for 0x%llx\n",
> @@ -264,8 +274,10 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
>                */
>               if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
>                   (newmedia == ifm->ifm_media) &&
> -                 (match == ifm->ifm_cur))
> +                 (match == ifm->ifm_cur)) {
> +                     mtx_leave(&ifmedia_mtx);
>                       return (0);
> +             }
>  
>               /*
>                * We found a match, now make the driver switch to it.
> @@ -283,10 +295,16 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
>               oldmedia = ifm->ifm_media;
>               ifm->ifm_cur = match;
>               ifm->ifm_media = newmedia;
> +             mtx_leave(&ifmedia_mtx);
> +
>               error = (*ifm->ifm_change_cb)(ifp);
>               if (error && error != ENETRESET) {
> -                     ifm->ifm_cur = oldentry;
> -                     ifm->ifm_media = oldmedia;
> +                     mtx_enter(&ifmedia_mtx);
> +                     if (ifm->ifm_cur == match) {
> +                             ifm->ifm_cur = oldentry;
> +                             ifm->ifm_media = oldmedia;
> +                     }
> +                     mtx_leave(&ifmedia_mtx);
>               }
>               break;
>       }
> @@ -302,10 +320,13 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
>               if (ifmr->ifm_count < 0)
>                       return (EINVAL);
>  
> +             mtx_enter(&ifmedia_mtx);
>               ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
>                   ifm->ifm_cur->ifm_media : IFM_NONE;
>               ifmr->ifm_mask = ifm->ifm_mask;
>               ifmr->ifm_status = 0;
> +             mtx_leave(&ifmedia_mtx);
> +
>               (*ifm->ifm_status_cb)(ifp, ifmr);
>  
>               mtx_enter(&ifmedia_mtx);
> @@ -368,17 +389,30 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
>  }
>  
>  /*
> - * Find media entry matching a given ifm word.
> + * Find media entry matching a given ifm word.  Return 1 if found.
>   */
> -struct ifmedia_entry *
> +int
>  ifmedia_match(struct ifmedia *ifm, uint64_t target, uint64_t mask)
>  {
> +     struct ifmedia_entry *match;
> +
> +     mtx_enter(&ifmedia_mtx);
> +     match = ifmedia_match_get(ifm, target, mask);
> +     mtx_leave(&ifmedia_mtx);
> +
> +     return (match != NULL);
> +}
> +
> +struct ifmedia_entry *
> +ifmedia_match_get(struct ifmedia *ifm, uint64_t target, uint64_t mask)
> +{
>       struct ifmedia_entry *match, *next;
>  
> +     MUTEX_ASSERT_LOCKED(&ifmedia_mtx);
> +
>       match = NULL;
>       mask = ~mask;
>  
> -     mtx_enter(&ifmedia_mtx);
>       TAILQ_FOREACH(next, &ifm->ifm_list, ifm_list) {
>               if ((next->ifm_media & mask) == (target & mask)) {
>                       if (match) {
> @@ -392,7 +426,6 @@ ifmedia_match(struct ifmedia *ifm, uint6
>                       match = next;
>               }
>       }
> -     mtx_leave(&ifmedia_mtx);
>  
>       return (match);
>  }
> @@ -417,6 +450,7 @@ ifmedia_delete_instance(struct ifmedia *
>                       TAILQ_INSERT_TAIL(&ifmlist, ife, ifm_list);
>               }
>       }
> +     ifm->ifm_cur = NULL;
>       mtx_leave(&ifmedia_mtx);
>  
>       /* Do not hold mutex longer than necessary, call free() without. */
> Index: net/if_media.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_media.h,v
> retrieving revision 1.44
> diff -u -p -r1.44 if_media.h
> --- net/if_media.h    12 Jul 2022 22:08:18 -0000      1.44
> +++ net/if_media.h    13 Jul 2022 14:18:09 -0000
> @@ -103,7 +103,7 @@ TAILQ_HEAD(ifmedia_list, ifmedia_entry);
>  struct ifmedia {
>       uint64_t        ifm_mask;       /* mask of changes we don't care about 
> */
>       uint64_t        ifm_media;      /* current user-set media word */
> -     struct ifmedia_entry *ifm_cur;  /* currently selected media */
> +     struct ifmedia_entry *ifm_cur;  /* [M] currently selected media */
>       struct ifmedia_list ifm_list;   /* [M] list of all supported media */
>       size_t          ifm_nwords;     /* [M] number of ifm_list entries */
>       ifm_change_cb_t ifm_change_cb;  /* media change driver callback */
> @@ -129,7 +129,7 @@ int       ifmedia_ioctl(struct ifnet *, struct
>           u_long);
>  
>  /* Locate a media entry */
> -struct       ifmedia_entry *ifmedia_match(struct ifmedia *, uint64_t, 
> uint64_t);
> +int  ifmedia_match(struct ifmedia *, uint64_t, uint64_t);
>  
>  /* Delete all media for a given media instance */
>  void ifmedia_delete_instance(struct ifmedia *, uint64_t);
> 

Reply via email to