blkpg.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

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. return 0;
  103. }
  104. /*
  105.  * Delete a partition given by partition number
  106.  *
  107.  * returns: EINVAL: bad parameters
  108.  *          ENXIO: cannot find partition
  109.  *          EBUSY: partition is busy
  110.  *          0: all OK.
  111.  *
  112.  * Note that the dev argument refers to the entire disk, not the partition.
  113.  */
  114. int del_partition(kdev_t dev, struct blkpg_partition *p) {
  115. struct gendisk *g;
  116. kdev_t devp;
  117. int drive, first_minor, minor;
  118. /* find the drive major */
  119. g = get_gendisk(dev);
  120. if (!g)
  121. return -ENXIO;
  122. /* drive and partition number OK? */
  123. drive = (MINOR(dev) >> g->minor_shift);
  124. first_minor = (drive << g->minor_shift);
  125. if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
  126. return -EINVAL;
  127. /* existing drive and partition? */
  128. minor = first_minor + p->pno;
  129. if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
  130. return -ENXIO;
  131. /* partition in use? Incomplete check for now. */
  132. devp = MKDEV(MAJOR(dev), minor);
  133. if (is_mounted(devp) || is_swap_partition(devp))
  134. return -EBUSY;
  135. /* all seems OK */
  136. fsync_dev(devp);
  137. invalidate_buffers(devp);
  138. g->part[minor].start_sect = 0;
  139. g->part[minor].nr_sects = 0;
  140. if (g->sizes)
  141. g->sizes[minor] = 0;
  142. return 0;
  143. }
  144. int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
  145. {
  146. struct blkpg_ioctl_arg a;
  147. struct blkpg_partition p;
  148. int len;
  149. if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
  150. return -EFAULT;
  151. switch (a.op) {
  152. case BLKPG_ADD_PARTITION:
  153. case BLKPG_DEL_PARTITION:
  154. len = a.datalen;
  155. if (len < sizeof(struct blkpg_partition))
  156. return -EINVAL;
  157. if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
  158. return -EFAULT;
  159. if (!capable(CAP_SYS_ADMIN))
  160. return -EACCES;
  161. if (a.op == BLKPG_ADD_PARTITION)
  162. return add_partition(dev, &p);
  163. else
  164. return del_partition(dev, &p);
  165. default:
  166. return -EINVAL;
  167. }
  168. }
  169. /*
  170.  * Common ioctl's for block devices
  171.  */
  172. int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
  173. {
  174. struct gendisk *g;
  175. u64 ullval = 0;
  176. int intval;
  177. if (!dev)
  178. return -EINVAL;
  179. switch (cmd) {
  180. case BLKROSET:
  181. if (!capable(CAP_SYS_ADMIN))
  182. return -EACCES;
  183. if (get_user(intval, (int *)(arg)))
  184. return -EFAULT;
  185. set_device_ro(dev, intval);
  186. return 0;
  187. case BLKROGET:
  188. intval = (is_read_only(dev) != 0);
  189. return put_user(intval, (int *)(arg));
  190. case BLKRASET:
  191. if(!capable(CAP_SYS_ADMIN))
  192. return -EACCES;
  193. if(arg > 0xff)
  194. return -EINVAL;
  195. read_ahead[MAJOR(dev)] = arg;
  196. return 0;
  197. case BLKRAGET:
  198. if (!arg)
  199. return -EINVAL;
  200. return put_user(read_ahead[MAJOR(dev)], (long *) arg);
  201. case BLKFLSBUF:
  202. if(!capable(CAP_SYS_ADMIN))
  203. return -EACCES;
  204. fsync_dev(dev);
  205. invalidate_buffers(dev);
  206. return 0;
  207. case BLKSSZGET:
  208. /* get block device sector size as needed e.g. by fdisk */
  209. intval = get_hardsect_size(dev);
  210. return put_user(intval, (int *) arg);
  211. case BLKGETSIZE:
  212. case BLKGETSIZE64:
  213. g = get_gendisk(dev);
  214. if (g)
  215. ullval = g->part[MINOR(dev)].nr_sects;
  216. if (cmd == BLKGETSIZE)
  217. return put_user((unsigned long)ullval, (unsigned long *)arg);
  218. else
  219. return put_user(ullval << 9, (u64 *)arg);
  220. #if 0
  221. case BLKRRPART: /* Re-read partition tables */
  222. if (!capable(CAP_SYS_ADMIN)) 
  223. return -EACCES;
  224. return reread_partitions(dev, 1);
  225. #endif
  226. case BLKPG:
  227. return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
  228. case BLKELVGET:
  229. return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
  230.        (blkelv_ioctl_arg_t *) arg);
  231. case BLKELVSET:
  232. return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
  233.        (blkelv_ioctl_arg_t *) arg);
  234. case BLKBSZGET:
  235. /* get the logical block size (cf. BLKSSZGET) */
  236. intval = BLOCK_SIZE;
  237. if (blksize_size[MAJOR(dev)])
  238. intval = blksize_size[MAJOR(dev)][MINOR(dev)];
  239. return put_user (intval, (int *) arg);
  240. case BLKBSZSET:
  241. /* set the logical block size */
  242. if (!capable (CAP_SYS_ADMIN))
  243. return -EACCES;
  244. if (!dev || !arg)
  245. return -EINVAL;
  246. if (get_user (intval, (int *) arg))
  247. return -EFAULT;
  248. if (intval > PAGE_SIZE || intval < 512 ||
  249.     (intval & (intval - 1)))
  250. return -EINVAL;
  251. if (is_mounted (dev) || is_swap_partition (dev))
  252. return -EBUSY;
  253. set_blocksize (dev, intval);
  254. return 0;
  255. default:
  256. return -EINVAL;
  257. }
  258. }
  259. EXPORT_SYMBOL(blk_ioctl);