block.c revision be284cae112d71a0073e24b34e16a63f31b32fd8
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#ifdef LINUX
30#include <stdint.h>
31#include <inttypes.h>
32#include <linux/blkpg.h>
33#include <linux/fs.h>
34#include <linux/hdreg.h>
35
36/* ioctls <= 114 are present in Linux 2.4. The following ones have been
37 * added since then and headers containing them may not be available on
38 * every system. */
39
40#define BLKTRACE_BDEV_SIZE      32
41struct blk_user_trace_setup {
42	char name[BLKTRACE_BDEV_SIZE];	/* output */
43	uint16_t act_mask;		/* input */
44	uint32_t buf_size;		/* input */
45	uint32_t buf_nr;		/* input */
46	uint64_t start_lba;
47	uint64_t end_lba;
48	uint32_t pid;
49};
50
51#ifndef BLKTRACESETUP
52#define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup)
53#endif
54#ifndef BLKTRACESTART
55#define BLKTRACESTART _IO(0x12,116)
56#endif
57#ifndef BLKTRACESTART
58#define BLKTRACESTOP _IO(0x12,117)
59#endif
60#ifndef BLKTRACETEARDOWN
61#define BLKTRACETEARDOWN _IO(0x12,118)
62#endif
63#ifndef BLKDISCARD
64#define BLKDISCARD _IO(0x12,119)
65#endif
66#ifndef BLKIOMIN
67#define BLKIOMIN _IO(0x12,120)
68#endif
69#ifndef BLKIOOPT
70#define BLKIOOPT _IO(0x12,121)
71#endif
72#ifndef BLKALIGNOFF
73#define BLKALIGNOFF _IO(0x12,122)
74#endif
75#ifndef BLKPBSZGET
76#define BLKPBSZGET _IO(0x12,123)
77#endif
78#ifndef BLKDISCARDZEROES
79#define BLKDISCARDZEROES _IO(0x12,124)
80#endif
81#ifndef BLKSECDISCARD
82#define BLKSECDISCARD _IO(0x12,125)
83#endif
84
85static const struct xlat blkpg_ops[] = {
86	{ BLKPG_ADD_PARTITION,	"BLKPG_ADD_PARTITION", },
87	{ BLKPG_DEL_PARTITION,	"BLKPG_DEL_PARTITION", },
88	{ 0,			NULL },
89};
90
91static void
92print_blkpg_req(struct tcb *tcp, struct blkpg_ioctl_arg *blkpg)
93{
94	struct blkpg_partition p;
95
96	tprintf("{");
97	printxval(blkpg_ops, blkpg->op, "BLKPG_???");
98
99	tprintf(", flags=%d, datalen=%d, ",
100		blkpg->flags, blkpg->datalen);
101
102	if (umove(tcp, (long) blkpg->data, &p) < 0)
103		tprintf("%#lx}", (long) blkpg->data);
104	else
105		tprintf("{start=%lld, length=%lld, pno=%d, "
106			"devname=\"%.*s\", volname=\"%.*s\"}}",
107			p.start, p.length, p.pno,
108			(int) sizeof(p.devname), p.devname,
109			(int) sizeof(p.volname), p.volname);
110}
111
112int
113block_ioctl(struct tcb *tcp, long code, long arg)
114{
115	switch (code) {
116	/* take arg as a value, not as a pointer */
117	case BLKRASET:
118	case BLKFRASET:
119		if (entering(tcp))
120			tprintf(", %ld", arg);
121		break;
122
123	/* take a signed int */
124	case BLKROSET:
125	case BLKBSZSET:
126		if (entering(tcp)) {
127			int val;
128			if (umove(tcp, arg, &val) < 0)
129				tprintf(", %#lx", arg);
130			else
131				tprintf(", %d", val);
132		}
133		break;
134
135	/* returns an unsigned short */
136	case BLKSECTGET:
137		if (exiting(tcp)) {
138			unsigned short val;
139			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
140				tprintf(", %#lx", arg);
141			else
142				tprintf(", %hu", val);
143		}
144		break;
145
146	/* return a signed int */
147	case BLKROGET:
148	case BLKBSZGET:
149	case BLKSSZGET:
150	case BLKALIGNOFF:
151		if (exiting(tcp)) {
152			int val;
153			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
154				tprintf(", %#lx", arg);
155			else
156				tprintf(", %d", val);
157		}
158		break;
159
160	/* return an unsigned int */
161	case BLKPBSZGET:
162	case BLKIOMIN:
163	case BLKIOOPT:
164	case BLKDISCARDZEROES:
165		if (exiting(tcp)) {
166			unsigned int val;
167			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
168				tprintf(", %#lx", arg);
169			else
170				tprintf(", %u", val);
171		}
172		break;
173
174	/* return a signed long */
175	case BLKRAGET:
176	case BLKFRAGET:
177		if (exiting(tcp)) {
178			long val;
179			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
180				tprintf(", %#lx", arg);
181			else
182				tprintf(", %ld", val);
183		}
184		break;
185
186	/* returns an unsigned long */
187	case BLKGETSIZE:
188		if (exiting(tcp)) {
189			unsigned long val;
190			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
191				tprintf(", %#lx", arg);
192			else
193				tprintf(", %lu", val);
194			}
195		break;
196
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
208	/* More complex types */
209	case BLKDISCARD:
210	case BLKSECDISCARD:
211		if (entering(tcp)) {
212			uint64_t range[2];
213			if (umove(tcp, arg, range) < 0)
214				tprintf(", %#lx", arg);
215			else
216				tprintf(", {%" PRIx64 ", %" PRIx64 "}",
217					range[0], range[1]);
218		}
219		break;
220
221	case HDIO_GETGEO:
222		if (exiting(tcp)) {
223			struct hd_geometry geo;
224			if (syserror(tcp) || umove(tcp, arg, &geo) < 0)
225				tprintf(", %#lx", arg);
226			else
227				tprintf(", {heads=%hhu, sectors=%hhu, "
228					"cylinders=%hu, start=%lu}",
229					geo.heads, geo.sectors,
230					geo.cylinders, geo.start);
231		}
232		break;
233
234	case BLKPG:
235		if (entering(tcp)) {
236			struct blkpg_ioctl_arg blkpg;
237			if (umove(tcp, arg, &blkpg) < 0)
238				tprintf(", %#lx", arg);
239			else {
240				tprintf(", ");
241				print_blkpg_req(tcp, &blkpg);
242			}
243		}
244		break;
245
246	case BLKTRACESETUP:
247		if (entering(tcp)) {
248			struct blk_user_trace_setup buts;
249			if (umove(tcp, arg, &buts) < 0)
250				tprintf(", %#lx", arg);
251			else
252				tprintf(", {act_mask=%hu, buf_size=%u, "
253					"buf_nr=%u, start_lba=%" PRIu64 ", "
254					"end_lba=%" PRIu64 ", pid=%u}",
255					buts.act_mask, buts.buf_size,
256					buts.buf_nr, buts.start_lba,
257					buts.end_lba, buts.pid);
258		}
259		if (exiting(tcp)) {
260			struct blk_user_trace_setup buts;
261			if (syserror(tcp) || umove(tcp, arg, &buts) < 0)
262				tprintf(", %#lx", arg);
263			else
264				tprintf(", {name=\"%.*s\"}",
265					(int) sizeof(buts.name), buts.name);
266		}
267		break;
268
269	/* No arguments or unhandled */
270	case BLKTRACESTART:
271	case BLKTRACESTOP:
272	case BLKTRACETEARDOWN:
273	case BLKFLSBUF: /* Requires driver knowlege */
274	case BLKRRPART: /* No args */
275	default:
276		if (entering(tcp))
277			tprintf(", %#lx", arg);
278		break;
279
280	};
281	return 1;
282}
283#endif /* LINUX */
284