block.c revision ed720fda5d515f1359fcd3242223e553d1216789
1/*
2 * Copyright (c) 2009, 2010 Jeff Mahoney <jeffm@suse.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "defs.h"
29#include <stdint.h>
30#include <inttypes.h>
31#include <linux/blkpg.h>
32#include <linux/fs.h>
33#include <linux/hdreg.h>
34
35/* ioctls <= 114 are present in Linux 2.4. The following ones have been
36 * added since then and headers containing them may not be available on
37 * every system. */
38
39#define BLKTRACE_BDEV_SIZE      32
40struct blk_user_trace_setup {
41	char name[BLKTRACE_BDEV_SIZE];	/* output */
42	uint16_t act_mask;		/* input */
43	uint32_t buf_size;		/* input */
44	uint32_t buf_nr;		/* input */
45	uint64_t start_lba;
46	uint64_t end_lba;
47	uint32_t pid;
48};
49
50#ifndef BLKTRACESETUP
51#define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup)
52#endif
53#ifndef BLKTRACESTART
54#define BLKTRACESTART _IO(0x12,116)
55#endif
56#ifndef BLKTRACESTOP
57#define BLKTRACESTOP _IO(0x12,117)
58#endif
59#ifndef BLKTRACETEARDOWN
60#define BLKTRACETEARDOWN _IO(0x12,118)
61#endif
62#ifndef BLKDISCARD
63#define BLKDISCARD _IO(0x12,119)
64#endif
65#ifndef BLKIOMIN
66#define BLKIOMIN _IO(0x12,120)
67#endif
68#ifndef BLKIOOPT
69#define BLKIOOPT _IO(0x12,121)
70#endif
71#ifndef BLKALIGNOFF
72#define BLKALIGNOFF _IO(0x12,122)
73#endif
74#ifndef BLKPBSZGET
75#define BLKPBSZGET _IO(0x12,123)
76#endif
77#ifndef BLKDISCARDZEROES
78#define BLKDISCARDZEROES _IO(0x12,124)
79#endif
80#ifndef BLKSECDISCARD
81#define BLKSECDISCARD _IO(0x12,125)
82#endif
83
84static const struct xlat blkpg_ops[] = {
85	{ BLKPG_ADD_PARTITION,	"BLKPG_ADD_PARTITION", },
86	{ BLKPG_DEL_PARTITION,	"BLKPG_DEL_PARTITION", },
87	{ 0,			NULL },
88};
89
90static void
91print_blkpg_req(struct tcb *tcp, struct blkpg_ioctl_arg *blkpg)
92{
93	struct blkpg_partition p;
94
95	tprints("{");
96	printxval(blkpg_ops, blkpg->op, "BLKPG_???");
97
98	tprintf(", flags=%d, datalen=%d, ",
99		blkpg->flags, blkpg->datalen);
100
101	if (umove(tcp, (long) blkpg->data, &p) < 0)
102		tprintf("%#lx}", (long) blkpg->data);
103	else
104		tprintf("{start=%lld, length=%lld, pno=%d, "
105			"devname=\"%.*s\", volname=\"%.*s\"}}",
106			p.start, p.length, p.pno,
107			(int) sizeof(p.devname), p.devname,
108			(int) sizeof(p.volname), p.volname);
109}
110
111int
112block_ioctl(struct tcb *tcp, long code, long arg)
113{
114	switch (code) {
115	/* take arg as a value, not as a pointer */
116	case BLKRASET:
117	case BLKFRASET:
118		if (entering(tcp))
119			tprintf(", %ld", arg);
120		break;
121
122	/* take a signed int */
123	case BLKROSET:
124	case BLKBSZSET:
125		if (entering(tcp)) {
126			int val;
127			if (umove(tcp, arg, &val) < 0)
128				tprintf(", %#lx", arg);
129			else
130				tprintf(", %d", val);
131		}
132		break;
133
134	/* returns an unsigned short */
135	case BLKSECTGET:
136		if (exiting(tcp)) {
137			unsigned short val;
138			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
139				tprintf(", %#lx", arg);
140			else
141				tprintf(", %hu", val);
142		}
143		break;
144
145	/* return a signed int */
146	case BLKROGET:
147	case BLKBSZGET:
148	case BLKSSZGET:
149	case BLKALIGNOFF:
150		if (exiting(tcp)) {
151			int val;
152			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
153				tprintf(", %#lx", arg);
154			else
155				tprintf(", %d", val);
156		}
157		break;
158
159	/* return an unsigned int */
160	case BLKPBSZGET:
161	case BLKIOMIN:
162	case BLKIOOPT:
163	case BLKDISCARDZEROES:
164		if (exiting(tcp)) {
165			unsigned int val;
166			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
167				tprintf(", %#lx", arg);
168			else
169				tprintf(", %u", val);
170		}
171		break;
172
173	/* return a signed long */
174	case BLKRAGET:
175	case BLKFRAGET:
176		if (exiting(tcp)) {
177			long val;
178			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
179				tprintf(", %#lx", arg);
180			else
181				tprintf(", %ld", val);
182		}
183		break;
184
185	/* returns an unsigned long */
186	case BLKGETSIZE:
187		if (exiting(tcp)) {
188			unsigned long val;
189			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
190				tprintf(", %#lx", arg);
191			else
192				tprintf(", %lu", val);
193			}
194		break;
195
196#ifdef HAVE_BLKGETSIZE64
197	/* return an uint64_t */
198	case BLKGETSIZE64:
199		if (exiting(tcp)) {
200			uint64_t val;
201			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
202				tprintf(", %#lx", arg);
203			else
204				tprintf(", %" PRIu64, val);
205		}
206		break;
207#endif
208
209	/* More complex types */
210	case BLKDISCARD:
211	case BLKSECDISCARD:
212		if (entering(tcp)) {
213			uint64_t range[2];
214			if (umove(tcp, arg, range) < 0)
215				tprintf(", %#lx", arg);
216			else
217				tprintf(", {%" PRIx64 ", %" PRIx64 "}",
218					range[0], range[1]);
219		}
220		break;
221
222	case HDIO_GETGEO:
223		if (exiting(tcp)) {
224			struct hd_geometry geo;
225			if (syserror(tcp) || umove(tcp, arg, &geo) < 0)
226				tprintf(", %#lx", arg);
227			else
228				tprintf(", {heads=%hhu, sectors=%hhu, "
229					"cylinders=%hu, start=%lu}",
230					geo.heads, geo.sectors,
231					geo.cylinders, geo.start);
232		}
233		break;
234
235	case BLKPG:
236		if (entering(tcp)) {
237			struct blkpg_ioctl_arg blkpg;
238			if (umove(tcp, arg, &blkpg) < 0)
239				tprintf(", %#lx", arg);
240			else {
241				tprints(", ");
242				print_blkpg_req(tcp, &blkpg);
243			}
244		}
245		break;
246
247	case BLKTRACESETUP:
248		if (entering(tcp)) {
249			struct blk_user_trace_setup buts;
250			if (umove(tcp, arg, &buts) < 0)
251				tprintf(", %#lx", arg);
252			else
253				tprintf(", {act_mask=%hu, buf_size=%u, "
254					"buf_nr=%u, start_lba=%" PRIu64 ", "
255					"end_lba=%" PRIu64 ", pid=%u}",
256					buts.act_mask, buts.buf_size,
257					buts.buf_nr, buts.start_lba,
258					buts.end_lba, buts.pid);
259		}
260		if (exiting(tcp)) {
261			struct blk_user_trace_setup buts;
262			if (syserror(tcp) || umove(tcp, arg, &buts) < 0)
263				tprintf(", %#lx", arg);
264			else
265				tprintf(", {name=\"%.*s\"}",
266					(int) sizeof(buts.name), buts.name);
267		}
268		break;
269
270	/* No arguments or unhandled */
271	case BLKTRACESTART:
272	case BLKTRACESTOP:
273	case BLKTRACETEARDOWN:
274	case BLKFLSBUF: /* Requires driver knowlege */
275	case BLKRRPART: /* No args */
276	default:
277		if (entering(tcp))
278			tprintf(", %#lx", arg);
279		break;
280
281	};
282	return 1;
283}
284