1 /*
2 * Copyright (c) 2009, 2010 Jeff Mahoney <jeffm@suse.com>
3 * Copyright (c) 2011-2016 Dmitry V. Levin <ldv@strace.io>
4 * Copyright (c) 2011-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11
12 #include DEF_MPERS_TYPE(struct_blk_user_trace_setup)
13 #include DEF_MPERS_TYPE(struct_blkpg_ioctl_arg)
14 #include DEF_MPERS_TYPE(struct_blkpg_partition)
15
16 #include <linux/ioctl.h>
17 #include <linux/fs.h>
18 #include <linux/blkpg.h>
19 #include <linux/blkzoned.h>
20 #include <linux/blktrace_api.h>
21
22 typedef struct blkpg_ioctl_arg struct_blkpg_ioctl_arg;
23 typedef struct blkpg_partition struct_blkpg_partition;
24 typedef struct blk_user_trace_setup struct_blk_user_trace_setup;
25
26 #include MPERS_DEFS
27
28 #include "xlat/blkpg_ops.h"
29
30 static void
31 print_blkpg_req(struct tcb *tcp, const struct_blkpg_ioctl_arg *blkpg)
32 {
33 struct_blkpg_partition p;
34
35 tprint_struct_begin();
36 PRINT_FIELD_XVAL(*blkpg, op, blkpg_ops, "BLKPG_???");
37 tprint_struct_next();
38 PRINT_FIELD_D(*blkpg, flags);
39 tprint_struct_next();
40 PRINT_FIELD_D(*blkpg, datalen);
41
42 tprint_struct_next();
43 tprints_field_name("data");
44 if (!umove_or_printaddr(tcp, ptr_to_kulong(blkpg->data), &p)) {
45 tprint_struct_begin();
46 PRINT_FIELD_D(p, start);
47 tprint_struct_next();
48 PRINT_FIELD_D(p, length);
49 tprint_struct_next();
50 PRINT_FIELD_D(p, pno);
51 tprint_struct_next();
52 PRINT_FIELD_CSTRING(p, devname);
53 tprint_struct_next();
54 PRINT_FIELD_CSTRING(p, volname);
55 tprint_struct_end();
56 }
57 tprint_struct_end();
58 }
59
60 MPERS_PRINTER_DECL(int, block_ioctl, struct tcb *const tcp,
61 const unsigned int code, const kernel_ulong_t arg)
62 {
63 switch (code) {
64 /* take arg as a value, not as a pointer */
65 case BLKRASET:
66 case BLKFRASET:
67 tprint_arg_next();
68 PRINT_VAL_U(arg);
69 break;
70
71 /* return an unsigned short */
72 case BLKSECTGET:
73 case BLKROTATIONAL:
74 if (entering(tcp))
75 return 0;
76 tprint_arg_next();
77 printnum_short(tcp, arg, "%hu");
78 break;
79
80 /* return a signed int */
81 case BLKROGET:
82 case BLKBSZGET:
83 case BLKSSZGET:
84 case BLKALIGNOFF:
85 if (entering(tcp))
86 return 0;
87 ATTRIBUTE_FALLTHROUGH;
88 /* take a signed int */
89 case BLKROSET:
90 case BLKBSZSET:
91 tprint_arg_next();
92 printnum_int(tcp, arg, "%d");
93 break;
94
95 /* return an unsigned int */
96 case BLKPBSZGET:
97 case BLKIOMIN:
98 case BLKIOOPT:
99 case BLKDISCARDZEROES:
100 case BLKGETZONESZ:
101 case BLKGETNRZONES:
102 if (entering(tcp))
103 return 0;
104 tprint_arg_next();
105 printnum_int(tcp, arg, "%u");
106 break;
107
108 /* return a signed long */
109 case BLKRAGET:
110 case BLKFRAGET:
111 if (entering(tcp))
112 return 0;
113 tprint_arg_next();
114 printnum_slong(tcp, arg);
115 break;
116
117 /* returns an unsigned long */
118 case BLKGETSIZE:
119 if (entering(tcp))
120 return 0;
121 tprint_arg_next();
122 printnum_ulong(tcp, arg);
123 break;
124
125 /* returns an uint64_t */
126 case BLKGETSIZE64:
127 case BLKGETDISKSEQ:
128 if (entering(tcp))
129 return 0;
130 tprint_arg_next();
131 printnum_int64(tcp, arg, "%" PRIu64);
132 break;
133
134 /* takes a pair of uint64_t */
135 case BLKDISCARD:
136 case BLKSECDISCARD:
137 case BLKZEROOUT:
138 tprint_arg_next();
139 printpair_int64(tcp, arg, "%" PRIu64);
140 break;
141
142 /* More complex types */
143 case BLKPG: {
144 struct_blkpg_ioctl_arg blkpg;
145
146 tprint_arg_next();
147 if (!umove_or_printaddr(tcp, arg, &blkpg))
148 print_blkpg_req(tcp, &blkpg);
149 break;
150 }
151
152 case BLKTRACESETUP:
153 if (entering(tcp)) {
154 struct_blk_user_trace_setup buts;
155
156 tprint_arg_next();
157 if (umove_or_printaddr(tcp, arg, &buts))
158 break;
159 tprint_struct_begin();
160 PRINT_FIELD_U(buts, act_mask);
161 tprint_struct_next();
162 PRINT_FIELD_U(buts, buf_size);
163 tprint_struct_next();
164 PRINT_FIELD_U(buts, buf_nr);
165 tprint_struct_next();
166 PRINT_FIELD_U(buts, start_lba);
167 tprint_struct_next();
168 PRINT_FIELD_U(buts, end_lba);
169 tprint_struct_next();
170 PRINT_FIELD_TGID(buts, pid, tcp);
171 return 0;
172 } else {
173 struct_blk_user_trace_setup buts;
174
175 if (!syserror(tcp) && !umove(tcp, arg, &buts)) {
176 tprint_struct_next();
177 PRINT_FIELD_CSTRING(buts, name);
178 }
179 tprint_struct_end();
180 break;
181 }
182
183 /* No arguments */
184 case BLKRRPART:
185 case BLKFLSBUF:
186 case BLKTRACESTART:
187 case BLKTRACESTOP:
188 case BLKTRACETEARDOWN:
189 break;
190 default:
191 return RVAL_DECODED;
192 }
193
194 return RVAL_IOCTL_DECODED;
195 }