root / hw / virtio-9p-debug.c @ c18e2f94
History | View | Annotate | Download (13.5 kB)
1 |
/*
|
---|---|
2 |
* Virtio 9p PDU debug
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2010
|
5 |
*
|
6 |
* Authors:
|
7 |
* Anthony Liguori <aliguori@us.ibm.com>
|
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 |
BUG_ON(!llogfile); |
331 |
|
332 |
switch (pdu->id) {
|
333 |
case P9_TREADDIR:
|
334 |
fprintf(llogfile, "TREADDIR: (");
|
335 |
pprint_int32(pdu, 0, &offset, "fid"); |
336 |
pprint_int64(pdu, 0, &offset, ", initial offset"); |
337 |
pprint_int32(pdu, 0, &offset, ", max count"); |
338 |
break;
|
339 |
case P9_RREADDIR:
|
340 |
fprintf(llogfile, "RREADDIR: (");
|
341 |
pprint_int32(pdu, 1, &offset, "count"); |
342 |
#ifdef DEBUG_DATA
|
343 |
pprint_data(pdu, 1, &offset, ", data"); |
344 |
#endif
|
345 |
break;
|
346 |
case P9_TVERSION:
|
347 |
fprintf(llogfile, "TVERSION: (");
|
348 |
pprint_int32(pdu, 0, &offset, "msize"); |
349 |
pprint_str(pdu, 0, &offset, ", version"); |
350 |
break;
|
351 |
case P9_RVERSION:
|
352 |
fprintf(llogfile, "RVERSION: (");
|
353 |
pprint_int32(pdu, 1, &offset, "msize"); |
354 |
pprint_str(pdu, 1, &offset, ", version"); |
355 |
break;
|
356 |
case P9_TAUTH:
|
357 |
fprintf(llogfile, "TAUTH: (");
|
358 |
pprint_int32(pdu, 0, &offset, "afid"); |
359 |
pprint_str(pdu, 0, &offset, ", uname"); |
360 |
pprint_str(pdu, 0, &offset, ", aname"); |
361 |
if (dotu) {
|
362 |
pprint_int32(pdu, 0, &offset, ", n_uname"); |
363 |
} |
364 |
break;
|
365 |
case P9_RAUTH:
|
366 |
fprintf(llogfile, "RAUTH: (");
|
367 |
pprint_qid(pdu, 1, &offset, "qid"); |
368 |
break;
|
369 |
case P9_TATTACH:
|
370 |
fprintf(llogfile, "TATTACH: (");
|
371 |
pprint_int32(pdu, 0, &offset, "fid"); |
372 |
pprint_int32(pdu, 0, &offset, ", afid"); |
373 |
pprint_str(pdu, 0, &offset, ", uname"); |
374 |
pprint_str(pdu, 0, &offset, ", aname"); |
375 |
if (dotu) {
|
376 |
pprint_int32(pdu, 0, &offset, ", n_uname"); |
377 |
} |
378 |
break;
|
379 |
case P9_RATTACH:
|
380 |
fprintf(llogfile, "RATTACH: (");
|
381 |
pprint_qid(pdu, 1, &offset, "qid"); |
382 |
break;
|
383 |
case P9_TERROR:
|
384 |
fprintf(llogfile, "TERROR: (");
|
385 |
break;
|
386 |
case P9_RERROR:
|
387 |
fprintf(llogfile, "RERROR: (");
|
388 |
pprint_str(pdu, 1, &offset, "ename"); |
389 |
if (dotu) {
|
390 |
pprint_int32(pdu, 1, &offset, ", ecode"); |
391 |
} |
392 |
break;
|
393 |
case P9_TFLUSH:
|
394 |
fprintf(llogfile, "TFLUSH: (");
|
395 |
pprint_int16(pdu, 0, &offset, "oldtag"); |
396 |
break;
|
397 |
case P9_RFLUSH:
|
398 |
fprintf(llogfile, "RFLUSH: (");
|
399 |
break;
|
400 |
case P9_TWALK:
|
401 |
fprintf(llogfile, "TWALK: (");
|
402 |
pprint_int32(pdu, 0, &offset, "fid"); |
403 |
pprint_int32(pdu, 0, &offset, ", newfid"); |
404 |
pprint_strs(pdu, 0, &offset, ", wnames"); |
405 |
break;
|
406 |
case P9_RWALK:
|
407 |
fprintf(llogfile, "RWALK: (");
|
408 |
pprint_qids(pdu, 1, &offset, "wqids"); |
409 |
break;
|
410 |
case P9_TOPEN:
|
411 |
fprintf(llogfile, "TOPEN: (");
|
412 |
pprint_int32(pdu, 0, &offset, "fid"); |
413 |
pprint_int8(pdu, 0, &offset, ", mode"); |
414 |
break;
|
415 |
case P9_ROPEN:
|
416 |
fprintf(llogfile, "ROPEN: (");
|
417 |
pprint_qid(pdu, 1, &offset, "qid"); |
418 |
pprint_int32(pdu, 1, &offset, ", iounit"); |
419 |
break;
|
420 |
case P9_TCREATE:
|
421 |
fprintf(llogfile, "TCREATE: (");
|
422 |
pprint_int32(pdu, 0, &offset, "fid"); |
423 |
pprint_str(pdu, 0, &offset, ", name"); |
424 |
pprint_int32(pdu, 0, &offset, ", perm"); |
425 |
pprint_int8(pdu, 0, &offset, ", mode"); |
426 |
if (dotu) {
|
427 |
pprint_str(pdu, 0, &offset, ", extension"); |
428 |
} |
429 |
break;
|
430 |
case P9_RCREATE:
|
431 |
fprintf(llogfile, "RCREATE: (");
|
432 |
pprint_qid(pdu, 1, &offset, "qid"); |
433 |
pprint_int32(pdu, 1, &offset, ", iounit"); |
434 |
break;
|
435 |
case P9_TREAD:
|
436 |
fprintf(llogfile, "TREAD: (");
|
437 |
pprint_int32(pdu, 0, &offset, "fid"); |
438 |
pprint_int64(pdu, 0, &offset, ", offset"); |
439 |
pprint_int32(pdu, 0, &offset, ", count"); |
440 |
pprint_sg(pdu, 0, &offset, ", sg"); |
441 |
break;
|
442 |
case P9_RREAD:
|
443 |
fprintf(llogfile, "RREAD: (");
|
444 |
pprint_int32(pdu, 1, &offset, "count"); |
445 |
pprint_sg(pdu, 1, &offset, ", sg"); |
446 |
offset = 7;
|
447 |
#ifdef DEBUG_DATA
|
448 |
pprint_data(pdu, 1, &offset, ", data"); |
449 |
#endif
|
450 |
break;
|
451 |
case P9_TWRITE:
|
452 |
fprintf(llogfile, "TWRITE: (");
|
453 |
pprint_int32(pdu, 0, &offset, "fid"); |
454 |
pprint_int64(pdu, 0, &offset, ", offset"); |
455 |
pprint_int32(pdu, 0, &offset, ", count"); |
456 |
break;
|
457 |
case P9_RWRITE:
|
458 |
fprintf(llogfile, "RWRITE: (");
|
459 |
pprint_int32(pdu, 1, &offset, "count"); |
460 |
break;
|
461 |
case P9_TCLUNK:
|
462 |
fprintf(llogfile, "TCLUNK: (");
|
463 |
pprint_int32(pdu, 0, &offset, "fid"); |
464 |
break;
|
465 |
case P9_RCLUNK:
|
466 |
fprintf(llogfile, "RCLUNK: (");
|
467 |
break;
|
468 |
case P9_TREMOVE:
|
469 |
fprintf(llogfile, "TREMOVE: (");
|
470 |
pprint_int32(pdu, 0, &offset, "fid"); |
471 |
break;
|
472 |
case P9_RREMOVE:
|
473 |
fprintf(llogfile, "RREMOVE: (");
|
474 |
break;
|
475 |
case P9_TSTAT:
|
476 |
fprintf(llogfile, "TSTAT: (");
|
477 |
pprint_int32(pdu, 0, &offset, "fid"); |
478 |
break;
|
479 |
case P9_RSTAT:
|
480 |
fprintf(llogfile, "RSTAT: (");
|
481 |
offset += 2; /* ignored */ |
482 |
pprint_stat(pdu, 1, &offset, "stat"); |
483 |
break;
|
484 |
case P9_TWSTAT:
|
485 |
fprintf(llogfile, "TWSTAT: (");
|
486 |
pprint_int32(pdu, 0, &offset, "fid"); |
487 |
offset += 2; /* ignored */ |
488 |
pprint_stat(pdu, 0, &offset, ", stat"); |
489 |
break;
|
490 |
case P9_RWSTAT:
|
491 |
fprintf(llogfile, "RWSTAT: (");
|
492 |
break;
|
493 |
default:
|
494 |
fprintf(llogfile, "unknown(%d): (", pdu->id);
|
495 |
break;
|
496 |
} |
497 |
|
498 |
fprintf(llogfile, ")\n");
|
499 |
/* Flush the log message out */
|
500 |
fflush(llogfile); |
501 |
} |