aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAndriy Voskoboinyk <avos@FreeBSD.org>2017-10-16 21:21:31 +0000
committerAndriy Voskoboinyk <avos@FreeBSD.org>2017-10-16 21:21:31 +0000
commitc64c1f95a791046f4bd15e1d69b7c0de63e4cd83 (patch)
tree40e6a74f495ae4c463f66c9a7c5f953685a22dd9 /sys
parente9445808a8409448264642dc078dc37033593be1 (diff)
downloadsrc-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')
-rw-r--r--sys/net/if_clone.c60
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)
{