ia64/xen-unstable

view tools/xenstore/xenstored_transaction.c @ 19731:01748ccc4da3

Intel VT-d: fix Stoakley boot issue with iommu=1

Signed-off-by: Weidong Han <Weidong.han@intel.com>
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 09:25:50 2009 +0100 (2009-06-05)
parents 61ef23e45e9c
children
line source
1 /*
2 Transaction code for Xen Store Daemon.
3 Copyright (C) 2005 Rusty Russell IBM Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <sys/time.h>
25 #include <time.h>
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include "talloc.h"
32 #include "list.h"
33 #include "xenstored_transaction.h"
34 #include "xenstored_watch.h"
35 #include "xenstored_domain.h"
36 #include "xs_lib.h"
37 #include "utils.h"
39 struct changed_node
40 {
41 /* List of all changed nodes in the context of this transaction. */
42 struct list_head list;
44 /* The name of the node. */
45 char *node;
47 /* And the children? (ie. rm) */
48 bool recurse;
49 };
51 struct changed_domain
52 {
53 /* List of all changed domains in the context of this transaction. */
54 struct list_head list;
56 /* Identifier of the changed domain. */
57 unsigned int domid;
59 /* Amount by which this domain's nbentry field has changed. */
60 int nbentry;
61 };
63 struct transaction
64 {
65 /* List of all transactions active on this connection. */
66 struct list_head list;
68 /* Connection-local identifier for this transaction. */
69 uint32_t id;
71 /* Generation when transaction started. */
72 unsigned int generation;
74 /* TDB to work on, and filename */
75 TDB_CONTEXT *tdb;
76 char *tdb_name;
78 /* List of changed nodes. */
79 struct list_head changes;
81 /* List of changed domains - to record the changed domain entry number */
82 struct list_head changed_domains;
83 };
85 extern int quota_max_transaction;
86 static unsigned int generation;
88 /* Return tdb context to use for this connection. */
89 TDB_CONTEXT *tdb_transaction_context(struct transaction *trans)
90 {
91 return trans->tdb;
92 }
94 /* Callers get a change node (which can fail) and only commit after they've
95 * finished. This way they don't have to unwind eg. a write. */
96 void add_change_node(struct transaction *trans, const char *node, bool recurse)
97 {
98 struct changed_node *i;
100 if (!trans) {
101 /* They're changing the global database. */
102 generation++;
103 return;
104 }
106 list_for_each_entry(i, &trans->changes, list)
107 if (streq(i->node, node))
108 return;
110 i = talloc(trans, struct changed_node);
111 i->node = talloc_strdup(i, node);
112 i->recurse = recurse;
113 list_add_tail(&i->list, &trans->changes);
114 }
116 static int destroy_transaction(void *_transaction)
117 {
118 struct transaction *trans = _transaction;
120 trace_destroy(trans, "transaction");
121 if (trans->tdb)
122 tdb_close(trans->tdb);
123 unlink(trans->tdb_name);
124 return 0;
125 }
127 struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
128 {
129 struct transaction *trans;
131 if (id == 0)
132 return NULL;
134 list_for_each_entry(trans, &conn->transaction_list, list)
135 if (trans->id == id)
136 return trans;
138 return ERR_PTR(-ENOENT);
139 }
141 void do_transaction_start(struct connection *conn, struct buffered_data *in)
142 {
143 struct transaction *trans, *exists;
144 char id_str[20];
146 /* We don't support nested transactions. */
147 if (conn->transaction) {
148 send_error(conn, EBUSY);
149 return;
150 }
152 if (conn->id && conn->transaction_started > quota_max_transaction) {
153 send_error(conn, ENOSPC);
154 return;
155 }
157 /* Attach transaction to input for autofree until it's complete */
158 trans = talloc(in, struct transaction);
159 INIT_LIST_HEAD(&trans->changes);
160 INIT_LIST_HEAD(&trans->changed_domains);
161 trans->generation = generation;
162 trans->tdb_name = talloc_asprintf(trans, "%s.%p",
163 xs_daemon_tdb(), trans);
164 trans->tdb = tdb_copy(tdb_context(conn), trans->tdb_name);
165 if (!trans->tdb) {
166 send_error(conn, errno);
167 return;
168 }
169 /* Make it close if we go away. */
170 talloc_steal(trans, trans->tdb);
172 /* Pick an unused transaction identifier. */
173 do {
174 trans->id = conn->next_transaction_id;
175 exists = transaction_lookup(conn, conn->next_transaction_id++);
176 } while (!IS_ERR(exists));
178 /* Now we own it. */
179 list_add_tail(&trans->list, &conn->transaction_list);
180 talloc_steal(conn, trans);
181 talloc_set_destructor(trans, destroy_transaction);
182 conn->transaction_started++;
184 snprintf(id_str, sizeof(id_str), "%u", trans->id);
185 send_reply(conn, XS_TRANSACTION_START, id_str, strlen(id_str)+1);
186 }
188 void do_transaction_end(struct connection *conn, const char *arg)
189 {
190 struct changed_node *i;
191 struct changed_domain *d;
192 struct transaction *trans;
194 if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) {
195 send_error(conn, EINVAL);
196 return;
197 }
199 if ((trans = conn->transaction) == NULL) {
200 send_error(conn, ENOENT);
201 return;
202 }
204 conn->transaction = NULL;
205 list_del(&trans->list);
206 conn->transaction_started--;
208 /* Attach transaction to arg for auto-cleanup */
209 talloc_steal(arg, trans);
211 if (streq(arg, "T")) {
212 /* FIXME: Merge, rather failing on any change. */
213 if (trans->generation != generation) {
214 send_error(conn, EAGAIN);
215 return;
216 }
217 if (!replace_tdb(trans->tdb_name, trans->tdb)) {
218 send_error(conn, errno);
219 return;
220 }
221 /* Don't close this: we won! */
222 trans->tdb = NULL;
224 /* fix domain entry for each changed domain */
225 list_for_each_entry(d, &trans->changed_domains, list)
226 domain_entry_fix(d->domid, d->nbentry);
228 /* Fire off the watches for everything that changed. */
229 list_for_each_entry(i, &trans->changes, list)
230 fire_watches(conn, i->node, i->recurse);
231 generation++;
232 }
233 send_ack(conn, XS_TRANSACTION_END);
234 }
236 void transaction_entry_inc(struct transaction *trans, unsigned int domid)
237 {
238 struct changed_domain *d;
240 list_for_each_entry(d, &trans->changed_domains, list)
241 if (d->domid == domid) {
242 d->nbentry++;
243 return;
244 }
246 d = talloc(trans, struct changed_domain);
247 d->domid = domid;
248 d->nbentry = 1;
249 list_add_tail(&d->list, &trans->changed_domains);
250 }
252 void transaction_entry_dec(struct transaction *trans, unsigned int domid)
253 {
254 struct changed_domain *d;
256 list_for_each_entry(d, &trans->changed_domains, list)
257 if (d->domid == domid) {
258 d->nbentry--;
259 return;
260 }
262 d = talloc(trans, struct changed_domain);
263 d->domid = domid;
264 d->nbentry = -1;
265 list_add_tail(&d->list, &trans->changed_domains);
266 }
268 void conn_delete_all_transactions(struct connection *conn)
269 {
270 struct transaction *trans;
272 while ((trans = list_top(&conn->transaction_list,
273 struct transaction, list))) {
274 list_del(&trans->list);
275 talloc_free(trans);
276 }
278 assert(conn->transaction == NULL);
280 conn->transaction_started = 0;
281 }
283 /*
284 * Local variables:
285 * c-file-style: "linux"
286 * indent-tabs-mode: t
287 * c-indent-level: 8
288 * c-basic-offset: 8
289 * tab-width: 8
290 * End:
291 */