Files
xen/tools/libs/light/libxl.c
T
Julian Vetter baaa185201 xen/arm: report clock_frequency via sysctl physinfo, not createdomain
The xen_arch_domainconfig.clock_frequency value is populated in
domain_vtimer_init() during XEN_DOMCTL_createdomain from the global
timer_dt_clock_frequency, which comes from the host's DT timer node and
has nothing to do with the domain being created. Like now removed
GIC_NATIVE resolution, this is a host-wide system property being
smuggled out through a domain-creation IN struct.

Expose it instead as a new arm_clock_frequency_hz field in
XEN_SYSCTL_physinfo, populated via arch_do_physinfo(), and mirroring how
the GIC capability bits were already moved there.

Rather than making the field dependant on DT boot, make Xen always
report the timer frequency, either via the DT "clock-frequency" node, or
directly via CNTFRQ_EL0. preinit_xen_time() already computes cpu_khz for
every boot path. The renamed timer_clock_frequency_hz now captures
whichever of the two produced that value, in full Hz precision, instead
of only recording the DT case. So, ACPI guests get a real value too,
allowing to drop the special case.

The DT "clock-frequency" property exists because firmware might leave
CNTFRQ_EL0 wrong, and since CNTFRQ_EL0 cannot be trapped the only fix is
to replicate the correct value into the guest DT. To keep that signal, a
new XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ capability bit records whether
arm_clock_frequency_hz came from the DT property. Then libxl only emits
a "clock-frequency" property into the guest timer node when that bit is
set. A guest whose CNTFRQ_EL0 is already correct keeps an unmodified
timer node, exactly as before.

Although the CNTFRQ_EL0 register is 64 bits wide, and some current timer
implementations run at 1GHz, a 32bit value is sufficient to store the
timer value, because it only mirrors the DT 'clock-frequency' property,
which the bindings define as a single 32-bit cell.

In struct xen_sysctl_physinfo the new field just reuses the former pad
word, so sysctl consumers are unaffected. struct xen_arch_domainconfig
however loses clock_frequency from its middle, which shrinks the struct
and shifts every field after it, so bump XEN_DOMCTL_INTERFACE_VERSION.

The xen_arch_domainconfig parameter passed to domain_vtimer_init() is no
longer needed, so drop that parameter entirely. libxl now fetches the
frequency via libxl_get_physinfo() in libxl__arch_domain_save_config()
instead of reading it back out of the createdomain reply. The OCaml
xen_arch_domainconfig mirror drops the field too.

Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
2026-10-14 16:32:32 +02:00

788 lines
20 KiB
C

