Page MenuHomeFreeBSD

D28136.diff
No OneTemporary

D28136.diff

diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -126,6 +126,7 @@
#include <sys/kernel.h>
#include <sys/khelp.h>
#include <sys/ktls.h>
+#include <sys/epoch.h>
#include <sys/event.h>
#include <sys/eventhandler.h>
#include <sys/poll.h>
@@ -2983,8 +2984,8 @@
return (sosetopt(so, &sopt));
}
-int
-sosetopt(struct socket *so, struct sockopt *sopt)
+static inline int
+sosetopt_locked(struct socket *so, struct sockopt *sopt)
{
int error, optval;
struct linger l;
@@ -2995,7 +2996,6 @@
struct mac extmac;
#endif
- CURVNET_SET(so->so_vnet);
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
if (so->so_proto->pr_ctloutput != NULL)
@@ -3182,10 +3182,24 @@
(void)(*so->so_proto->pr_ctloutput)(so, sopt);
}
bad:
- CURVNET_RESTORE();
return (error);
}
+int
+sosetopt(struct socket *so, struct sockopt *sopt)
+{
+ struct epoch_tracker et;
+ int retval;
+
+ epoch_enter_sleepable(net_epoch_sleepable, &et);
+ CURVNET_SET(so->so_vnet);
+ retval = sosetopt_locked(so, sopt);
+ CURVNET_RESTORE();
+ epoch_exit_sleepable(net_epoch_sleepable, &et);
+
+ return (retval);
+}
+
/*
* Helper routine for getsockopt.
*/
@@ -3216,8 +3230,8 @@
return (error);
}
-int
-sogetopt(struct socket *so, struct sockopt *sopt)
+static inline int
+sogetopt_locked(struct socket *so, struct sockopt *sopt)
{
int error, optval;
struct linger l;
@@ -3226,14 +3240,12 @@
struct mac extmac;
#endif
- CURVNET_SET(so->so_vnet);
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
if (so->so_proto->pr_ctloutput != NULL)
error = (*so->so_proto->pr_ctloutput)(so, sopt);
else
error = ENOPROTOOPT;
- CURVNET_RESTORE();
return (error);
} else {
switch (sopt->sopt_name) {
@@ -3388,10 +3400,24 @@
#ifdef MAC
bad:
#endif
- CURVNET_RESTORE();
return (error);
}
+int
+sogetopt(struct socket *so, struct sockopt *sopt)
+{
+ struct epoch_tracker et;
+ int retval;
+
+ epoch_enter_sleepable(net_epoch_sleepable, &et);
+ CURVNET_SET(so->so_vnet);
+ retval = sogetopt_locked(so, sopt);
+ CURVNET_RESTORE();
+ epoch_exit_sleepable(net_epoch_sleepable, &et);
+
+ return (retval);
+}
+
int
soopt_getm(struct sockopt *sopt, struct mbuf **mp)
{
diff --git a/sys/net/if.c b/sys/net/if.c
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -110,6 +110,8 @@
offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru");
__read_mostly epoch_t net_epoch_preempt;
+__read_mostly epoch_t net_epoch_sleepable;
+
#ifdef COMPAT_FREEBSD32
#include <sys/mount.h>
#include <compat/freebsd32/freebsd32.h>
@@ -283,6 +285,7 @@
static int if_detach_internal(struct ifnet *, int, struct if_clone **);
static void if_siocaddmulti(void *, int);
static void if_link_ifnet(struct ifnet *);
+static void if_wait_sleepable(void);
static bool if_unlink_ifnet(struct ifnet *, bool);
#ifdef VIMAGE
static int if_vmove(struct ifnet *, struct vnet *);
@@ -494,6 +497,13 @@
IFNET_WUNLOCK();
}
+static void
+if_wait_sleepable(void)
+{
+ /* Wait for pending user-space calls to complete. */
+ epoch_wait_sleepable(net_epoch_sleepable);
+}
+
static bool
if_unlink_ifnet(struct ifnet *ifp, bool vmove)
{
@@ -554,6 +564,8 @@
}
IFNET_WUNLOCK();
+ if_wait_sleepable();
+
for (int j = 0; j < i; j++) {
if_vmove(pending[j], pending[j]->if_home_vnet);
}
@@ -1015,6 +1027,7 @@
{
net_epoch_preempt = epoch_alloc("Net preemptible", EPOCH_PREEMPT);
+ net_epoch_sleepable = epoch_alloc("Net sleepable", EPOCH_SLEEPABLE);
}
SYSINIT(ifepochalloc, SI_SUB_EPOCH, SI_ORDER_ANY, if_epochalloc, NULL);
@@ -1140,6 +1153,8 @@
CURVNET_SET_QUIET(ifp->if_vnet);
found = if_unlink_ifnet(ifp, false);
if (found) {
+ if_wait_sleepable();
+
sx_xlock(&ifnet_detach_sxlock);
if_detach_internal(ifp, 0, NULL);
sx_xunlock(&ifnet_detach_sxlock);
@@ -1437,6 +1452,8 @@
found = if_unlink_ifnet(ifp, true);
MPASS(found);
+ if_wait_sleepable();
+
/* Move the interface into the child jail/vnet. */
error = if_vmove(ifp, pr->pr_vnet);
@@ -1494,6 +1511,9 @@
/* Get interface back from child jail/vnet. */
found = if_unlink_ifnet(ifp, true);
MPASS(found);
+
+ if_wait_sleepable();
+
error = if_vmove(ifp, vnet_dst);
CURVNET_RESTORE();
@@ -2891,8 +2911,8 @@
/*
* Interface ioctls.
*/
-int
-ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
+static inline int
+ifioctl_locked(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
{
#ifdef COMPAT_FREEBSD32
union {
@@ -3116,6 +3136,30 @@
return (error);
}
+int
+ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
+{
+ struct epoch_tracker et;
+ int retval;
+
+ switch (cmd) {
+#ifdef VIMAGE
+ case SIOCSIFRVNET:
+#endif
+ case SIOCIFCREATE:
+ case SIOCIFCREATE2:
+ case SIOCIFDESTROY:
+ retval = ifioctl_locked(so, cmd, data, td);
+ break;
+ default:
+ epoch_enter_sleepable(net_epoch_sleepable, &et);
+ retval = ifioctl_locked(so, cmd, data, td);
+ epoch_exit_sleepable(net_epoch_sleepable, &et);
+ break;
+ }
+ return (retval);
+}
+
/*
* The code common to handling reference counted flags,
* e.g., in ifpromisc() and if_allmulti().
diff --git a/sys/sys/epoch.h b/sys/sys/epoch.h
--- a/sys/sys/epoch.h
+++ b/sys/sys/epoch.h
@@ -115,8 +115,10 @@
/*
* Globally recognized epochs in the FreeBSD kernel.
*/
-/* Network preemptible epoch, declared in sys/net/if.c. */
+
+/* Network epochs, declared in sys/net/if.c. */
extern epoch_t net_epoch_preempt;
+extern epoch_t net_epoch_sleepable;
#define NET_EPOCH_ENTER(et) epoch_enter_preempt(net_epoch_preempt, &(et))
#define NET_EPOCH_EXIT(et) epoch_exit_preempt(net_epoch_preempt, &(et))
#define NET_EPOCH_WAIT() epoch_wait_preempt(net_epoch_preempt)

File Metadata

Mime Type
text/plain
Expires
Fri, May 2, 6:40 PM (13 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17910170
Default Alt Text
D28136.diff (5 KB)

Event Timeline