compat_ioctl: move hdio calls to block/compat_ioctl.c
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / block / compat_ioctl.c
CommitLineData
f58c4c0a
AB
1#include <linux/blkdev.h>
2#include <linux/blkpg.h>
3#include <linux/blktrace_api.h>
4#include <linux/cdrom.h>
5#include <linux/compat.h>
6#include <linux/elevator.h>
7#include <linux/fd.h>
8#include <linux/hdreg.h>
9#include <linux/syscalls.h>
10#include <linux/smp_lock.h>
11#include <linux/types.h>
12#include <linux/uaccess.h>
13
14static int compat_put_ushort(unsigned long arg, unsigned short val)
15{
16 return put_user(val, (unsigned short __user *)compat_ptr(arg));
17}
18
19static int compat_put_int(unsigned long arg, int val)
20{
21 return put_user(val, (compat_int_t __user *)compat_ptr(arg));
22}
23
24static int compat_put_long(unsigned long arg, long val)
25{
26 return put_user(val, (compat_long_t __user *)compat_ptr(arg));
27}
28
29static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
30{
31 return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
32}
33
34static int compat_put_u64(unsigned long arg, u64 val)
35{
36 return put_user(val, (compat_u64 __user *)compat_ptr(arg));
37}
38
9617db08
AB
39struct compat_hd_geometry {
40 unsigned char heads;
41 unsigned char sectors;
42 unsigned short cylinders;
43 u32 start;
44};
45
46static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
47 struct compat_hd_geometry __user *ugeo)
48{
49 struct hd_geometry geo;
50 int ret;
51
52 if (!ugeo)
53 return -EINVAL;
54 if (!disk->fops->getgeo)
55 return -ENOTTY;
56
57 /*
58 * We need to set the startsect first, the driver may
59 * want to override it.
60 */
61 geo.start = get_start_sect(bdev);
62 ret = disk->fops->getgeo(bdev, &geo);
63 if (ret)
64 return ret;
65
66 ret = copy_to_user(ugeo, &geo, 4);
67 ret |= __put_user(geo.start, &ugeo->start);
68 if (ret)
69 ret = -EFAULT;
70
71 return ret;
72}
73
74static int compat_hdio_ioctl(struct inode *inode, struct file *file,
75 struct gendisk *disk, unsigned int cmd, unsigned long arg)
76{
77 mm_segment_t old_fs = get_fs();
78 unsigned long kval;
79 unsigned int __user *uvp;
80 int error;
81
82 set_fs(KERNEL_DS);
83 error = blkdev_driver_ioctl(inode, file, disk,
84 cmd, (unsigned long)(&kval));
85 set_fs(old_fs);
86
87 if (error == 0) {
88 uvp = compat_ptr(arg);
89 if (put_user(kval, uvp))
90 error = -EFAULT;
91 }
92 return error;
93}
94
f58c4c0a
AB
95#define BLKBSZGET_32 _IOR(0x12, 112, int)
96#define BLKBSZSET_32 _IOW(0x12, 113, int)
97#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
98
171044d4
AB
99struct compat_blk_user_trace_setup {
100 char name[32];
101 u16 act_mask;
102 u32 buf_size;
103 u32 buf_nr;
104 compat_u64 start_lba;
105 compat_u64 end_lba;
106 u32 pid;
107};
108#define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
109
110static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
111{
112 struct blk_user_trace_setup buts;
113 struct compat_blk_user_trace_setup cbuts;
114 struct request_queue *q;
115 int ret;
116
117 q = bdev_get_queue(bdev);
118 if (!q)
119 return -ENXIO;
120
121 if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
122 return -EFAULT;
123
124 buts = (struct blk_user_trace_setup) {
125 .act_mask = cbuts.act_mask,
126 .buf_size = cbuts.buf_size,
127 .buf_nr = cbuts.buf_nr,
128 .start_lba = cbuts.start_lba,
129 .end_lba = cbuts.end_lba,
130 .pid = cbuts.pid,
131 };
132 memcpy(&buts.name, &cbuts.name, 32);
133
134 mutex_lock(&bdev->bd_mutex);
135 ret = do_blk_trace_setup(q, bdev, &buts);
136 mutex_unlock(&bdev->bd_mutex);
137 if (ret)
138 return ret;
139
140 if (copy_to_user(arg, &buts.name, 32))
141 return -EFAULT;
142
143 return 0;
144}
145
7199d4cd
AB
146static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
147 struct gendisk *disk, unsigned cmd, unsigned long arg)
148{
149 int ret;
150
151 switch (arg) {
9617db08
AB
152 case HDIO_GET_UNMASKINTR:
153 case HDIO_GET_MULTCOUNT:
154 case HDIO_GET_KEEPSETTINGS:
155 case HDIO_GET_32BIT:
156 case HDIO_GET_NOWERR:
157 case HDIO_GET_DMA:
158 case HDIO_GET_NICE:
159 case HDIO_GET_WCACHE:
160 case HDIO_GET_ACOUSTIC:
161 case HDIO_GET_ADDRESS:
162 case HDIO_GET_BUSSTATE:
163 return compat_hdio_ioctl(inode, file, disk, cmd, arg);
7199d4cd
AB
164 /*
165 * No handler required for the ones below, we just need to
166 * convert arg to a 64 bit pointer.
167 */
168 case BLKSECTSET:
169 /*
170 * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
171 * Some need translations, these do not.
172 */
173 case HDIO_GET_IDENTITY:
174 case HDIO_DRIVE_TASK:
175 case HDIO_DRIVE_CMD:
176 case HDIO_SCAN_HWIF:
177 /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
178 case 0x330:
179 /* 0x02 -- Floppy ioctls */
180 case FDMSGON:
181 case FDMSGOFF:
182 case FDSETEMSGTRESH:
183 case FDFLUSH:
184 case FDWERRORCLR:
185 case FDSETMAXERRS:
186 case FDGETMAXERRS:
187 case FDGETDRVTYP:
188 case FDEJECT:
189 case FDCLRPRM:
190 case FDFMTBEG:
191 case FDFMTEND:
192 case FDRESET:
193 case FDTWADDLE:
194 case FDFMTTRK:
195 case FDRAWCMD:
196 /* CDROM stuff */
197 case CDROMPAUSE:
198 case CDROMRESUME:
199 case CDROMPLAYMSF:
200 case CDROMPLAYTRKIND:
201 case CDROMREADTOCHDR:
202 case CDROMREADTOCENTRY:
203 case CDROMSTOP:
204 case CDROMSTART:
205 case CDROMEJECT:
206 case CDROMVOLCTRL:
207 case CDROMSUBCHNL:
208 case CDROMMULTISESSION:
209 case CDROM_GET_MCN:
210 case CDROMRESET:
211 case CDROMVOLREAD:
212 case CDROMSEEK:
213 case CDROMPLAYBLK:
214 case CDROMCLOSETRAY:
215 case CDROM_DISC_STATUS:
216 case CDROM_CHANGER_NSLOTS:
217 case CDROM_GET_CAPABILITY:
218 /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
219 * not take a struct cdrom_read, instead they take a struct cdrom_msf
220 * which is compatible.
221 */
222 case CDROMREADMODE2:
223 case CDROMREADMODE1:
224 case CDROMREADRAW:
225 case CDROMREADCOOKED:
226 case CDROMREADALL:
227 /* DVD ioctls */
228 case DVD_READ_STRUCT:
229 case DVD_WRITE_STRUCT:
230 case DVD_AUTH:
231 arg = (unsigned long)compat_ptr(arg);
232 /* These intepret arg as an unsigned long, not as a pointer,
233 * so we must not do compat_ptr() conversion. */
234 case HDIO_SET_MULTCOUNT:
235 case HDIO_SET_UNMASKINTR:
236 case HDIO_SET_KEEPSETTINGS:
237 case HDIO_SET_32BIT:
238 case HDIO_SET_NOWERR:
239 case HDIO_SET_DMA:
240 case HDIO_SET_PIO_MODE:
241 case HDIO_SET_NICE:
242 case HDIO_SET_WCACHE:
243 case HDIO_SET_ACOUSTIC:
244 case HDIO_SET_BUSSTATE:
245 case HDIO_SET_ADDRESS:
246 case CDROMEJECT_SW:
247 case CDROM_SET_OPTIONS:
248 case CDROM_CLEAR_OPTIONS:
249 case CDROM_SELECT_SPEED:
250 case CDROM_SELECT_DISC:
251 case CDROM_MEDIA_CHANGED:
252 case CDROM_DRIVE_STATUS:
253 case CDROM_LOCKDOOR:
254 case CDROM_DEBUG:
255 break;
256 default:
257 /* unknown ioctl number */
258 return -ENOIOCTLCMD;
259 }
260
261 if (disk->fops->unlocked_ioctl)
262 return disk->fops->unlocked_ioctl(file, cmd, arg);
263
264 if (disk->fops->ioctl) {
265 lock_kernel();
266 ret = disk->fops->ioctl(inode, file, cmd, arg);
267 unlock_kernel();
268 return ret;
269 }
270
271 return -ENOTTY;
272}
273
f58c4c0a
AB
274static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
275 struct block_device *bdev,
276 unsigned cmd, unsigned long arg)
277{
278 struct backing_dev_info *bdi;
279
280 switch (cmd) {
281 case BLKRAGET:
282 case BLKFRAGET:
283 if (!arg)
284 return -EINVAL;
285 bdi = blk_get_backing_dev_info(bdev);
286 if (bdi == NULL)
287 return -ENOTTY;
288 return compat_put_long(arg,
289 (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
290 case BLKROGET: /* compatible */
291 return compat_put_int(arg, bdev_read_only(bdev) != 0);
292 case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
293 return compat_put_int(arg, block_size(bdev));
294 case BLKSSZGET: /* get block device hardware sector size */
295 return compat_put_int(arg, bdev_hardsect_size(bdev));
296 case BLKSECTGET:
297 return compat_put_ushort(arg,
298 bdev_get_queue(bdev)->max_sectors);
299 case BLKRASET: /* compatible, but no compat_ptr (!) */
300 case BLKFRASET:
301 if (!capable(CAP_SYS_ADMIN))
302 return -EACCES;
303 bdi = blk_get_backing_dev_info(bdev);
304 if (bdi == NULL)
305 return -ENOTTY;
306 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
307 return 0;
308 case BLKGETSIZE:
309 if ((bdev->bd_inode->i_size >> 9) > ~0UL)
310 return -EFBIG;
311 return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
312
313 case BLKGETSIZE64_32:
314 return compat_put_u64(arg, bdev->bd_inode->i_size);
171044d4
AB
315
316 case BLKTRACESETUP32:
317 return compat_blk_trace_setup(bdev, compat_ptr(arg));
318 case BLKTRACESTART: /* compatible */
319 case BLKTRACESTOP: /* compatible */
320 case BLKTRACETEARDOWN: /* compatible */
321 return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
f58c4c0a
AB
322 }
323 return -ENOIOCTLCMD;
324}
325
326/* Most of the generic ioctls are handled in the normal fallback path.
327 This assumes the blkdev's low level compat_ioctl always returns
328 ENOIOCTLCMD for unknown ioctls. */
329long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
330{
331 int ret = -ENOIOCTLCMD;
332 struct inode *inode = file->f_mapping->host;
333 struct block_device *bdev = inode->i_bdev;
334 struct gendisk *disk = bdev->bd_disk;
335
336 switch (cmd) {
9617db08
AB
337 case HDIO_GETGEO:
338 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
f58c4c0a
AB
339 case BLKFLSBUF:
340 case BLKROSET:
341 /*
342 * the ones below are implemented in blkdev_locked_ioctl,
343 * but we call blkdev_ioctl, which gets the lock for us
344 */
345 case BLKRRPART:
346 return blkdev_ioctl(inode, file, cmd,
347 (unsigned long)compat_ptr(arg));
348 case BLKBSZSET_32:
349 return blkdev_ioctl(inode, file, BLKBSZSET,
350 (unsigned long)compat_ptr(arg));
351 }
352
353 lock_kernel();
354 ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
355 /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
356 if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
357 ret = disk->fops->compat_ioctl(file, cmd, arg);
358 unlock_kernel();
359
7199d4cd
AB
360 if (ret != -ENOIOCTLCMD)
361 return ret;
362
363 return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
f58c4c0a 364}