/*
* Copyright 2009-2017 Citrix Ltd and other contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
#include "libxl_osdeps.h"
#include "libxl_internal.h"
int libxl_ctx_alloc(libxl_ctx **pctx, int version,
unsigned flags, xentoollog_logger * lg)
{
libxl_ctx *ctx = NULL;
libxl__gc gc_buf, *gc = NULL;
int rc;
if (version != LIBXL_VERSION) { rc = ERROR_VERSION; goto out; }
ctx = malloc(sizeof(*ctx));
if (!ctx) {
xtl_log(lg, XTL_ERROR, errno, "libxl",
"%s:%d:%s: Failed to allocate context\n",
__FILE__, __LINE__, __func__);
rc = ERROR_NOMEM; goto out;
}
memset(ctx, 0, sizeof(libxl_ctx));
ctx->lg = lg;
/* First initialise pointers etc. (cannot fail) */
ctx->nogc_gc.alloc_maxsize = -1;
ctx->nogc_gc.owner = ctx;
XEN_TAILQ_INIT(&ctx->occurred);
ctx->osevent_hooks = 0;
ctx->poller_app = 0;
XEN_LIST_INIT(&ctx->pollers_event);
XEN_LIST_INIT(&ctx->pollers_idle);
XEN_LIST_INIT(&ctx->pollers_active);
XEN_LIST_INIT(&ctx->efds);
XEN_TAILQ_INIT(&ctx->etimes);
ctx->watch_slots = 0;
XEN_SLIST_INIT(&ctx->watch_freeslots);
libxl__ev_fd_init(&ctx->watch_efd);
ctx->xce = 0;
XEN_LIST_INIT(&ctx->evtchns_waiting);
libxl__ev_fd_init(&ctx->evtchn_efd);
XEN_LIST_INIT(&ctx->aos_inprogress);
XEN_TAILQ_INIT(&ctx->death_list);
libxl__ev_xswatch_init(&ctx->death_watch);
ctx->childproc_hooks = &libxl__childproc_default_hooks;
ctx->childproc_user = 0;
ctx->sigchld_selfpipe[0] = -1;
ctx->sigchld_selfpipe[1] = -1;
libxl__ev_fd_init(&ctx->sigchld_selfpipe_efd);
/* The mutex is special because we can't idempotently destroy it */
if (libxl__init_recursive_mutex(ctx, &ctx->lock) < 0) {
LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to initialize mutex");
free(ctx);
ctx = 0;
rc = ERROR_FAIL;
goto out;
}
/* Now ctx is safe for ctx_free; failures simply set rc and "goto out" */
LIBXL_INIT_GC(gc_buf,ctx);
gc = &gc_buf;
/* Now gc is useable */
rc = libxl__atfork_init(ctx);
if (rc) goto out;
ctx->poller_app = libxl__poller_get(gc);
if (!ctx->poller_app) {
rc = ERROR_FAIL;
goto out;
}
ctx->xch = xc_interface_open(lg,lg,0);
if (!ctx->xch) {
LOGEV(ERROR, errno, "cannot open libxc handle");
rc = ERROR_FAIL; goto out;
}
ctx->xsh = xs_open(0);
if (!ctx->xsh) {
LOGEV(ERROR, errno, "cannot connect to xenstore");
rc = ERROR_FAIL; goto out;
}
*pctx = ctx;
return 0;
out:
if (gc) libxl__free_all(gc);
libxl_ctx_free(ctx);
*pctx = NULL;
return rc;
}
static void free_disable_deaths(libxl__gc *gc,
struct libxl__evgen_domain_death_list *l) {
libxl_evgen_domain_death *death;
while ((death = XEN_TAILQ_FIRST(l)))
libxl__evdisable_domain_death(gc, death);
}
static void discard_events(struct libxl__event_list *l) {
/* doesn't bother unlinking from the list, so l is corrupt on return */
libxl_event *ev, *next;
XEN_TAILQ_FOREACH_SAFE(ev, l, link, next)
libxl_event_free(0, ev);
}
int libxl_ctx_free(libxl_ctx *ctx)
{
if (!ctx) return 0;
int i;
GC_INIT(ctx);
CTX_LOCK;
assert(!ctx->osevent_in_hook);
CTX->osevent_in_hook += 1000; /* make violations easier to debug */
/* Deregister all libxl__ev_KINDs: */
free_disable_deaths(gc, &CTX->death_list);
free_disable_deaths(gc, &CTX->death_reported);
libxl_evgen_disk_eject *eject;
while ((eject = XEN_LIST_FIRST(&CTX->disk_eject_evgens)))
libxl__evdisable_disk_eject(gc, eject);
libxl_childproc_setmode(CTX,0,0);
for (i = 0; i < ctx->watch_nslots; i++)
assert(!libxl__watch_slot_contents(gc, i));
assert(!libxl__ev_fd_isregistered(&ctx->watch_efd));
assert(!libxl__ev_fd_isregistered(&ctx->evtchn_efd));
assert(!libxl__ev_fd_isregistered(&ctx->sigchld_selfpipe_efd));
/* Now there should be no more events requested from the application: */
assert(XEN_LIST_EMPTY(&ctx->efds));
assert(XEN_TAILQ_EMPTY(&ctx->etimes));
assert(XEN_LIST_EMPTY(&ctx->evtchns_waiting));
assert(XEN_LIST_EMPTY(&ctx->aos_inprogress));
if (ctx->xch) xc_interface_close(ctx->xch);
libxl_version_info_dispose(&ctx->version_info);
if (ctx->xsh) xs_close(ctx->xsh);
if (ctx->xce) xenevtchn_close(ctx->xce);
libxl__poller_put(ctx, ctx->poller_app);
ctx->poller_app = NULL;
assert(XEN_LIST_EMPTY(&ctx->pollers_event));
assert(XEN_LIST_EMPTY(&ctx->pollers_active));
libxl__poller *poller, *poller_tmp;
XEN_LIST_FOREACH_SAFE(poller, &ctx->pollers_idle, entry, poller_tmp) {
libxl__poller_dispose(poller);
free(poller);
}
free(ctx->watch_slots);
discard_events(&ctx->occurred);
/* If we have outstanding children, then the application inherits
* them; we wish the application good luck with understanding
* this if and when it reaps them. */
libxl__sigchld_notneeded(gc);
libxl__pipe_close(ctx->sigchld_selfpipe);
CTX_UNLOCK;
pthread_mutex_destroy(&ctx->lock);
GC_FREE;
free(ctx);
return 0;
}
void libxl_string_list_dispose(libxl_string_list *psl)
{
int i;
libxl_string_list sl = *psl;
if (!sl)
return;
for (i = 0; sl[i] != NULL; i++) {
free(sl[i]);
sl[i] = NULL;
}
free(sl);
*psl = NULL;
}
void libxl_string_list_copy(libxl_ctx *ctx,
libxl_string_list *dst,
const libxl_string_list *src)
{
GC_INIT(ctx);
int i, len;
if (!*src) {
*dst = NULL;
goto out;
}
len = libxl_string_list_length(src);
/* one extra slot for sentinel */
*dst = libxl__calloc(NOGC, len + 1, sizeof(char *));
for (i = 0; i < len; i++)
(*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
out:
GC_FREE;
}
int libxl_string_list_length(const libxl_string_list *psl)
{
int i = 0;
if (*psl)
while ((*psl)[i])
i++;
return i;
}
int libxl_key_value_list_length(const libxl_key_value_list *pkvl)
{
int i = 0;
libxl_key_value_list kvl = *pkvl;
if (kvl) {
while (kvl[2 * i]) /* Only checks keys */
i++;
}
return i;
}
void libxl_key_value_list_dispose(libxl_key_value_list *pkvl)
{
int i;
libxl_key_value_list kvl = *pkvl;
if (!kvl)
return;
for (i = 0; kvl[i] != NULL; i += 2) {
free(kvl[i]);
kvl[i] = NULL;
if (kvl[i + 1]) {
free(kvl[i + 1]);
kvl[i+1] = NULL;
}
}
free(kvl);
*pkvl = NULL;
}
void libxl_key_value_list_copy(libxl_ctx *ctx,
libxl_key_value_list *dst,
const libxl_key_value_list *src)
{
GC_INIT(ctx);
int i, len;
if (*src == NULL) {
*dst = NULL;
goto out;
}
len = libxl_key_value_list_length(src);
/* one extra slot for sentinel */
*dst = libxl__calloc(NOGC, len * 2 + 1, sizeof(char *));
for (i = 0; i < len * 2; i += 2) {
(*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
if ((*src)[i+1])
(*dst)[i+1] = libxl__strdup(NOGC, (*src)[i+1]);
else
(*dst)[i+1] = NULL;
}
out:
GC_FREE;
}
void libxl_defbool_set(libxl_defbool *db, bool b)
{
db->val = b ? LIBXL__DEFBOOL_TRUE : LIBXL__DEFBOOL_FALSE;
}
void libxl_defbool_unset(libxl_defbool *db)
{
db->val = LIBXL__DEFBOOL_DEFAULT;
}
bool libxl_defbool_is_default(libxl_defbool db)
{
return !db.val;
}
void libxl_defbool_setdefault(libxl_defbool *db, bool b)
{
if (libxl_defbool_is_default(*db))
libxl_defbool_set(db, b);
}
bool libxl_defbool_val(libxl_defbool db)
{
assert(!libxl_defbool_is_default(db));
return db.val > 0;
}
const char *libxl_defbool_to_string(libxl_defbool b)
{
if (b.val < 0)
return LIBXL__DEFBOOL_STR_FALSE;
else if (b.val > 0)
return LIBXL__DEFBOOL_STR_TRUE;
else
return LIBXL__DEFBOOL_STR_DEFAULT;
}
/******************************************************************************/
int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
{
xc_physinfo_t xcphysinfo;
int rc;
long l;
GC_INIT(ctx);
rc = xc_physinfo(ctx->xch, &xcphysinfo);
if (rc != 0) {
LOGE(ERROR, "getting physinfo");
GC_FREE;
return ERROR_FAIL;
}
physinfo->threads_per_core = xcphysinfo.threads_per_core;
physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
physinfo->nr_cpus = xcphysinfo.nr_cpus;
physinfo->cpu_khz = xcphysinfo.cpu_khz;
physinfo->total_pages = xcphysinfo.total_pages;
physinfo->free_pages = xcphysinfo.free_pages;
physinfo->scrub_pages = xcphysinfo.scrub_pages;
physinfo->outstanding_pages = xcphysinfo.outstanding_pages;
physinfo->max_possible_mfn = xcphysinfo.max_mfn;
l = xc_sharing_freed_pages(ctx->xch);
if (l < 0 && errno == ENOSYS) {
l = 0;
} else if (l < 0) {
LOGEV(ERROR, l, "getting sharing freed pages");
GC_FREE;
return ERROR_FAIL;
}
physinfo->sharing_freed_pages = l;
l = xc_sharing_used_frames(ctx->xch);
if (l < 0 && errno == ENOSYS) {
l = 0;
} else if (l < 0) {
LOGEV(ERROR, l, "getting sharing used frames");
GC_FREE;
return ERROR_FAIL;
}
physinfo->sharing_used_frames = l;
physinfo->nr_nodes = xcphysinfo.nr_nodes;
memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap));
physinfo->cap_hvm = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm);
physinfo->cap_pv = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv);
physinfo->cap_hvm_directio =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_directio);
physinfo->cap_hap = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap);
physinfo->cap_shadow =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow);
physinfo->cap_iommu_hap_pt_share =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share);
physinfo->cap_vmtrace =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_vmtrace);
physinfo->cap_vpmu = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_vpmu);
physinfo->cap_gnttab_v1 =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v1);
physinfo->cap_gnttab_v2 =
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2);
physinfo->arch_capabilities = xcphysinfo.arch_capabilities;
physinfo->arm_clock_frequency_hz = xcphysinfo.arm_clock_frequency_hz;
GC_FREE;
return 0;
}
libxl_cputopology *libxl_get_cpu_topology(libxl_ctx *ctx, int *nb_cpu_out)
{
GC_INIT(ctx);
xc_cputopo_t *cputopo;
libxl_cputopology *ret = NULL;
int i;
unsigned num_cpus = 0;
/* Setting buffer to NULL makes the call return number of CPUs */
if (xc_cputopoinfo(ctx->xch, &num_cpus, NULL))
{
LOGE(ERROR, "Unable to determine number of CPUS");
goto out;
}
cputopo = libxl__zalloc(gc, sizeof(*cputopo) * num_cpus);
if (xc_cputopoinfo(ctx->xch, &num_cpus, cputopo)) {
LOGE(ERROR, "CPU topology info hypercall failed");
goto out;
}
ret = libxl__zalloc(NOGC, sizeof(libxl_cputopology) * num_cpus);
for (i = 0; i < num_cpus; i++) {
#define V(map, i, invalid) ( cputopo[i].map == invalid) ? \
LIBXL_CPUTOPOLOGY_INVALID_ENTRY : cputopo[i].map
ret[i].core = V(core, i, XEN_INVALID_CORE_ID);
ret[i].socket = V(socket, i, XEN_INVALID_SOCKET_ID);
ret[i].node = V(node, i, XEN_INVALID_NODE_ID);
#undef V
}
*nb_cpu_out = num_cpus;
out:
GC_FREE;
return ret;
}
libxl_pcitopology *libxl_get_pci_topology(libxl_ctx *ctx, int *num_devs)
{
GC_INIT(ctx);
physdev_pci_device_t *devs;
uint32_t *nodes;
libxl_pcitopology *ret = NULL;
int i, rc;
*num_devs = libxl__pci_numdevs(gc);
if (*num_devs < 0) {
LOG(ERROR, "Unable to determine number of PCI devices, rc %d",
*num_devs);
goto out;
}
devs = libxl__zalloc(gc, sizeof(*devs) * *num_devs);
nodes = libxl__zalloc(gc, sizeof(*nodes) * *num_devs);
rc = libxl__pci_topology_init(gc, devs, *num_devs);
if (rc) {
LOG(ERROR, "Cannot initialize PCI hypercall structure, rc %d", rc);
goto out;
}
if (xc_pcitopoinfo(ctx->xch, *num_devs, devs, nodes) != 0) {
LOGE(ERROR, "PCI topology info hypercall failed");
goto out;
}
ret = libxl__zalloc(NOGC, sizeof(libxl_pcitopology) * *num_devs);
for (i = 0; i < *num_devs; i++) {
ret[i].seg = devs[i].seg;
ret[i].bus = devs[i].bus;
ret[i].devfn = devs[i].devfn;
ret[i].node = ((nodes[i] == XEN_INVALID_NODE_ID) ||
(nodes[i] == XEN_INVALID_DEV)) ?
LIBXL_PCITOPOLOGY_INVALID_ENTRY : nodes[i];
}
out:
GC_FREE;
return ret;
}
libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr)
{
GC_INIT(ctx);
xc_meminfo_t *meminfo;
uint32_t *distance;
libxl_numainfo *ret = NULL;
int i, j;
unsigned num_nodes = 0;
if (xc_numainfo(ctx->xch, &num_nodes, NULL, NULL)) {
LOGE(ERROR, "Unable to determine number of nodes");
goto out;
}
meminfo = libxl__zalloc(gc, sizeof(*meminfo) * num_nodes);
distance = libxl__zalloc(gc, sizeof(*distance) * num_nodes * num_nodes);
if (xc_numainfo(ctx->xch, &num_nodes, meminfo, distance)) {
LOGE(ERROR, "getting numainfo");
goto out;
}
*nr = num_nodes;
ret = libxl__zalloc(NOGC, sizeof(libxl_numainfo) * num_nodes);
for (i = 0; i < num_nodes; i++)
ret[i].dists = libxl__calloc(NOGC, num_nodes, sizeof(*distance));
for (i = 0; i < num_nodes; i++) {
#define V(val, invalid) (val == invalid) ? \
LIBXL_NUMAINFO_INVALID_ENTRY : val
ret[i].size = V(meminfo[i].memsize, XEN_INVALID_MEM_SZ);
ret[i].free = V(meminfo[i].memfree, XEN_INVALID_MEM_SZ);
ret[i].num_dists = num_nodes;
for (j = 0; j < ret[i].num_dists; j++) {
unsigned idx = i * num_nodes + j;
ret[i].dists[j] = V(distance[idx], XEN_INVALID_NODE_DIST);
}
#undef V
}
out:
GC_FREE;
return ret;
}
const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx)
{
GC_INIT(ctx);
union {
xen_compile_info_t xen_cc;
xen_platform_parameters_t p_parms;
xen_build_id_t build_id;
} u;
long xen_version;
libxl_version_info *info = &ctx->version_info;
if (info->xen_version_extra != NULL)
goto out;
xen_version = xc_version(ctx->xch, XENVER_version, NULL);
info->xen_version_major = xen_version >> 16;
info->xen_version_minor = xen_version & 0xFF;
info->xen_version_extra = xc_xenver_extraversion(ctx->xch);
xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc);
info->compiler = libxl__strdup(NOGC, u.xen_cc.compiler);
info->compile_by = libxl__strdup(NOGC, u.xen_cc.compile_by);
info->compile_domain = libxl__strdup(NOGC, u.xen_cc.compile_domain);
info->compile_date = libxl__strdup(NOGC, u.xen_cc.compile_date);
info->capabilities = xc_xenver_capabilities(ctx->xch);
info->changeset = xc_xenver_changeset(ctx->xch);
xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms);
info->virt_start = u.p_parms.virt_start;
info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL);
info->commandline = xc_xenver_commandline(ctx->xch);
info->build_id = xc_xenver_buildid(ctx->xch);
out:
GC_FREE;
return info;
}
int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
{
GC_INIT(ctx);
char *dompath = libxl__xs_get_dompath(gc, domid);
libxl__xs_printf(gc, XBT_NULL, GCSPRINTF("%s/control/sysrq", dompath),
"%c", sysrq);
GC_FREE;
return 0;
}
int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
{
int ret;
GC_INIT(ctx);
ret = xc_send_debug_keys(ctx->xch, keys);
if ( ret < 0 ) {
LOGE(ERROR, "sending debug keys");
GC_FREE;
return ERROR_FAIL;
}
GC_FREE;
return 0;
}
int libxl_set_parameters(libxl_ctx *ctx, char *params)
{
int ret;
GC_INIT(ctx);
char *par, *val, *end, *path;
xenhypfs_handle *hypfs;
hypfs = xenhypfs_open(ctx->lg, 0);
if (!hypfs) {
LOGE(ERROR, "opening Xen hypfs");
ret = ERROR_FAIL;
goto out;
}
while (isblank(*params))
params++;
for (par = params; *par; par = end) {
end = strchr(par, ' ');
if (!end)
end = par + strlen(par);
val = strchr(par, '=');
if (val > end)
val = NULL;
if (!val && !strncmp(par, "no", 2)) {
path = libxl__sprintf(gc, "/params/%s", par + 2);
path[end - par - 2 + 8] = 0;
val = "no";
par += 2;
} else {
path = libxl__sprintf(gc, "/params/%s", par);
path[val - par + 8] = 0;
val = libxl__strndup(gc, val + 1, end - val - 1);
}
LOG(DEBUG, "setting node \"%s\" to value \"%s\"", path, val);
ret = xenhypfs_write(hypfs, path, val);
if (ret < 0) {
LOGE(ERROR, "setting parameters");
ret = ERROR_FAIL;
goto out;
}
while (isblank(*end))
end++;
}
ret = 0;
out:
xenhypfs_close(hypfs);
GC_FREE;
return ret;
}
static int fd_set_flags(libxl_ctx *ctx, int fd,
int fcntlgetop, int fcntlsetop, const char *fl,
int flagmask, int set_p)
{
int flags, r;
GC_INIT(ctx);
flags = fcntl(fd, fcntlgetop);
if (flags == -1) {
LOGE(ERROR, "fcntl(,F_GET%s) failed", fl);
GC_FREE;
return ERROR_FAIL;
}
if (set_p)
flags |= flagmask;
else
flags &= ~flagmask;
r = fcntl(fd, fcntlsetop, flags);
if (r == -1) {
LOGE(ERROR, "fcntl(,F_SET%s) failed", fl);
GC_FREE;
return ERROR_FAIL;
}
GC_FREE;
return 0;
}
int libxl_fd_set_cloexec(libxl_ctx *ctx, int fd, int cloexec)
{ return fd_set_flags(ctx,fd, F_GETFD,F_SETFD,"FD", FD_CLOEXEC, cloexec); }
int libxl_fd_set_nonblock(libxl_ctx *ctx, int fd, int nonblock)
{ return fd_set_flags(ctx,fd, F_GETFL,F_SETFL,"FL", O_NONBLOCK, nonblock); }
int libxl__fd_flags_modify_save(libxl__gc *gc, int fd,
int mask, int val, int *r_oldflags)
{
int rc, ret, fdfl;
fdfl = fcntl(fd, F_GETFL);
if (fdfl < 0) {
LOGE(ERROR, "failed to fcntl.F_GETFL for fd %d", fd);
rc = ERROR_FAIL;
goto out_err;
}
LOG(DEBUG, "fnctl F_GETFL flags for fd %d are 0x%x", fd, fdfl);
if (r_oldflags)
*r_oldflags = fdfl;
fdfl &= mask;
fdfl |= val;
LOG(DEBUG, "fnctl F_SETFL of fd %d to 0x%x", fd, fdfl);
ret = fcntl(fd, F_SETFL, fdfl);
if (ret < 0) {
LOGE(ERROR, "failed to fcntl.F_SETFL for fd %d", fd);
rc = ERROR_FAIL;
goto out_err;
}
rc = 0;
out_err:
return rc;
}
int libxl__fd_flags_restore(libxl__gc *gc, int fd, int fdfl)
{
int ret, rc;
LOG(DEBUG, "fnctl F_SETFL of fd %d to 0x%x", fd, fdfl);
ret = fcntl(fd, F_SETFL, fdfl);
if (ret < 0) {
LOGE(ERROR, "failed to fcntl.F_SETFL for fd %d", fd);
rc = ERROR_FAIL;
goto out_err;
}
rc = 0;
out_err:
return rc;
}
void libxl_hwcap_copy(libxl_ctx *ctx,libxl_hwcap *dst, const libxl_hwcap *src)
{
int i;
for (i = 0; i < 8; i++)
(*dst)[i] = (*src)[i];
}
void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, const libxl_mac *src)
{
int i;
for (i = 0; i < 6; i++)
(*dst)[i] = (*src)[i];
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/