mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/libxenevtchn: add possibility to not close file descriptor on exec
Today the file descriptor for the access of the event channel driver is being closed in case of exec(2). For the support of live update of a daemon using libxenevtchn this can be problematic, so add a way to keep that file descriptor open. Add support of a flag XENEVTCHN_NO_CLOEXEC for xenevtchn_open() which will result in _not_ setting O_CLOEXEC when opening the event channel driver node. The caller can then obtain the file descriptor via xenevtchn_fd(). Add an alternative open function xenevtchn_fdopen() which takes that file descriptor as an additional parameter. This allows to allocate a xenevtchn_handle and to associate it with that file descriptor. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Wei Liu <wl@xen.org> Reviewed-by: Julien Grall <jgrall@amazon.com>
This commit is contained in:
1 parent
935e5fb0d5
commit
29a6082f21
7 files changed
+97
-37
No files matched your search
+31
-19
@@ -42,35 +42,47 @@ struct xentoollog_logger;
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return a handle to the event channel driver, or NULL on failure, in
|
||||
* which case errno will be set appropriately.
|
||||
* Opens the evtchn device node. Return a handle to the event channel
|
||||
* driver, or NULL on failure, in which case errno will be set
|
||||
* appropriately.
|
||||
*
|
||||
* Note: After fork(2) a child process must not use any opened evtchn
|
||||
* handle inherited from their parent, nor access any grant mapped
|
||||
* areas associated with that handle.
|
||||
* On fork(2):
|
||||
*
|
||||
* The child must open a new handle if they want to interact with
|
||||
* evtchn.
|
||||
* After fork, a child process must not use any opened evtchn handle
|
||||
* inherited from their parent. This includes operations such as
|
||||
* poll() on the underlying file descriptor. Calling xenevtchn_close()
|
||||
* is the only safe operation on a xenevtchn_handle which has been
|
||||
* inherited.
|
||||
*
|
||||
* Calling exec(2) in a child will safely (and reliably) reclaim any
|
||||
* allocated resources via a xenevtchn_handle in the parent.
|
||||
* The child must open a new handle if they want to interact with
|
||||
* evtchn.
|
||||
*
|
||||
* A child which does not call exec(2) may safely call
|
||||
* xenevtchn_close() on a xenevtchn_handle inherited from their
|
||||
* parent. This will attempt to reclaim any resources associated with
|
||||
* that handle. Note that in some implementations this reclamation may
|
||||
* not be completely effective, in this case any affected resources
|
||||
* remain allocated.
|
||||
* On exec(2):
|
||||
*
|
||||
* Calling xenevtchn_close() is the only safe operation on a
|
||||
* xenevtchn_handle which has been inherited.
|
||||
* Wherever possible, the device node will be opened with O_CLOEXEC,
|
||||
* so it is not inherited by the subsequent program.
|
||||
*
|
||||
* However the XENEVTCHN_NO_CLOEXEC flag may be used to avoid opening
|
||||
* the device node with O_CLOEXEC. This is intended for use by
|
||||
* daemons which support a self-reexec method of updating themselves.
|
||||
*
|
||||
* In this case, the updated daemon should pass the underlying file
|
||||
* descriptor it inherited to xenevtchn_fdopen() to reconstruct the
|
||||
* library handle.
|
||||
*/
|
||||
/* Currently no flags are defined */
|
||||
|
||||
/* Don't set O_CLOEXEC when opening event channel driver node. */
|
||||
#define XENEVTCHN_NO_CLOEXEC (1 << 0)
|
||||
|
||||
xenevtchn_handle *xenevtchn_open(struct xentoollog_logger *logger,
|
||||
unsigned int flags);
|
||||
|
||||
/* Flag XENEVTCHN_NO_CLOEXEC is rejected by xenevtchn_fdopen(). */
|
||||
xenevtchn_handle *xenevtchn_fdopen(struct xentoollog_logger *logger,
|
||||
int fd, unsigned open_flags);
|
||||
|
||||
/*
|
||||
* Close a handle previously allocated with xenevtchn_open().
|
||||
* Close a handle previously allocated with xenevtchn_{,fd}open().
|
||||
*/
|
||||
int xenevtchn_close(xenevtchn_handle *xce);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ XEN_ROOT = $(CURDIR)/../../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
MAJOR = 1
|
||||
MINOR = 1
|
||||
MINOR = 2
|
||||
|
||||
SRCS-y += core.c
|
||||
SRCS-$(CONFIG_Linux) += linux.c
|
||||
|
||||
+45
-15
@@ -30,18 +30,10 @@ static int all_restrict_cb(Xentoolcore__Active_Handle *ah, domid_t domid)
|
||||
return xenevtchn_restrict(xce, domid);
|
||||
}
|
||||
|
||||
xenevtchn_handle *xenevtchn_open(xentoollog_logger *logger, unsigned int flags)
|
||||
static xenevtchn_handle *xenevtchn_alloc_handle(xentoollog_logger *logger)
|
||||
{
|
||||
xenevtchn_handle *xce;
|
||||
int rc;
|
||||
xenevtchn_handle *xce = malloc(sizeof(*xce));
|
||||
|
||||
if ( flags )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xce = malloc(sizeof(*xce));
|
||||
if ( !xce )
|
||||
return NULL;
|
||||
|
||||
@@ -60,6 +52,28 @@ xenevtchn_handle *xenevtchn_open(xentoollog_logger *logger, unsigned int flags)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return xce;
|
||||
|
||||
err:
|
||||
xenevtchn_close(xce);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xenevtchn_handle *xenevtchn_open(xentoollog_logger *logger, unsigned int flags)
|
||||
{
|
||||
xenevtchn_handle *xce;
|
||||
int rc;
|
||||
|
||||
if ( flags & ~XENEVTCHN_NO_CLOEXEC )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xce = xenevtchn_alloc_handle(logger);
|
||||
if ( !xce )
|
||||
return NULL;
|
||||
|
||||
rc = osdep_evtchn_open(xce, flags);
|
||||
if ( rc < 0 )
|
||||
goto err;
|
||||
@@ -67,14 +81,30 @@ xenevtchn_handle *xenevtchn_open(xentoollog_logger *logger, unsigned int flags)
|
||||
return xce;
|
||||
|
||||
err:
|
||||
xentoolcore__deregister_active_handle(&xce->tc_ah);
|
||||
osdep_evtchn_close(xce);
|
||||
xtl_logger_destroy(xce->logger_tofree);
|
||||
free(xce);
|
||||
|
||||
xenevtchn_close(xce);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xenevtchn_handle *xenevtchn_fdopen(struct xentoollog_logger *logger,
|
||||
int fd, unsigned int flags)
|
||||
{
|
||||
xenevtchn_handle *xce;
|
||||
|
||||
if ( flags )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xce = xenevtchn_alloc_handle(logger);
|
||||
if ( !xce )
|
||||
return NULL;
|
||||
|
||||
xce->fd = fd;
|
||||
|
||||
return xce;
|
||||
}
|
||||
|
||||
int xenevtchn_close(xenevtchn_handle *xce)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -33,8 +33,13 @@
|
||||
|
||||
int osdep_evtchn_open(xenevtchn_handle *xce, unsigned int flags)
|
||||
{
|
||||
int fd = open(EVTCHN_DEV, O_RDWR|O_CLOEXEC);
|
||||
int open_flags = O_RDWR;
|
||||
int fd;
|
||||
|
||||
if ( !(flags & XENEVTCHN_NO_CLOEXEC) )
|
||||
open_flags |= O_CLOEXEC;
|
||||
|
||||
fd = open(EVTCHN_DEV, open_flags);
|
||||
if ( fd == -1 )
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -21,3 +21,7 @@ VERS_1.1 {
|
||||
global:
|
||||
xenevtchn_restrict;
|
||||
} VERS_1.0;
|
||||
VERS_1.2 {
|
||||
global:
|
||||
xenevtchn_fdopen;
|
||||
} VERS_1.1;
|
||||
@@ -36,8 +36,13 @@
|
||||
|
||||
int osdep_evtchn_open(xenevtchn_handle *xce, unsigned int flags)
|
||||
{
|
||||
int fd = open("/dev/xen/evtchn", O_RDWR|O_CLOEXEC);
|
||||
int open_flags = O_RDWR;
|
||||
int fd;
|
||||
|
||||
if ( !(flags & XENEVTCHN_NO_CLOEXEC) )
|
||||
open_flags |= O_CLOEXEC;
|
||||
|
||||
fd = open("/dev/xen/evtchn", open_flags);
|
||||
if ( fd == -1 )
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ static void port_dealloc(struct evtchn_port_info *port_info)
|
||||
free(port_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* XENEVTCHN_NO_CLOEXEC is being ignored, as there is no exec() call supported
|
||||
* in Mini-OS.
|
||||
*/
|
||||
int osdep_evtchn_open(xenevtchn_handle *xce, unsigned int flags)
|
||||
{
|
||||
int fd = alloc_fd(FTYPE_EVTCHN);
|
||||
|
||||