1 /* 2 * Copyright (c) 2009, 2010 Jeff Mahoney <jeffm (at) 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 41 struct 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 85 static const struct xlat blkpg_ops[] = { 86 { BLKPG_ADD_PARTITION, "BLKPG_ADD_PARTITION", }, 87 { BLKPG_DEL_PARTITION, "BLKPG_DEL_PARTITION", }, 88 { 0, NULL }, 89 }; 90 91 static void 92 print_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 112 int 113 block_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