ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c @ 10076:18c3da3ad6f7

When doing local migration, a timing-related problem occurred due to the
frontend switching to the Closed state, which could end up having
the .remove function being called after the backend has shut down. This
now fixes the problem by switching to the Closing state.
The other part of the patch cleans up freeing of memory.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 17 23:28:22 2006 +0100 (2006-05-17)
parents daa8047710d0
children 48c0f5489d44
line source
1 /* Xenbus code for tpmif backend
2 Copyright (C) 2005 IBM Corporation
3 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
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 */
19 #include <stdarg.h>
20 #include <linux/module.h>
21 #include <xen/xenbus.h>
22 #include "common.h"
24 struct backend_info
25 {
26 struct xenbus_device *dev;
28 /* our communications channel */
29 tpmif_t *tpmif;
31 long int frontend_id;
32 long int instance; // instance of TPM
33 u8 is_instance_set;// whether instance number has been set
35 /* watch front end for changes */
36 struct xenbus_watch backend_watch;
37 XenbusState frontend_state;
38 };
40 static void maybe_connect(struct backend_info *be);
41 static void connect(struct backend_info *be);
42 static int connect_ring(struct backend_info *be);
43 static void backend_changed(struct xenbus_watch *watch,
44 const char **vec, unsigned int len);
45 static void frontend_changed(struct xenbus_device *dev,
46 XenbusState frontend_state);
48 static int tpmback_remove(struct xenbus_device *dev)
49 {
50 struct backend_info *be = dev->data;
52 if (!be) return 0;
54 if (be->backend_watch.node) {
55 unregister_xenbus_watch(&be->backend_watch);
56 kfree(be->backend_watch.node);
57 be->backend_watch.node = NULL;
58 }
59 if (be->tpmif) {
60 vtpm_release_packets(be->tpmif, 0);
61 tpmif_put(be->tpmif);
62 be->tpmif = NULL;
63 }
64 kfree(be);
65 dev->data = NULL;
66 return 0;
67 }
69 static int tpmback_probe(struct xenbus_device *dev,
70 const struct xenbus_device_id *id)
71 {
72 int err;
73 struct backend_info *be = kzalloc(sizeof(struct backend_info),
74 GFP_KERNEL);
76 if (!be) {
77 xenbus_dev_fatal(dev, -ENOMEM,
78 "allocating backend structure");
79 return -ENOMEM;
80 }
82 be->is_instance_set = 0;
83 be->dev = dev;
84 dev->data = be;
86 err = xenbus_watch_path2(dev, dev->nodename,
87 "instance", &be->backend_watch,
88 backend_changed);
89 if (err) {
90 goto fail;
91 }
93 err = xenbus_switch_state(dev, XenbusStateInitWait);
94 if (err) {
95 goto fail;
96 }
97 return 0;
98 fail:
99 tpmback_remove(dev);
100 return err;
101 }
104 static void backend_changed(struct xenbus_watch *watch,
105 const char **vec, unsigned int len)
106 {
107 int err;
108 long instance;
109 struct backend_info *be
110 = container_of(watch, struct backend_info, backend_watch);
111 struct xenbus_device *dev = be->dev;
113 err = xenbus_scanf(XBT_NULL, dev->nodename,
114 "instance","%li", &instance);
115 if (XENBUS_EXIST_ERR(err)) {
116 return;
117 }
119 if (err != 1) {
120 xenbus_dev_fatal(dev, err, "reading instance");
121 return;
122 }
124 if (be->is_instance_set == 0) {
125 be->instance = instance;
126 be->is_instance_set = 1;
127 }
128 }
131 static void frontend_changed(struct xenbus_device *dev,
132 XenbusState frontend_state)
133 {
134 struct backend_info *be = dev->data;
135 int err;
137 be->frontend_state = frontend_state;
139 switch (frontend_state) {
140 case XenbusStateInitialising:
141 case XenbusStateInitialised:
142 break;
144 case XenbusStateConnected:
145 err = connect_ring(be);
146 if (err) {
147 return;
148 }
149 maybe_connect(be);
150 break;
152 case XenbusStateClosing:
153 be->tpmif->tpm_instance = -1;
154 break;
156 case XenbusStateClosed:
157 /*
158 * Notify the vTPM manager about the front-end
159 * having left.
160 */
161 tpmif_vtpm_close(be->instance);
162 device_unregister(&be->dev->dev);
163 tpmback_remove(dev);
164 break;
166 case XenbusStateUnknown:
167 case XenbusStateInitWait:
168 default:
169 xenbus_dev_fatal(dev, -EINVAL,
170 "saw state %d at frontend",
171 frontend_state);
172 break;
173 }
174 }
178 static void maybe_connect(struct backend_info *be)
179 {
180 int err;
182 if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
183 return;
185 connect(be);
187 /*
188 * Notify the vTPM manager about a new front-end.
189 */
190 err = tpmif_vtpm_open(be->tpmif,
191 be->frontend_id,
192 be->instance);
193 if (err) {
194 xenbus_dev_error(be->dev, err,
195 "queueing vtpm open packet");
196 /*
197 * Should close down this device and notify FE
198 * about closure.
199 */
200 return;
201 }
202 }
205 static void connect(struct backend_info *be)
206 {
207 xenbus_transaction_t xbt;
208 int err;
209 struct xenbus_device *dev = be->dev;
210 unsigned long ready = 1;
212 again:
213 err = xenbus_transaction_start(&xbt);
214 if (err) {
215 xenbus_dev_fatal(be->dev, err, "starting transaction");
216 return;
217 }
219 err = xenbus_printf(xbt, be->dev->nodename,
220 "ready", "%lu", ready);
221 if (err) {
222 xenbus_dev_fatal(be->dev, err, "writing 'ready'");
223 goto abort;
224 }
226 err = xenbus_transaction_end(xbt, 0);
227 if (err == -EAGAIN)
228 goto again;
229 if (err)
230 xenbus_dev_fatal(be->dev, err, "end of transaction");
232 err = xenbus_switch_state(dev, XenbusStateConnected);
233 if (!err)
234 be->tpmif->status = CONNECTED;
235 return;
236 abort:
237 xenbus_transaction_end(xbt, 1);
238 }
241 static int connect_ring(struct backend_info *be)
242 {
243 struct xenbus_device *dev = be->dev;
244 unsigned long ring_ref;
245 unsigned int evtchn;
246 int err;
248 err = xenbus_gather(XBT_NULL, dev->otherend,
249 "ring-ref", "%lu", &ring_ref,
250 "event-channel", "%u", &evtchn, NULL);
251 if (err) {
252 xenbus_dev_error(dev, err,
253 "reading %s/ring-ref and event-channel",
254 dev->otherend);
255 return err;
256 }
258 if (!be->tpmif) {
259 be->tpmif = tpmif_find(dev->otherend_id,
260 be->instance);
261 if (IS_ERR(be->tpmif)) {
262 err = PTR_ERR(be->tpmif);
263 be->tpmif = NULL;
264 xenbus_dev_fatal(dev,err,"creating vtpm interface");
265 return err;
266 }
267 }
269 if (be->tpmif != NULL) {
270 err = tpmif_map(be->tpmif, ring_ref, evtchn);
271 if (err) {
272 xenbus_dev_error(dev, err,
273 "mapping shared-frame %lu port %u",
274 ring_ref, evtchn);
275 return err;
276 }
277 }
278 return 0;
279 }
282 static struct xenbus_device_id tpmback_ids[] = {
283 { "vtpm" },
284 { "" }
285 };
288 static struct xenbus_driver tpmback = {
289 .name = "vtpm",
290 .owner = THIS_MODULE,
291 .ids = tpmback_ids,
292 .probe = tpmback_probe,
293 .remove = tpmback_remove,
294 .otherend_changed = frontend_changed,
295 };
298 void tpmif_xenbus_init(void)
299 {
300 xenbus_register_backend(&tpmback);
301 }
303 void tpmif_xenbus_exit(void)
304 {
305 xenbus_unregister_driver(&tpmback);
306 }
308 /*
309 * Local variables:
310 * c-file-style: "linux"
311 * indent-tabs-mode: t
312 * c-indent-level: 8
313 * c-basic-offset: 8
314 * tab-width: 8
315 * End:
316 */