compat_ioctl.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. static int compat_put_ushort(unsigned long arg, unsigned short val)
  14. {
  15. return put_user(val, (unsigned short __user *)compat_ptr(arg));
  16. }
  17. static int compat_put_int(unsigned long arg, int val)
  18. {
  19. return put_user(val, (compat_int_t __user *)compat_ptr(arg));
  20. }
  21. static int compat_put_long(unsigned long arg, long val)
  22. {
  23. return put_user(val, (compat_long_t __user *)compat_ptr(arg));
  24. }
  25. static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
  26. {
  27. return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
  28. }
  29. static int compat_put_u64(unsigned long arg, u64 val)
  30. {
  31. return put_user(val, (compat_u64 __user *)compat_ptr(arg));
  32. }
  33. #define BLKBSZGET_32 _IOR(0x12, 112, int)
  34. #define BLKBSZSET_32 _IOW(0x12, 113, int)
  35. #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
  36. struct compat_blk_user_trace_setup {
  37. char name[32];
  38. u16 act_mask;
  39. u32 buf_size;
  40. u32 buf_nr;
  41. compat_u64 start_lba;
  42. compat_u64 end_lba;
  43. u32 pid;
  44. };
  45. #define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
  46. static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
  47. {
  48. struct blk_user_trace_setup buts;
  49. struct compat_blk_user_trace_setup cbuts;
  50. struct request_queue *q;
  51. int ret;
  52. q = bdev_get_queue(bdev);
  53. if (!q)
  54. return -ENXIO;
  55. if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
  56. return -EFAULT;
  57. buts = (struct blk_user_trace_setup) {
  58. .act_mask = cbuts.act_mask,
  59. .buf_size = cbuts.buf_size,
  60. .buf_nr = cbuts.buf_nr,
  61. .start_lba = cbuts.start_lba,
  62. .end_lba = cbuts.end_lba,
  63. .pid = cbuts.pid,
  64. };
  65. memcpy(&buts.name, &cbuts.name, 32);
  66. mutex_lock(&bdev->bd_mutex);
  67. ret = do_blk_trace_setup(q, bdev, &buts);
  68. mutex_unlock(&bdev->bd_mutex);
  69. if (ret)
  70. return ret;
  71. if (copy_to_user(arg, &buts.name, 32))
  72. return -EFAULT;
  73. return 0;
  74. }
  75. static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
  76. struct gendisk *disk, unsigned cmd, unsigned long arg)
  77. {
  78. int ret;
  79. switch (arg) {
  80. /*
  81. * No handler required for the ones below, we just need to
  82. * convert arg to a 64 bit pointer.
  83. */
  84. case BLKSECTSET:
  85. /*
  86. * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
  87. * Some need translations, these do not.
  88. */
  89. case HDIO_GET_IDENTITY:
  90. case HDIO_DRIVE_TASK:
  91. case HDIO_DRIVE_CMD:
  92. case HDIO_SCAN_HWIF:
  93. /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
  94. case 0x330:
  95. /* 0x02 -- Floppy ioctls */
  96. case FDMSGON:
  97. case FDMSGOFF:
  98. case FDSETEMSGTRESH:
  99. case FDFLUSH:
  100. case FDWERRORCLR:
  101. case FDSETMAXERRS:
  102. case FDGETMAXERRS:
  103. case FDGETDRVTYP:
  104. case FDEJECT:
  105. case FDCLRPRM:
  106. case FDFMTBEG:
  107. case FDFMTEND:
  108. case FDRESET:
  109. case FDTWADDLE:
  110. case FDFMTTRK:
  111. case FDRAWCMD:
  112. /* CDROM stuff */
  113. case CDROMPAUSE:
  114. case CDROMRESUME:
  115. case CDROMPLAYMSF:
  116. case CDROMPLAYTRKIND:
  117. case CDROMREADTOCHDR:
  118. case CDROMREADTOCENTRY:
  119. case CDROMSTOP:
  120. case CDROMSTART:
  121. case CDROMEJECT:
  122. case CDROMVOLCTRL:
  123. case CDROMSUBCHNL:
  124. case CDROMMULTISESSION:
  125. case CDROM_GET_MCN:
  126. case CDROMRESET:
  127. case CDROMVOLREAD:
  128. case CDROMSEEK:
  129. case CDROMPLAYBLK:
  130. case CDROMCLOSETRAY:
  131. case CDROM_DISC_STATUS:
  132. case CDROM_CHANGER_NSLOTS:
  133. case CDROM_GET_CAPABILITY:
  134. /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
  135. * not take a struct cdrom_read, instead they take a struct cdrom_msf
  136. * which is compatible.
  137. */
  138. case CDROMREADMODE2:
  139. case CDROMREADMODE1:
  140. case CDROMREADRAW:
  141. case CDROMREADCOOKED:
  142. case CDROMREADALL:
  143. /* DVD ioctls */
  144. case DVD_READ_STRUCT:
  145. case DVD_WRITE_STRUCT:
  146. case DVD_AUTH:
  147. arg = (unsigned long)compat_ptr(arg);
  148. /* These intepret arg as an unsigned long, not as a pointer,
  149. * so we must not do compat_ptr() conversion. */
  150. case HDIO_SET_MULTCOUNT:
  151. case HDIO_SET_UNMASKINTR:
  152. case HDIO_SET_KEEPSETTINGS:
  153. case HDIO_SET_32BIT:
  154. case HDIO_SET_NOWERR:
  155. case HDIO_SET_DMA:
  156. case HDIO_SET_PIO_MODE:
  157. case HDIO_SET_NICE:
  158. case HDIO_SET_WCACHE:
  159. case HDIO_SET_ACOUSTIC:
  160. case HDIO_SET_BUSSTATE:
  161. case HDIO_SET_ADDRESS:
  162. case CDROMEJECT_SW:
  163. case CDROM_SET_OPTIONS:
  164. case CDROM_CLEAR_OPTIONS:
  165. case CDROM_SELECT_SPEED:
  166. case CDROM_SELECT_DISC:
  167. case CDROM_MEDIA_CHANGED:
  168. case CDROM_DRIVE_STATUS:
  169. case CDROM_LOCKDOOR:
  170. case CDROM_DEBUG:
  171. break;
  172. default:
  173. /* unknown ioctl number */
  174. return -ENOIOCTLCMD;
  175. }
  176. if (disk->fops->unlocked_ioctl)
  177. return disk->fops->unlocked_ioctl(file, cmd, arg);
  178. if (disk->fops->ioctl) {
  179. lock_kernel();
  180. ret = disk->fops->ioctl(inode, file, cmd, arg);
  181. unlock_kernel();
  182. return ret;
  183. }
  184. return -ENOTTY;
  185. }
  186. static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
  187. struct block_device *bdev,
  188. unsigned cmd, unsigned long arg)
  189. {
  190. struct backing_dev_info *bdi;
  191. switch (cmd) {
  192. case BLKRAGET:
  193. case BLKFRAGET:
  194. if (!arg)
  195. return -EINVAL;
  196. bdi = blk_get_backing_dev_info(bdev);
  197. if (bdi == NULL)
  198. return -ENOTTY;
  199. return compat_put_long(arg,
  200. (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
  201. case BLKROGET: /* compatible */
  202. return compat_put_int(arg, bdev_read_only(bdev) != 0);
  203. case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
  204. return compat_put_int(arg, block_size(bdev));
  205. case BLKSSZGET: /* get block device hardware sector size */
  206. return compat_put_int(arg, bdev_hardsect_size(bdev));
  207. case BLKSECTGET:
  208. return compat_put_ushort(arg,
  209. bdev_get_queue(bdev)->max_sectors);
  210. case BLKRASET: /* compatible, but no compat_ptr (!) */
  211. case BLKFRASET:
  212. if (!capable(CAP_SYS_ADMIN))
  213. return -EACCES;
  214. bdi = blk_get_backing_dev_info(bdev);
  215. if (bdi == NULL)
  216. return -ENOTTY;
  217. bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
  218. return 0;
  219. case BLKGETSIZE:
  220. if ((bdev->bd_inode->i_size >> 9) > ~0UL)
  221. return -EFBIG;
  222. return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
  223. case BLKGETSIZE64_32:
  224. return compat_put_u64(arg, bdev->bd_inode->i_size);
  225. case BLKTRACESETUP32:
  226. return compat_blk_trace_setup(bdev, compat_ptr(arg));
  227. case BLKTRACESTART: /* compatible */
  228. case BLKTRACESTOP: /* compatible */
  229. case BLKTRACETEARDOWN: /* compatible */
  230. return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
  231. }
  232. return -ENOIOCTLCMD;
  233. }
  234. /* Most of the generic ioctls are handled in the normal fallback path.
  235. This assumes the blkdev's low level compat_ioctl always returns
  236. ENOIOCTLCMD for unknown ioctls. */
  237. long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  238. {
  239. int ret = -ENOIOCTLCMD;
  240. struct inode *inode = file->f_mapping->host;
  241. struct block_device *bdev = inode->i_bdev;
  242. struct gendisk *disk = bdev->bd_disk;
  243. switch (cmd) {
  244. case BLKFLSBUF:
  245. case BLKROSET:
  246. /*
  247. * the ones below are implemented in blkdev_locked_ioctl,
  248. * but we call blkdev_ioctl, which gets the lock for us
  249. */
  250. case BLKRRPART:
  251. return blkdev_ioctl(inode, file, cmd,
  252. (unsigned long)compat_ptr(arg));
  253. case BLKBSZSET_32:
  254. return blkdev_ioctl(inode, file, BLKBSZSET,
  255. (unsigned long)compat_ptr(arg));
  256. }
  257. lock_kernel();
  258. ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
  259. /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
  260. if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
  261. ret = disk->fops->compat_ioctl(file, cmd, arg);
  262. unlock_kernel();
  263. if (ret != -ENOIOCTLCMD)
  264. return ret;
  265. return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  266. }