mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
The dom0_domid variable is misnamed and conflates purposes. If we have xenstored running in a Linux domain that is not dom0, this variable controls the lookup of /proc/xen/xsd_kva and the event channel. Rename to store_domid to better show its purpose. One implication of this change is that the xenstore domain is not privileged by virtue of considering store_domid as privileged. domain_is_unprivileged() removes the dom0_domid/store_domid check, so xenstore domain is no longer considered privileged. onearg_domain() is updated to return EINVAL for store_domid or priv_domid to maintain the ability to call XS_RESUME. xenbus_master_domid() is removed with store_domid being used instead. Add a description of the -m/--master-domid options while doing this. Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Reviewed-by: Juergen Gross <jgross@suse.com>
498 lines
14 KiB
C
498 lines
14 KiB
C
/*
|
|
Internal interfaces for Xen Store Daemon.
|
|
Copyright (C) 2005 Rusty Russell IBM Corporation
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _XENSTORED_CORE_H
|
|
#define _XENSTORED_CORE_H
|
|
|
|
#include <xengnttab.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <poll.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <xenevtchn.h>
|
|
|
|
#include "xenstore_lib.h"
|
|
#include "xenstore_state.h"
|
|
#include "list.h"
|
|
#include "hashtable.h"
|
|
|
|
#define XENSTORE_LIB_DIR XEN_LIB_DIR "/xenstore"
|
|
|
|
#ifndef O_CLOEXEC
|
|
#define O_CLOEXEC 0
|
|
/* O_CLOEXEC support is needed for Live Update in the daemon case. */
|
|
#ifndef __MINIOS__
|
|
#define NO_LIVE_UPDATE
|
|
#endif
|
|
#endif
|
|
|
|
/* Live update in stubdom case needs kexec support. */
|
|
#if defined(__MINIOS__) && !defined(CONFIG_KEXEC)
|
|
#define NO_LIVE_UPDATE
|
|
#endif
|
|
|
|
/* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
|
|
#define DEFAULT_BUFFER_SIZE 16
|
|
|
|
struct xs_state_connection;
|
|
|
|
struct buffered_data
|
|
{
|
|
struct list_head list;
|
|
bool on_out_list;
|
|
bool on_ref_list;
|
|
|
|
/* Are we still doing the header? */
|
|
bool inhdr;
|
|
|
|
/* Is this a watch event? */
|
|
bool watch_event;
|
|
|
|
/* How far are we? */
|
|
unsigned int used;
|
|
|
|
/* Outstanding request accounting. */
|
|
union {
|
|
/* ref is being used for requests. */
|
|
struct {
|
|
unsigned int event_cnt; /* # of outstanding events. */
|
|
unsigned int domid; /* domid of request. */
|
|
} ref;
|
|
/* req is being used for watch events. */
|
|
struct buffered_data *req; /* request causing event. */
|
|
} pend;
|
|
|
|
union {
|
|
struct xsd_sockmsg msg;
|
|
char raw[sizeof(struct xsd_sockmsg)];
|
|
} hdr;
|
|
|
|
uint64_t timeout_msec;
|
|
|
|
/* The actual data. */
|
|
char *buffer;
|
|
char default_buffer[DEFAULT_BUFFER_SIZE];
|
|
};
|
|
|
|
struct delayed_request {
|
|
/* Next delayed request. */
|
|
struct list_head list;
|
|
|
|
/* The delayed request. */
|
|
struct buffered_data *in;
|
|
|
|
/* Function to call. */
|
|
bool (*func)(struct delayed_request *req);
|
|
|
|
/* Further data. */
|
|
void *data;
|
|
};
|
|
|
|
struct connection;
|
|
|
|
struct interface_funcs {
|
|
int (*write)(struct connection *, const void *, unsigned int);
|
|
int (*read)(struct connection *, void *, unsigned int);
|
|
bool (*can_write)(struct connection *);
|
|
bool (*can_read)(struct connection *);
|
|
};
|
|
|
|
struct connection
|
|
{
|
|
struct list_head list;
|
|
|
|
/* The file descriptor we came in on. */
|
|
int fd;
|
|
/* The index of pollfd in global pollfd array */
|
|
int pollfd_idx;
|
|
|
|
/* Who am I? Domid of connection. */
|
|
unsigned int id;
|
|
|
|
/* Is this connection ignored? */
|
|
bool is_ignored;
|
|
|
|
/* Is the connection stalled? */
|
|
bool is_stalled;
|
|
|
|
/* Buffered incoming data. */
|
|
struct buffered_data *in;
|
|
|
|
/* Buffered output data */
|
|
struct list_head out_list;
|
|
uint64_t timeout_msec;
|
|
|
|
/* Not yet committed accounting data (valid if in != NULL). */
|
|
struct list_head acc_list;
|
|
|
|
/* Referenced requests no longer pending. */
|
|
struct list_head ref_list;
|
|
|
|
/* Transaction context for current request (NULL if none). */
|
|
struct transaction *transaction;
|
|
|
|
/* List of in-progress transactions. */
|
|
struct list_head transaction_list;
|
|
uint32_t next_transaction_id;
|
|
time_t ta_start_time;
|
|
|
|
/* List of delayed requests. */
|
|
struct list_head delayed;
|
|
|
|
/* The domain I'm associated with, if any. */
|
|
struct domain *domain;
|
|
|
|
/* The target of the domain I'm associated with. */
|
|
struct connection *target;
|
|
|
|
/* My watches. */
|
|
struct list_head watches;
|
|
|
|
/* Methods for communicating over this connection. */
|
|
const struct interface_funcs *funcs;
|
|
|
|
/* Support for live update: connection id. */
|
|
unsigned int conn_id;
|
|
};
|
|
extern struct list_head connections;
|
|
|
|
/*
|
|
* Header of the node record in the data base.
|
|
* In the data base the memory of the node is a single memory chunk with the
|
|
* following format:
|
|
* struct {
|
|
* node_hdr hdr;
|
|
* struct xs_permissions perms[hdr.num_perms];
|
|
* char data[hdr.datalen];
|
|
* char children[hdr.childlen];
|
|
* };
|
|
*/
|
|
struct node_hdr {
|
|
uint64_t generation;
|
|
#define NO_GENERATION ~((uint64_t)0)
|
|
uint16_t num_perms;
|
|
uint16_t datalen;
|
|
uint32_t childlen;
|
|
};
|
|
|
|
struct node_perms {
|
|
unsigned int num;
|
|
struct xs_permissions *p;
|
|
};
|
|
|
|
struct node_account_data {
|
|
unsigned int domid;
|
|
int memory; /* -1 if unknown */
|
|
};
|
|
|
|
struct node {
|
|
/* Copied to/from data base. */
|
|
struct node_hdr hdr;
|
|
|
|
/* Xenstore path. */
|
|
const char *name;
|
|
/* Name used to access data base. */
|
|
const char *db_name;
|
|
|
|
/* Parent (optional) */
|
|
struct node *parent;
|
|
|
|
/* Permissions. */
|
|
struct xs_permissions *perms;
|
|
|
|
/* Contents. */
|
|
void *data;
|
|
|
|
/* Children, each nul-terminated. */
|
|
unsigned int childoff; /* Used by walk_node_tree() internally. */
|
|
char *children;
|
|
|
|
/* Allocation information for node currently in store. */
|
|
struct node_account_data acc;
|
|
};
|
|
|
|
/* Return the only argument in the input. */
|
|
const char *onearg(struct buffered_data *in);
|
|
|
|
/* Break input into vectors, return the number, fill in up to num of them. */
|
|
unsigned int get_strings(struct buffered_data *data,
|
|
const char *vec[], unsigned int num);
|
|
unsigned int get_string(const struct buffered_data *data, unsigned int offset);
|
|
|
|
void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
|
|
const void *data, unsigned int len);
|
|
void send_event(struct buffered_data *req, struct connection *conn,
|
|
const char *path, const char *token);
|
|
|
|
/* Some routines (write, mkdir, etc) just need a non-error return */
|
|
void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
|
|
|
|
/* Canonicalize this path if possible. */
|
|
const char *canonicalize(struct connection *conn, const void *ctx,
|
|
const char *node, bool allow_special);
|
|
|
|
/* Get access permissions. */
|
|
unsigned int perm_for_conn(struct connection *conn,
|
|
const struct node_perms *perms);
|
|
|
|
/* Get owner of a node. */
|
|
static inline unsigned int get_node_owner(const struct node *node)
|
|
{
|
|
return node->perms[0].id;
|
|
}
|
|
|
|
/* Transfer permissions from node to struct node_perms. */
|
|
static inline void node_to_node_perms(const struct node *node,
|
|
struct node_perms *perms)
|
|
{
|
|
perms->num = node->hdr.num_perms;
|
|
perms->p = node->perms;
|
|
}
|
|
|
|
static inline unsigned int perm_for_conn_from_node(struct connection *conn,
|
|
const struct node *node)
|
|
{
|
|
struct node_perms perms;
|
|
|
|
node_to_node_perms(node, &perms);
|
|
|
|
return perm_for_conn(conn, &perms);
|
|
}
|
|
|
|
/* Transfer permissions from struct node_perms to node. */
|
|
static inline void node_perms_to_node(const struct node_perms *perms,
|
|
struct node *node)
|
|
{
|
|
node->hdr.num_perms = perms->num;
|
|
node->perms = perms->p;
|
|
}
|
|
|
|
/* Write a node to the data base. */
|
|
enum write_node_mode {
|
|
NODE_CREATE,
|
|
NODE_MODIFY
|
|
};
|
|
|
|
int write_node_raw(struct connection *conn, const char *db_name,
|
|
struct node *node, enum write_node_mode mode,
|
|
bool no_quota_check);
|
|
|
|
/* Get a node from the data base. */
|
|
struct node *read_node(struct connection *conn, const void *ctx,
|
|
const char *name);
|
|
const struct node *read_node_const(struct connection *conn, const void *ctx,
|
|
const char *name);
|
|
|
|
/* Remove a node and its children. */
|
|
int rm_node(struct connection *conn, const void *ctx, const char *name);
|
|
|
|
void setup_structure(bool live_update);
|
|
struct connection *new_connection(const struct interface_funcs *funcs);
|
|
struct connection *add_socket_connection(int fd);
|
|
struct connection *get_connection_by_id(unsigned int conn_id);
|
|
void check_store(void);
|
|
void corrupt(struct connection *conn, const char *fmt, ...);
|
|
|
|
/* Get name of parent node. */
|
|
char *get_parent(const void *ctx, const char *node);
|
|
|
|
/* Delay a request. */
|
|
int delay_request(struct connection *conn, struct buffered_data *in,
|
|
bool (*func)(struct delayed_request *), void *data,
|
|
bool no_quota_check);
|
|
|
|
/* Tracing infrastructure. */
|
|
void trace_create(const void *data, const char *type);
|
|
void trace_destroy(const void *data, const char *type);
|
|
void trace(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
|
void reopen_log(void);
|
|
void close_log(void);
|
|
|
|
#define log(...) \
|
|
do { \
|
|
int _saved_errno = errno; \
|
|
char *s = talloc_asprintf(NULL, __VA_ARGS__); \
|
|
if (s) { \
|
|
trace("%s\n", s); \
|
|
syslog(LOG_ERR, "%s\n", s); \
|
|
talloc_free(s); \
|
|
} else { \
|
|
trace("talloc failure during logging\n"); \
|
|
syslog(LOG_ERR, "talloc failure during logging\n"); \
|
|
} \
|
|
errno = _saved_errno; \
|
|
} while (0)
|
|
|
|
extern int orig_argc;
|
|
extern char **orig_argv;
|
|
|
|
extern const char *tracefile;
|
|
extern int tracefd;
|
|
|
|
/* Trace flag values must be kept in sync with trace_switches[] contents. */
|
|
extern unsigned int trace_flags;
|
|
#define TRACE_OBJ 0x00000001
|
|
#define TRACE_IO 0x00000002
|
|
#define TRACE_WRL 0x00000004
|
|
#define TRACE_ACC 0x00000008
|
|
#define TRACE_TDB 0x00000010
|
|
extern const char *const trace_switches[];
|
|
int set_trace_switch(const char *arg);
|
|
|
|
#define trace_tdb(...) \
|
|
do { \
|
|
if (trace_flags & TRACE_TDB) \
|
|
trace("tdb: " __VA_ARGS__); \
|
|
} while (0)
|
|
|
|
extern int store_domid;
|
|
extern int dom0_event;
|
|
extern int priv_domid;
|
|
extern domid_t stub_domid;
|
|
extern bool keep_orphans;
|
|
|
|
extern struct pollfd *poll_fds;
|
|
|
|
extern unsigned int timeout_watch_event_msec;
|
|
|
|
/* Get internal time in milliseconds. */
|
|
uint64_t get_now_msec(void);
|
|
|
|
/* Map the kernel's xenstore page. */
|
|
void *xenbus_map(void);
|
|
void unmap_xenbus(void *interface);
|
|
|
|
static inline bool domid_is_unprivileged(unsigned int domid)
|
|
{
|
|
return domid != priv_domid;
|
|
}
|
|
|
|
static inline bool domain_is_unprivileged(const struct connection *conn)
|
|
{
|
|
return conn && domid_is_unprivileged(conn->id);
|
|
}
|
|
|
|
extern xenevtchn_handle *xce_handle; /* in domain.c */
|
|
|
|
/* Return the event channel used by xenbus. */
|
|
evtchn_port_t get_domain_evtchn(unsigned int domid);
|
|
void early_init(bool live_update, bool dofork, const char *pidfile);
|
|
void late_init(bool live_update);
|
|
|
|
int set_fd(int fd, short events);
|
|
void set_special_fds(void);
|
|
void handle_special_fds(void);
|
|
|
|
int get_socket_fd(void);
|
|
void set_socket_fd(int fd);
|
|
|
|
xenevtchn_handle *evtchn_fdopen(int fd);
|
|
int evtchn_rebind(int port);
|
|
|
|
#ifdef __MINIOS__
|
|
void mount_9pfs(bool live_update);
|
|
#endif
|
|
|
|
const char *xenstore_rundir(void);
|
|
const char *absolute_filename(const void *ctx, const char *filename);
|
|
|
|
/* Close stdin/stdout/stderr to complete daemonize */
|
|
void finish_daemonize(void);
|
|
|
|
extern xengnttab_handle **xgt_handle;
|
|
|
|
int remember_string(struct hashtable *hash, const char *str);
|
|
|
|
/* Data base access functions. */
|
|
const struct node_hdr *db_fetch(const char *db_name, size_t *size);
|
|
int db_write(struct connection *conn, const char *db_name, void *data,
|
|
size_t size, struct node_account_data *acc,
|
|
enum write_node_mode mode, bool no_quota_check);
|
|
void db_delete(struct connection *conn, const char *name,
|
|
struct node_account_data *acc);
|
|
|
|
void conn_free_buffered_data(struct connection *conn);
|
|
|
|
const char *dump_state_global(FILE *fp);
|
|
const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
|
|
struct xs_state_connection *sc);
|
|
const char *dump_state_nodes(FILE *fp, const void *ctx);
|
|
const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
|
|
unsigned int n_perms);
|
|
|
|
void read_state_global(const void *ctx, const void *state);
|
|
void read_state_buffered_data(const void *ctx, struct connection *conn,
|
|
const struct xs_state_connection *sc);
|
|
void read_state_node(const void *ctx, const void *state);
|
|
|
|
/*
|
|
* Walk the node tree below root calling funcs->enter() and funcs->exit() for
|
|
* each node. funcs->enter() is being called when entering a node, so before
|
|
* any of the children of the node is processed. funcs->exit() is being
|
|
* called when leaving the node, so after all children have been processed.
|
|
* funcs->enoent() is being called when a node isn't existing.
|
|
* funcs->*() return values:
|
|
* < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
|
|
* in case WALK_TREE_ERROR_STOP is returned, errno should be set
|
|
* WALK_TREE_OK: tree walk is continuing
|
|
* WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
|
|
* walk continues
|
|
* WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
|
|
* the modified parent node back to the data base, implies to not descend
|
|
* below the current node, but to continue the walk
|
|
* funcs->*() is allowed to modify the node it is called for in the data base.
|
|
* In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
|
|
* in order to avoid descending into no longer existing children.
|
|
*/
|
|
/* Return values for funcs->*() and walk_node_tree(). */
|
|
#define WALK_TREE_SUCCESS_STOP -100 /* Stop walk early, no error. */
|
|
#define WALK_TREE_ERROR_STOP -1 /* Stop walk due to error. */
|
|
#define WALK_TREE_OK 0 /* No error. */
|
|
/* Return value for funcs->*() only. */
|
|
#define WALK_TREE_SKIP_CHILDREN 1 /* Don't recurse below current node. */
|
|
#define WALK_TREE_RM_CHILDENTRY 2 /* Remove child entry from parent. */
|
|
|
|
struct walk_funcs {
|
|
int (*enter)(const void *ctx, struct connection *conn,
|
|
struct node *node, void *arg);
|
|
int (*exit)(const void *ctx, struct connection *conn,
|
|
struct node *node, void *arg);
|
|
int (*enoent)(const void *ctx, struct connection *conn,
|
|
struct node *parent, char *name, void *arg);
|
|
};
|
|
|
|
int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
|
|
struct walk_funcs *funcs, void *arg);
|
|
|
|
#endif /* _XENSTORED_CORE_H */
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "linux"
|
|
* indent-tabs-mode: t
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* End:
|
|
*/
|