diff options
author | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-10-16 21:21:31 +0000 |
---|---|---|
committer | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-10-16 21:21:31 +0000 |
commit | c64c1f95a791046f4bd15e1d69b7c0de63e4cd83 (patch) | |
tree | 40e6a74f495ae4c463f66c9a7c5f953685a22dd9 /sys/net | |
parent | e9445808a8409448264642dc078dc37033593be1 (diff) | |
download | src-c64c1f95a791046f4bd15e1d69b7c0de63e4cd83.tar.gz src-c64c1f95a791046f4bd15e1d69b7c0de63e4cd83.zip |
ifnet(9): split ifc_alloc_unit() (should simplify code flow)
Allocate smallest unit number from pool via ifc_alloc_unit_next()
and exact unit number (if available) via ifc_alloc_unit_specific().
While here, address possible deadlock (mentioned in PR).
PR: 217401
MFC after: 5 days
Differential Revision: https://reviews.freebsd.org/D12551
Notes
Notes:
svn path=/head/; revision=324672
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_clone.c | 60 |
1 files changed, 36 insertions, 24 deletions
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c index 3b5884e841d5..cba0d9ad7d69 100644 --- a/sys/net/if_clone.c +++ b/sys/net/if_clone.c @@ -595,39 +595,21 @@ ifc_name2unit(const char *name, int *unit) return (0); } -int -ifc_alloc_unit(struct if_clone *ifc, int *unit) +static int +ifc_alloc_unit_specific(struct if_clone *ifc, int *unit) { char name[IFNAMSIZ]; - int wildcard; - wildcard = (*unit < 0); -retry: if (*unit > ifc->ifc_maxunit) return (ENOSPC); - if (*unit < 0) { - *unit = alloc_unr(ifc->ifc_unrhdr); - if (*unit == -1) - return (ENOSPC); - } else { - *unit = alloc_unr_specific(ifc->ifc_unrhdr, *unit); - if (*unit == -1) { - if (wildcard) { - (*unit)++; - goto retry; - } else - return (EEXIST); - } - } + + if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1) + return (EEXIST); snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); if (ifunit(name) != NULL) { free_unr(ifc->ifc_unrhdr, *unit); - if (wildcard) { - (*unit)++; - goto retry; - } else - return (EEXIST); + return (EEXIST); } IF_CLONE_ADDREF(ifc); @@ -635,6 +617,36 @@ retry: return (0); } +static int +ifc_alloc_unit_next(struct if_clone *ifc, int *unit) +{ + int error; + + *unit = alloc_unr(ifc->ifc_unrhdr); + if (*unit == -1) + return (ENOSPC); + + free_unr(ifc->ifc_unrhdr, *unit); + for (;;) { + error = ifc_alloc_unit_specific(ifc, unit); + if (error != EEXIST) + break; + + (*unit)++; + } + + return (error); +} + +int +ifc_alloc_unit(struct if_clone *ifc, int *unit) +{ + if (*unit < 0) + return (ifc_alloc_unit_next(ifc, unit)); + else + return (ifc_alloc_unit_specific(ifc, unit)); +} + void ifc_free_unit(struct if_clone *ifc, int unit) { |