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