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