]>
Commit | Line | Data |
---|---|---|
9f107513 AL |
1 | /* |
2 | * Virtio 9p PDU debug | |
3 | * | |
4 | * Copyright IBM, Corp. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | #include "virtio.h" | |
14 | #include "pc.h" | |
15 | #include "virtio-9p.h" | |
16 | #include "virtio-9p-debug.h" | |
17 | ||
18 | #define BUG_ON(cond) assert(!(cond)) | |
19 | ||
20 | static FILE *llogfile; | |
21 | ||
22 | static struct iovec *get_sg(V9fsPDU *pdu, int rx) | |
23 | { | |
24 | if (rx) { | |
25 | return pdu->elem.in_sg; | |
26 | } | |
27 | return pdu->elem.out_sg; | |
28 | } | |
29 | ||
30 | static int get_sg_count(V9fsPDU *pdu, int rx) | |
31 | { | |
32 | if (rx) { | |
33 | return pdu->elem.in_num; | |
34 | } | |
35 | return pdu->elem.out_num; | |
36 | ||
37 | } | |
38 | ||
39 | static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp, | |
40 | const char *name) | |
41 | { | |
42 | size_t copied; | |
43 | int count = get_sg_count(pdu, rx); | |
44 | size_t offset = *offsetp; | |
45 | struct iovec *sg = get_sg(pdu, rx); | |
46 | int8_t value; | |
47 | ||
48 | copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); | |
49 | ||
50 | BUG_ON(copied != sizeof(value)); | |
51 | offset += sizeof(value); | |
52 | fprintf(llogfile, "%s=0x%x", name, value); | |
53 | *offsetp = offset; | |
54 | } | |
55 | ||
56 | static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp, | |
57 | const char *name) | |
58 | { | |
59 | size_t copied; | |
60 | int count = get_sg_count(pdu, rx); | |
61 | struct iovec *sg = get_sg(pdu, rx); | |
62 | size_t offset = *offsetp; | |
63 | int16_t value; | |
64 | ||
65 | ||
66 | copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); | |
67 | ||
68 | BUG_ON(copied != sizeof(value)); | |
69 | offset += sizeof(value); | |
70 | fprintf(llogfile, "%s=0x%x", name, value); | |
71 | *offsetp = offset; | |
72 | } | |
73 | ||
74 | static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp, | |
75 | const char *name) | |
76 | { | |
77 | size_t copied; | |
78 | int count = get_sg_count(pdu, rx); | |
79 | struct iovec *sg = get_sg(pdu, rx); | |
80 | size_t offset = *offsetp; | |
81 | int32_t value; | |
82 | ||
83 | ||
84 | copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); | |
85 | ||
86 | BUG_ON(copied != sizeof(value)); | |
87 | offset += sizeof(value); | |
88 | fprintf(llogfile, "%s=0x%x", name, value); | |
89 | *offsetp = offset; | |
90 | } | |
91 | ||
92 | static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp, | |
93 | const char *name) | |
94 | { | |
95 | size_t copied; | |
96 | int count = get_sg_count(pdu, rx); | |
97 | struct iovec *sg = get_sg(pdu, rx); | |
98 | size_t offset = *offsetp; | |
99 | int64_t value; | |
100 | ||
101 | ||
102 | copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); | |
103 | ||
104 | BUG_ON(copied != sizeof(value)); | |
105 | offset += sizeof(value); | |
106 | fprintf(llogfile, "%s=0x%" PRIx64, name, value); | |
107 | *offsetp = offset; | |
108 | } | |
109 | ||
110 | static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
111 | { | |
112 | int sg_count = get_sg_count(pdu, rx); | |
113 | struct iovec *sg = get_sg(pdu, rx); | |
114 | size_t offset = *offsetp; | |
115 | uint16_t tmp_size, size; | |
116 | size_t result; | |
117 | size_t copied = 0; | |
118 | int i = 0; | |
119 | ||
120 | /* get the size */ | |
121 | copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size)); | |
122 | BUG_ON(copied != sizeof(tmp_size)); | |
123 | size = le16_to_cpupu(&tmp_size); | |
124 | offset += copied; | |
125 | ||
126 | fprintf(llogfile, "%s=", name); | |
127 | for (i = 0; size && i < sg_count; i++) { | |
128 | size_t len; | |
129 | if (offset >= sg[i].iov_len) { | |
130 | /* skip this sg */ | |
131 | offset -= sg[i].iov_len; | |
132 | continue; | |
133 | } else { | |
134 | len = MIN(sg[i].iov_len - offset, size); | |
135 | result = fwrite(sg[i].iov_base + offset, 1, len, llogfile); | |
136 | BUG_ON(result != len); | |
137 | size -= len; | |
138 | copied += len; | |
139 | if (size) { | |
140 | offset = 0; | |
141 | continue; | |
142 | } | |
143 | } | |
144 | } | |
145 | *offsetp += copied; | |
146 | } | |
147 | ||
148 | static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
149 | { | |
150 | fprintf(llogfile, "%s={", name); | |
151 | pprint_int8(pdu, rx, offsetp, "type"); | |
152 | pprint_int32(pdu, rx, offsetp, ", version"); | |
153 | pprint_int64(pdu, rx, offsetp, ", path"); | |
154 | fprintf(llogfile, "}"); | |
155 | } | |
156 | ||
157 | static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
158 | { | |
159 | fprintf(llogfile, "%s={", name); | |
160 | pprint_int16(pdu, rx, offsetp, "size"); | |
161 | pprint_int16(pdu, rx, offsetp, ", type"); | |
162 | pprint_int32(pdu, rx, offsetp, ", dev"); | |
163 | pprint_qid(pdu, rx, offsetp, ", qid"); | |
164 | pprint_int32(pdu, rx, offsetp, ", mode"); | |
165 | pprint_int32(pdu, rx, offsetp, ", atime"); | |
166 | pprint_int32(pdu, rx, offsetp, ", mtime"); | |
167 | pprint_int64(pdu, rx, offsetp, ", length"); | |
168 | pprint_str(pdu, rx, offsetp, ", name"); | |
169 | pprint_str(pdu, rx, offsetp, ", uid"); | |
170 | pprint_str(pdu, rx, offsetp, ", gid"); | |
171 | pprint_str(pdu, rx, offsetp, ", muid"); | |
172 | if (dotu) { | |
173 | pprint_str(pdu, rx, offsetp, ", extension"); | |
174 | pprint_int32(pdu, rx, offsetp, ", uid"); | |
175 | pprint_int32(pdu, rx, offsetp, ", gid"); | |
176 | pprint_int32(pdu, rx, offsetp, ", muid"); | |
177 | } | |
178 | fprintf(llogfile, "}"); | |
179 | } | |
180 | ||
181 | static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
182 | { | |
183 | int sg_count = get_sg_count(pdu, rx); | |
184 | struct iovec *sg = get_sg(pdu, rx); | |
185 | size_t offset = *offsetp; | |
186 | uint16_t tmp_count, count, i; | |
187 | size_t copied = 0; | |
188 | ||
189 | fprintf(llogfile, "%s={", name); | |
190 | ||
191 | /* Get the count */ | |
192 | copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); | |
193 | BUG_ON(copied != sizeof(tmp_count)); | |
194 | count = le16_to_cpupu(&tmp_count); | |
195 | offset += copied; | |
196 | ||
197 | for (i = 0; i < count; i++) { | |
198 | char str[512]; | |
199 | if (i) { | |
200 | fprintf(llogfile, ", "); | |
201 | } | |
202 | snprintf(str, sizeof(str), "[%d]", i); | |
203 | pprint_str(pdu, rx, &offset, str); | |
204 | } | |
205 | ||
206 | fprintf(llogfile, "}"); | |
207 | ||
208 | *offsetp = offset; | |
209 | } | |
210 | ||
211 | static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
212 | { | |
213 | int sg_count = get_sg_count(pdu, rx); | |
214 | struct iovec *sg = get_sg(pdu, rx); | |
215 | size_t offset = *offsetp; | |
216 | uint16_t tmp_count, count, i; | |
217 | size_t copied = 0; | |
218 | ||
219 | fprintf(llogfile, "%s={", name); | |
220 | ||
221 | copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); | |
222 | BUG_ON(copied != sizeof(tmp_count)); | |
223 | count = le16_to_cpupu(&tmp_count); | |
224 | offset += copied; | |
225 | ||
226 | for (i = 0; i < count; i++) { | |
227 | char str[512]; | |
228 | if (i) { | |
229 | fprintf(llogfile, ", "); | |
230 | } | |
231 | snprintf(str, sizeof(str), "[%d]", i); | |
232 | pprint_qid(pdu, rx, &offset, str); | |
233 | } | |
234 | ||
235 | fprintf(llogfile, "}"); | |
236 | ||
237 | *offsetp = offset; | |
238 | } | |
239 | ||
240 | static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
241 | { | |
242 | struct iovec *sg = get_sg(pdu, rx); | |
243 | unsigned int count; | |
244 | int i; | |
245 | ||
246 | if (rx) { | |
247 | count = pdu->elem.in_num; | |
248 | } else { | |
249 | count = pdu->elem.out_num; | |
250 | } | |
251 | ||
252 | fprintf(llogfile, "%s={", name); | |
253 | for (i = 0; i < count; i++) { | |
254 | if (i) { | |
255 | fprintf(llogfile, ", "); | |
256 | } | |
257 | fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len); | |
258 | } | |
259 | fprintf(llogfile, "}"); | |
260 | } | |
261 | ||
262 | /* FIXME: read from a directory fid returns serialized stat_t's */ | |
263 | #ifdef DEBUG_DATA | |
264 | static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) | |
265 | { | |
266 | struct iovec *sg = get_sg(pdu, rx); | |
267 | size_t offset = *offsetp; | |
268 | unsigned int count; | |
269 | int32_t size; | |
270 | int total, i, j; | |
271 | ssize_t len; | |
272 | ||
273 | if (rx) { | |
274 | count = pdu->elem.in_num; | |
275 | } else | |
276 | count = pdu->elem.out_num; | |
277 | } | |
278 | ||
279 | BUG_ON((offset + sizeof(size)) > sg[0].iov_len); | |
280 | ||
281 | memcpy(&size, sg[0].iov_base + offset, sizeof(size)); | |
282 | offset += sizeof(size); | |
283 | ||
284 | fprintf(llogfile, "size: %x\n", size); | |
285 | ||
286 | sg[0].iov_base += 11; /* skip header */ | |
287 | sg[0].iov_len -= 11; | |
288 | ||
289 | total = 0; | |
290 | for (i = 0; i < count; i++) { | |
291 | total += sg[i].iov_len; | |
292 | if (total >= size) { | |
293 | /* trim sg list so writev does the right thing */ | |
294 | sg[i].iov_len -= (total - size); | |
295 | i++; | |
296 | break; | |
297 | } | |
298 | } | |
299 | ||
300 | fprintf(llogfile, "%s={\"", name); | |
301 | fflush(llogfile); | |
302 | for (j = 0; j < i; j++) { | |
303 | if (j) { | |
304 | fprintf(llogfile, "\", \""); | |
305 | fflush(llogfile); | |
306 | } | |
307 | ||
308 | do { | |
309 | len = writev(fileno(llogfile), &sg[j], 1); | |
310 | } while (len == -1 && errno == EINTR); | |
311 | fprintf(llogfile, "len == %ld: %m\n", len); | |
312 | BUG_ON(len != sg[j].iov_len); | |
313 | } | |
314 | fprintf(llogfile, "\"}"); | |
315 | ||
316 | sg[0].iov_base -= 11; | |
317 | sg[0].iov_len += 11; | |
318 | ||
319 | } | |
320 | #endif | |
321 | ||
322 | void pprint_pdu(V9fsPDU *pdu) | |
323 | { | |
324 | size_t offset = 7; | |
325 | ||
326 | if (llogfile == NULL) { | |
327 | llogfile = fopen("/tmp/pdu.log", "w"); | |
328 | } | |
329 | ||
330 | switch (pdu->id) { | |
331 | case P9_TVERSION: | |
332 | fprintf(llogfile, "TVERSION: ("); | |
333 | pprint_int32(pdu, 0, &offset, "msize"); | |
334 | pprint_str(pdu, 0, &offset, ", version"); | |
335 | break; | |
336 | case P9_RVERSION: | |
337 | fprintf(llogfile, "RVERSION: ("); | |
338 | pprint_int32(pdu, 1, &offset, "msize"); | |
339 | pprint_str(pdu, 1, &offset, ", version"); | |
340 | break; | |
341 | case P9_TAUTH: | |
342 | fprintf(llogfile, "TAUTH: ("); | |
343 | pprint_int32(pdu, 0, &offset, "afid"); | |
344 | pprint_str(pdu, 0, &offset, ", uname"); | |
345 | pprint_str(pdu, 0, &offset, ", aname"); | |
346 | if (dotu) { | |
347 | pprint_int32(pdu, 0, &offset, ", n_uname"); | |
348 | } | |
349 | break; | |
350 | case P9_RAUTH: | |
351 | fprintf(llogfile, "RAUTH: ("); | |
352 | pprint_qid(pdu, 1, &offset, "qid"); | |
353 | break; | |
354 | case P9_TATTACH: | |
355 | fprintf(llogfile, "TATTACH: ("); | |
356 | pprint_int32(pdu, 0, &offset, "fid"); | |
357 | pprint_int32(pdu, 0, &offset, ", afid"); | |
358 | pprint_str(pdu, 0, &offset, ", uname"); | |
359 | pprint_str(pdu, 0, &offset, ", aname"); | |
360 | if (dotu) { | |
361 | pprint_int32(pdu, 0, &offset, ", n_uname"); | |
362 | } | |
363 | break; | |
364 | case P9_RATTACH: | |
365 | fprintf(llogfile, "RATTACH: ("); | |
366 | pprint_qid(pdu, 1, &offset, "qid"); | |
367 | break; | |
368 | case P9_TERROR: | |
369 | fprintf(llogfile, "TERROR: ("); | |
370 | break; | |
371 | case P9_RERROR: | |
372 | fprintf(llogfile, "RERROR: ("); | |
373 | pprint_str(pdu, 1, &offset, "ename"); | |
374 | if (dotu) { | |
375 | pprint_int32(pdu, 1, &offset, ", ecode"); | |
376 | } | |
377 | break; | |
378 | case P9_TFLUSH: | |
379 | fprintf(llogfile, "TFLUSH: ("); | |
380 | pprint_int16(pdu, 0, &offset, "oldtag"); | |
381 | break; | |
382 | case P9_RFLUSH: | |
383 | fprintf(llogfile, "RFLUSH: ("); | |
384 | break; | |
385 | case P9_TWALK: | |
386 | fprintf(llogfile, "TWALK: ("); | |
387 | pprint_int32(pdu, 0, &offset, "fid"); | |
388 | pprint_int32(pdu, 0, &offset, ", newfid"); | |
389 | pprint_strs(pdu, 0, &offset, ", wnames"); | |
390 | break; | |
391 | case P9_RWALK: | |
392 | fprintf(llogfile, "RWALK: ("); | |
393 | pprint_qids(pdu, 1, &offset, "wqids"); | |
394 | break; | |
395 | case P9_TOPEN: | |
396 | fprintf(llogfile, "TOPEN: ("); | |
397 | pprint_int32(pdu, 0, &offset, "fid"); | |
398 | pprint_int8(pdu, 0, &offset, ", mode"); | |
399 | break; | |
400 | case P9_ROPEN: | |
401 | fprintf(llogfile, "ROPEN: ("); | |
402 | pprint_qid(pdu, 1, &offset, "qid"); | |
403 | pprint_int32(pdu, 1, &offset, ", iounit"); | |
404 | break; | |
405 | case P9_TCREATE: | |
406 | fprintf(llogfile, "TCREATE: ("); | |
407 | pprint_int32(pdu, 0, &offset, "fid"); | |
408 | pprint_str(pdu, 0, &offset, ", name"); | |
409 | pprint_int32(pdu, 0, &offset, ", perm"); | |
410 | pprint_int8(pdu, 0, &offset, ", mode"); | |
411 | if (dotu) { | |
412 | pprint_str(pdu, 0, &offset, ", extension"); | |
413 | } | |
414 | break; | |
415 | case P9_RCREATE: | |
416 | fprintf(llogfile, "RCREATE: ("); | |
417 | pprint_qid(pdu, 1, &offset, "qid"); | |
418 | pprint_int32(pdu, 1, &offset, ", iounit"); | |
419 | break; | |
420 | case P9_TREAD: | |
421 | fprintf(llogfile, "TREAD: ("); | |
422 | pprint_int32(pdu, 0, &offset, "fid"); | |
423 | pprint_int64(pdu, 0, &offset, ", offset"); | |
424 | pprint_int32(pdu, 0, &offset, ", count"); | |
425 | pprint_sg(pdu, 0, &offset, ", sg"); | |
426 | break; | |
427 | case P9_RREAD: | |
428 | fprintf(llogfile, "RREAD: ("); | |
429 | pprint_int32(pdu, 1, &offset, "count"); | |
430 | pprint_sg(pdu, 1, &offset, ", sg"); | |
431 | offset = 7; | |
432 | #ifdef DEBUG_DATA | |
433 | pprint_data(pdu, 1, &offset, ", data"); | |
434 | #endif | |
435 | break; | |
436 | case P9_TWRITE: | |
437 | fprintf(llogfile, "TWRITE: ("); | |
438 | pprint_int32(pdu, 0, &offset, "fid"); | |
439 | pprint_int64(pdu, 0, &offset, ", offset"); | |
440 | pprint_int32(pdu, 0, &offset, ", count"); | |
441 | break; | |
442 | case P9_RWRITE: | |
443 | fprintf(llogfile, "RWRITE: ("); | |
444 | pprint_int32(pdu, 1, &offset, "count"); | |
445 | break; | |
446 | case P9_TCLUNK: | |
447 | fprintf(llogfile, "TCLUNK: ("); | |
448 | pprint_int32(pdu, 0, &offset, "fid"); | |
449 | break; | |
450 | case P9_RCLUNK: | |
451 | fprintf(llogfile, "RCLUNK: ("); | |
452 | break; | |
453 | case P9_TREMOVE: | |
454 | fprintf(llogfile, "TREMOVE: ("); | |
455 | pprint_int32(pdu, 0, &offset, "fid"); | |
456 | break; | |
457 | case P9_RREMOVE: | |
458 | fprintf(llogfile, "RREMOVE: ("); | |
459 | break; | |
460 | case P9_TSTAT: | |
461 | fprintf(llogfile, "TSTAT: ("); | |
462 | pprint_int32(pdu, 0, &offset, "fid"); | |
463 | break; | |
464 | case P9_RSTAT: | |
465 | fprintf(llogfile, "RSTAT: ("); | |
466 | offset += 2; /* ignored */ | |
467 | pprint_stat(pdu, 1, &offset, "stat"); | |
468 | break; | |
469 | case P9_TWSTAT: | |
470 | fprintf(llogfile, "TWSTAT: ("); | |
471 | pprint_int32(pdu, 0, &offset, "fid"); | |
472 | offset += 2; /* ignored */ | |
473 | pprint_stat(pdu, 0, &offset, ", stat"); | |
474 | break; | |
475 | case P9_RWSTAT: | |
476 | fprintf(llogfile, "RWSTAT: ("); | |
477 | break; | |
478 | default: | |
479 | fprintf(llogfile, "unknown(%d): (", pdu->id); | |
480 | break; | |
481 | } | |
482 | ||
483 | fprintf(llogfile, ")\n"); | |
484 | } |