blkpg.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Partition table and disk geometry handling
  3.  *
  4.  * This obsoletes the partition-handling code in genhd.c:
  5.  * Userspace can look at a disk in arbitrary format and tell
  6.  * the kernel what partitions there are on the disk, and how
  7.  * these should be numbered.
  8.  * It also allows one to repartition a disk that is being used.
  9.  *
  10.  * A single ioctl with lots of subfunctions:
  11.  *
  12.  * Device number stuff:
  13.  *    get_whole_disk()          (given the device number of a partition, find
  14.  *                               the device number of the encompassing disk)
  15.  *    get_all_partitions()      (given the device number of a disk, return the
  16.  *                               device numbers of all its known partitions)
  17.  *
  18.  * Partition stuff:
  19.  *    add_partition()
  20.  *    delete_partition()
  21.  *    test_partition_in_use()   (also for test_disk_in_use)
  22.  *
  23.  * Geometry stuff:
  24.  *    get_geometry()
  25.  *    set_geometry()
  26.  *    get_bios_drivedata()
  27.  *
  28.  * For today, only the partition stuff - aeb, 990515
  29.  */
  30. #include <linux/errno.h>
  31. #include <linux/fs.h> /* for BLKRASET, ... */
  32. #include <linux/sched.h> /* for capable() */
  33. #include <linux/blk.h> /* for set_device_ro() */
  34. #include <linux/blkpg.h>
  35. #include <linux/genhd.h>
  36. #include <linux/swap.h> /* for is_swap_partition() */
  37. #include <linux/module.h>               /* for EXPORT_SYMBOL */
  38. #include <asm/uaccess.h>
  39. /*
  40.  * What is the data describing a partition?
  41.  *
  42.  * 1. a device number (kdev_t)
  43.  * 2. a starting sector and number of sectors (hd_struct)
  44.  *    given in the part[] array of the gendisk structure for the drive.
  45.  *
  46.  * The number of sectors is replicated in the sizes[] array of
  47.  * the gendisk structure for the major, which again is copied to
  48.  * the blk_size[][] array.
  49.  * (However, hd_struct has the number of 512-byte sectors,
  50.  *  g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
  51.  * Note that several drives may have the same major.
  52.  */
  53. /*
  54.  * Add a partition.
  55.  *
  56.  * returns: EINVAL: bad parameters
  57.  *          ENXIO: cannot find drive
  58.  *          EBUSY: proposed partition overlaps an existing one
  59.  *                 or has the same number as an existing one
  60.  *          0: all OK.
  61.  */
  62. int add_partition(kdev_t dev, struct blkpg_partition *p) {
  63. struct gendisk *g;
  64. long long ppstart, pplength;
  65. long pstart, plength;
  66. int i, drive, first_minor, end_minor, minor;
  67. /* convert bytes to sectors, check for fit in a hd_struct */
  68. ppstart = (p->start >> 9);
  69. pplength = (p->length >> 9);
  70. pstart = ppstart;
  71. plength = pplength;
  72. if (pstart != ppstart || plength != pplength
  73.     || pstart < 0 || plength < 0)
  74. return -EINVAL;
  75. /* find the drive major */
  76. g = get_gendisk(dev);
  77. if (!g)
  78. return -ENXIO;
  79. /* existing drive? */
  80. drive = (MINOR(dev) >> g->minor_shift);
  81. first_minor = (drive << g->minor_shift);
  82. end_minor   = first_minor + g->max_p;
  83. if (drive >= g->nr_real)
  84. return -ENXIO;
  85. /* drive and partition number OK? */
  86. if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
  87. return -EINVAL;
  88. /* partition number in use? */
  89. minor = first_minor + p->pno;
  90. if (g->part[minor].nr_sects != 0)
  91. return -EBUSY;
  92. /* overlap? */
  93. for (i=first_minor+1; i<end_minor; i++)
  94. if (!(pstart+plength <= g->part[i].start_sect ||
  95.       pstart >= g->part[i].start_sect + g->part[i].nr_sects))
  96. return -EBUSY;
  97. /* all seems OK */
  98. g->part[minor].start_sect = pstart;
  99. g->part[minor].nr_sects = plength;
  100. if (g->sizes)
  101. g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
  102. devfs_register_partitions (g, first_minor, 0);
  103. return 0;
  104. }
  105. /*
  106.  * Delete a partition given by partition number
  107.  *
  108.  * returns: EINVAL: bad parameters
  109.  *          ENXIO: cannot find partition
  110.  *          EBUSY: partition is busy
  111.  *          0: all OK.
  112.  *
  113.  * Note that the dev argument refers to the entire disk, not the partition.
  114.  */
  115. int del_partition(kdev_t dev, struct blkpg_partition *p) {
  116. struct gendisk *g;
  117. kdev_t devp;
  118. int drive, first_minor, minor;
  119. /* find the drive major */
  120. g = get_gendisk(dev);
  121. if (!g)
  122. return -ENXIO;
  123. /* drive and partition number OK? */
  124. drive = (MINOR(dev) >> g->minor_shift);
  125. first_minor = (drive << g->minor_shift);
  126. if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
  127. return -EINVAL;
  128. /* existing drive and partition? */
  129. minor = first_minor + p->pno;
  130. if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
  131. return -ENXIO;
  132. /* partition in use? Incomplete check for now. */
  133. devp = MKDEV(MAJOR(dev), minor);
  134. if (is_mounted(devp) || is_swap_partition(devp))
  135. return -EBUSY;
  136. /* all seems OK */
  137. fsync_dev(devp);
  138. invalidate_buffers(devp);
  139. g->part[minor].start_sect = 0;
  140. g->part[minor].nr_sects = 0;
  141. if (g->sizes)
  142. g->sizes[minor] = 0;
  143. devfs_register_partitions (g, first_minor, 0);
  144. return 0;
  145. }
  146. int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
  147. {
  148. struct blkpg_ioctl_arg a;
  149. struct blkpg_partition p;
  150. int len;
  151. if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
  152. return -EFAULT;
  153. switch (a.op) {
  154. case BLKPG_ADD_PARTITION:
  155. case BLKPG_DEL_PARTITION:
  156. len = a.datalen;
  157. if (len < sizeof(struct blkpg_partition))
  158. return -EINVAL;
  159. if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
  160. return -EFAULT;
  161. if (!capable(CAP_SYS_ADMIN))
  162. return -EACCES;
  163. if (a.op == BLKPG_ADD_PARTITION)
  164. return add_partition(dev, &p);
  165. else
  166. return del_partition(dev, &p);
  167. default:
  168. return -EINVAL;
  169. }
  170. }
  171. /*
  172.  * Common ioctl's for block devices
  173.  */
  174. int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
  175. {
  176. struct gendisk *g;
  177. u64 ullval = 0;
  178. int intval;
  179. if (!dev)
  180. return -EINVAL;
  181. switch (cmd) {
  182. case BLKROSET:
  183. if (!capable(CAP_SYS_ADMIN))
  184. return -EACCES;
  185. if (get_user(intval, (int *)(arg)))
  186. return -EFAULT;
  187. set_device_ro(dev, intval);
  188. return 0;
  189. case BLKROGET:
  190. intval = (is_read_only(dev) != 0);
  191. return put_user(intval, (int *)(arg));
  192. case BLKRASET:
  193. if(!capable(CAP_SYS_ADMIN))
  194. return -EACCES;
  195. if(arg > 0xff)
  196. return -EINVAL;
  197. read_ahead[MAJOR(dev)] = arg;
  198. return 0;
  199. case BLKRAGET:
  200. if (!arg)
  201. return -EINVAL;
  202. return put_user(read_ahead[MAJOR(dev)], (long *) arg);
  203. case BLKFLSBUF:
  204. if(!capable(CAP_SYS_ADMIN))
  205. return -EACCES;
  206. fsync_dev(dev);
  207. invalidate_buffers(dev);
  208. return 0;
  209. case BLKSSZGET:
  210. /* get block device sector size as needed e.g. by fdisk */
  211. intval = get_hardsect_size(dev);
  212. return put_user(intval, (int *) arg);
  213. case BLKGETSIZE:
  214. case BLKGETSIZE64:
  215. g = get_gendisk(dev);
  216. if (g)
  217. ullval = g->part[MINOR(dev)].nr_sects;
  218. if (cmd == BLKGETSIZE)
  219. return put_user((unsigned long)ullval, (unsigned long *)arg);
  220. else
  221. return put_user(ullval << 9, (u64 *)arg);
  222. #if 0
  223. case BLKRRPART: /* Re-read partition tables */
  224. if (!capable(CAP_SYS_ADMIN)) 
  225. return -EACCES;
  226. return reread_partitions(dev, 1);
  227. #endif
  228. case BLKPG:
  229. return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
  230. case BLKELVGET:
  231. return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
  232.        (blkelv_ioctl_arg_t *) arg);
  233. case BLKELVSET:
  234. return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
  235.        (blkelv_ioctl_arg_t *) arg);
  236. case BLKBSZGET:
  237. /* get the logical block size (cf. BLKSSZGET) */
  238. intval = BLOCK_SIZE;
  239. if (blksize_size[MAJOR(dev)])
  240. intval = blksize_size[MAJOR(dev)][MINOR(dev)];
  241. return put_user (intval, (int *) arg);
  242. case BLKBSZSET:
  243. /* set the logical block size */
  244. if (!capable (CAP_SYS_ADMIN))
  245. return -EACCES;
  246. if (!dev || !arg)
  247. return -EINVAL;
  248. if (get_user (intval, (int *) arg))
  249. return -EFAULT;
  250. if (intval > PAGE_SIZE || intval < 512 ||
  251.     (intval & (intval - 1)))
  252. return -EINVAL;
  253. if (is_mounted (dev) || is_swap_partition (dev))
  254. return -EBUSY;
  255. set_blocksize (dev, intval);
  256. return 0;
  257. default:
  258. return -EINVAL;
  259. }
  260. }
  261. EXPORT_SYMBOL(blk_ioctl);