@@ -1027,6 +1027,9 @@ static void send_error(struct connection *conn, int error)
break;
}
}
+
+ acc_drop(conn);
+
send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
strlen(xsd_errors[i].errstring) + 1);
}
@@ -1064,6 +1067,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
}
conn->in = NULL;
+ acc_commit(conn);
/* Update relevant header fields and fill in the message body. */
bdata->hdr.msg.type = type;
@@ -2186,6 +2190,7 @@ struct connection *new_connection(const struct interface_funcs *funcs)
new->is_stalled = false;
new->transaction_started = 0;
INIT_LIST_HEAD(&new->out_list);
+ INIT_LIST_HEAD(&new->acc_list);
INIT_LIST_HEAD(&new->ref_list);
INIT_LIST_HEAD(&new->watches);
INIT_LIST_HEAD(&new->transaction_list);
@@ -139,6 +139,9 @@ struct connection
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;
@@ -100,7 +100,7 @@ struct changed_domain
unsigned int domid;
/* Accounting data. */
- int acc[ACC_TR_N];
+ int acc[];
};
static struct hashtable *domhash;
@@ -585,6 +585,7 @@ static struct changed_domain *acc_find_changed_domain(struct list_head *head,
static struct changed_domain *acc_get_changed_domain(const void *ctx,
struct list_head *head,
+ unsigned int acc_sz,
unsigned int domid)
{
struct changed_domain *cd;
@@ -593,7 +594,7 @@ static struct changed_domain *acc_get_changed_domain(const void *ctx,
if (cd)
return cd;
- cd = talloc_zero(ctx, struct changed_domain);
+ cd = talloc_zero_size(ctx, sizeof(*cd) + acc_sz * sizeof(cd->acc[0]));
if (!cd)
return NULL;
@@ -604,11 +605,12 @@ static struct changed_domain *acc_get_changed_domain(const void *ctx,
}
static int acc_add_changed_dom(const void *ctx, struct list_head *head,
- unsigned int what, int val, unsigned int domid)
+ unsigned int acc_sz, unsigned int what,
+ int val, unsigned int domid)
{
struct changed_domain *cd;
- cd = acc_get_changed_domain(ctx, head, domid);
+ cd = acc_get_changed_domain(ctx, head, acc_sz, domid);
if (!cd)
return 0;
@@ -1067,6 +1069,7 @@ static int domain_acc_add(struct connection *conn, unsigned int domid,
unsigned int what, int add, bool dom_exists)
{
struct domain *d;
+ struct changed_domain *cd;
struct list_head *head;
int ret;
@@ -1087,10 +1090,26 @@ static int domain_acc_add(struct connection *conn, unsigned int domid,
}
}
+ /* Temporary accounting data until final commit? */
+ if (conn && conn->in && what < ACC_REQ_N) {
+ /* Consider transaction local data. */
+ ret = 0;
+ if (conn->transaction && what < ACC_TR_N) {
+ head = transaction_get_changed_domains(
+ conn->transaction);
+ cd = acc_find_changed_domain(head, domid);
+ if (cd)
+ ret = cd->acc[what];
+ }
+ ret += acc_add_changed_dom(conn->in, &conn->acc_list, ACC_REQ_N,
+ what, add, domid);
+ return errno ? -1 : domain_acc_add_chk(d, what, ret, domid);
+ }
+
if (conn && conn->transaction && what < ACC_TR_N) {
head = transaction_get_changed_domains(conn->transaction);
- ret = acc_add_changed_dom(conn->transaction, head, what,
- add, domid);
+ ret = acc_add_changed_dom(conn->transaction, head, ACC_TR_N,
+ what, add, domid);
if (errno) {
fail_transaction(conn->transaction);
return -1;
@@ -1103,6 +1122,36 @@ static int domain_acc_add(struct connection *conn, unsigned int domid,
return d->acc[what];
}
+void acc_drop(struct connection *conn)
+{
+ struct changed_domain *cd;
+
+ while ((cd = list_top(&conn->acc_list, struct changed_domain, list))) {
+ list_del(&cd->list);
+ talloc_free(cd);
+ }
+}
+
+void acc_commit(struct connection *conn)
+{
+ struct changed_domain *cd;
+ struct buffered_data *in = conn->in;
+ unsigned int what;
+
+ conn->in = NULL; /* Avoid recursion. */
+ while ((cd = list_top(&conn->acc_list, struct changed_domain, list))) {
+ list_del(&cd->list);
+ for (what = 0; what < ACC_REQ_N; what++)
+ if (cd->acc[what])
+ domain_acc_add(conn, cd->domid, what,
+ cd->acc[what], true);
+
+ talloc_free(cd);
+ }
+
+ conn->in = in;
+}
+
int domain_nbentry_inc(struct connection *conn, unsigned int domid)
{
return (domain_acc_add(conn, domid, ACC_NODES, 1, false) < 0)
@@ -20,7 +20,8 @@
#define _XENSTORED_DOMAIN_H
enum {
- ACC_NODES,
+ ACC_REQ_N, /* Number of elements per request and domain. */
+ ACC_NODES = ACC_REQ_N,
ACC_TR_N, /* Number of elements per transaction and domain. */
ACC_N = ACC_TR_N /* Number of elements per domain. */
};
@@ -103,6 +104,8 @@ void domain_outstanding_domid_dec(unsigned int domid);
int domain_get_quota(const void *ctx, struct connection *conn,
unsigned int domid);
int acc_fix_domains(struct list_head *head, bool update);
+void acc_drop(struct connection *conn);
+void acc_commit(struct connection *conn);
/* Write rate limiting */
Instead of modifying accounting data and undo those modifications in case of an error during further processing, add a framework for collecting the needed changes and commit them only when the whole operation has succeeded. This scheme can reuse large parts of the per transaction accounting. The changed_domain handling can be reused, but the array size of the accounting data should be possible to be different for both use cases. Signed-off-by: Juergen Gross <jgross@suse.com> --- tools/xenstore/xenstored_core.c | 5 +++ tools/xenstore/xenstored_core.h | 3 ++ tools/xenstore/xenstored_domain.c | 61 ++++++++++++++++++++++++++++--- tools/xenstore/xenstored_domain.h | 5 ++- 4 files changed, 67 insertions(+), 7 deletions(-)