blob: fc151220f479a22729536373db369b792fe28377 [file] [log] [blame]
Dmitry V. Levin4ef6db42011-01-15 20:15:31 +00001/*
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 <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 BLKTRACESTART
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 const char *ioctl_name;
95
96 ioctl_name = xlookup(blkpg_ops, blkpg->op);
97 if (!ioctl_name) {
98 tprintf("{%#x, /* BLKPG_??? */", blkpg->op);
99 return;
100 }
101
102 tprintf("{%s, flags=%d, datalen=%d, ",
103 ioctl_name, blkpg->flags, blkpg->datalen);
104
105 if (umove(tcp, (unsigned long)blkpg->data, &p) < 0) {
106 tprintf("%#lx", (unsigned long)blkpg->data);
107 return;
108 }
109
110 tprintf("{start=%lld, length=%lld, pno=%d, ",
111 p.start, p.length, p.pno);
112
113 tprintf("devname=\"%s\", volname=\"%s\"}",
114 p.devname, p.volname);
115}
116
117int
118block_ioctl(struct tcb *tcp, long code, long arg)
119{
120 switch (code) {
121
122 /* These pass arg as a value, not a pointer */
123 case BLKRASET:
124 case BLKFRASET:
125 if (entering(tcp))
126 tprintf(", %ld", arg);
127 break;
128
129 /* Just pass in a signed int */
130 case BLKROSET:
131 case BLKBSZSET:
132 if (entering(tcp)) {
133 int int_val;
134 if (umove(tcp, arg, &int_val) < 0)
135 tprintf(", %#lx", arg);
136 else
137 tprintf(", %d", int_val);
138 }
139 break;
140
141 /* Just return an unsigned short */
142 case BLKSECTGET:
143 if (exiting(tcp)) {
144 unsigned short ushort_val;
145 if (umove(tcp, arg, &ushort_val) < 0)
146 tprintf(", %#lx", arg);
147 else
148 tprintf(", %hu", ushort_val);
149 }
150 break;
151
152 /* Just return a signed int */
153 case BLKROGET:
154 case BLKBSZGET:
155 case BLKSSZGET:
156 case BLKALIGNOFF:
157 if (exiting(tcp)) {
158 int int_val;
159 if (umove(tcp, arg, &int_val) < 0)
160 tprintf(", %#lx", arg);
161 else
162 tprintf(", %d", int_val);
163 }
164 break;
165
166 /* Just return an unsigned int */
167 case BLKPBSZGET:
168 case BLKIOMIN:
169 case BLKIOOPT:
170 case BLKDISCARDZEROES:
171 if (exiting(tcp)) {
172 unsigned int uint_val;
173 if (umove(tcp, arg, &uint_val) < 0)
174 tprintf(", %#lx", arg);
175 else
176 tprintf(", %u", uint_val);
177 }
178 break;
179
180 /* Just return a signed long */
181 case BLKRAGET:
182 case BLKFRAGET:
183 if (exiting(tcp)) {
184 long size;
185 if (umove(tcp, arg, &size) < 0)
186 tprintf(", %#lx", arg);
187 else
188 tprintf(", %ld", size);
189 }
190 break;
191
192 /* Just return an unsigned long */
193 case BLKGETSIZE:
194 if (exiting(tcp)) {
195 unsigned long ulong_val;
196 if (umove(tcp, arg, &ulong_val) < 0)
197 tprintf(", %#lx", arg);
198 else
199 tprintf(", %lu", ulong_val);
200 }
201 break;
202
203 /* Just return a quad */
204 case BLKGETSIZE64:
205 if (exiting(tcp)) {
206 uint64_t uint64_val;
207 if (umove(tcp, arg, &uint64_val) < 0)
208 tprintf(", %#lx", arg);
209 else
210 tprintf(", %llu",
211 (unsigned long long)uint64_val);
212 }
213 break;
214
215 /* More complex types */
216 case BLKDISCARD:
217 case BLKSECDISCARD:
218 if (entering(tcp)) {
219 uint64_t range[2];
220 if (umove(tcp, arg, range) < 0)
221 tprintf(", %#lx", arg);
222 else
223 tprintf(", {%llx, %llx}",
224 (unsigned long long)range[0],
225 (unsigned long long)range[1]);
226 }
227 break;
228
229 case HDIO_GETGEO:
230 if (exiting(tcp)) {
231 struct hd_geometry geo;
232 if (umove(tcp, arg, &geo) < 0)
233 tprintf(", %#lx", arg);
234 else
235 tprintf(", {heads=%hhu, sectors=%hhu, "
236 "cylinders=%hu, start=%lu}",
237 geo.heads, geo.sectors,
238 geo.cylinders, geo.start);
239 }
240 break;
241 case BLKPG:
242 if (entering(tcp)) {
243 struct blkpg_ioctl_arg blkpg;
244 if (umove(tcp, arg, &blkpg) < 0)
245 tprintf(", %#lx", arg);
246 else {
247 tprintf(", ");
248 print_blkpg_req(tcp, &blkpg);
249 }
250 }
251 if (exiting(tcp)) {
252 tprintf("}");
253 }
254 break;
255 case BLKTRACESETUP:
256 if (entering(tcp)) {
257 struct blk_user_trace_setup buts;
258 if (umove(tcp, arg, &buts) < 0)
259 tprintf(", %#lx", arg);
260 else {
261 tprintf(", {act_mask=%hu, buf_size=%u, ",
262 buts.act_mask, buts.buf_size);
263 tprintf("buf_nr=%u, start_lba=%llu, ",
264 buts.buf_nr,
265 (unsigned long long)buts.start_lba);
266 tprintf("end_lba=%llu, pid=%u}",
267 (unsigned long long)buts.end_lba,
268 buts.pid);
269 }
270 }
271 if (exiting(tcp)) {
272 struct blk_user_trace_setup buts;
273 if (umove(tcp, arg, &buts) < 0)
274 tprintf(", %#lx", arg);
275 else
276 tprintf(", {name=\"%s\"}", buts.name);
277 }
278 break;
279 /* No arguments or unhandled */
280 case BLKTRACESTART:
281 case BLKTRACESTOP:
282 case BLKTRACETEARDOWN:
283 case BLKFLSBUF: /* Requires driver knowlege */
284 case BLKRRPART: /* No args */
285 default:
286 if (entering(tcp))
287 tprintf(", %#lx", arg);
288 break;
289
290 };
291 return 1;
292}
293#endif /* LINUX */