1 #include <linux/capability.h> 2 #include <linux/blkdev.h> 3 #include <linux/blkpg.h> 4 #include <linux/hdreg.h> 5 #include <linux/backing-dev.h> 6 #include <linux/buffer_head.h> 7 #include <linux/smp_lock.h> 8 #include <linux/blktrace_api.h> 9 #include <asm/uaccess.h> 10 11 static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) 12 { 13 struct block_device *bdevp; 14 struct gendisk *disk; 15 struct blkpg_ioctl_arg a; 16 struct blkpg_partition p; 17 long long start, length; 18 int part; 19 int i; 20 21 if (!capable(CAP_SYS_ADMIN)) 22 return -EACCES; 23 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) 24 return -EFAULT; 25 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) 26 return -EFAULT; 27 disk = bdev->bd_disk; 28 if (bdev != bdev->bd_contains) 29 return -EINVAL; 30 part = p.pno; 31 if (part <= 0 || part >= disk->minors) 32 return -EINVAL; 33 switch (a.op) { 34 case BLKPG_ADD_PARTITION: 35 start = p.start >> 9; 36 length = p.length >> 9; 37 /* check for fit in a hd_struct */ 38 if (sizeof(sector_t) == sizeof(long) && 39 sizeof(long long) > sizeof(long)) { 40 long pstart = start, plength = length; 41 if (pstart != start || plength != length 42 || pstart < 0 || plength < 0) 43 return -EINVAL; 44 } 45 /* partition number in use? */ 46 mutex_lock(&bdev->bd_mutex); 47 if (disk->part[part - 1]) { 48 mutex_unlock(&bdev->bd_mutex); 49 return -EBUSY; 50 } 51 /* overlap? */ 52 for (i = 0; i < disk->minors - 1; i++) { 53 struct hd_struct *s = disk->part[i]; 54 55 if (!s) 56 continue; 57 if (!(start+length <= s->start_sect || 58 start >= s->start_sect + s->nr_sects)) { 59 mutex_unlock(&bdev->bd_mutex); 60 return -EBUSY; 61 } 62 } 63 /* all seems OK */ 64 add_partition(disk, part, start, length, ADDPART_FLAG_NONE); 65 mutex_unlock(&bdev->bd_mutex); 66 return 0; 67 case BLKPG_DEL_PARTITION: 68 if (!disk->part[part-1]) 69 return -ENXIO; 70 if (disk->part[part - 1]->nr_sects == 0) 71 return -ENXIO; 72 bdevp = bdget_disk(disk, part); 73 if (!bdevp) 74 return -ENOMEM; 75 mutex_lock(&bdevp->bd_mutex); 76 if (bdevp->bd_openers) { 77 mutex_unlock(&bdevp->bd_mutex); 78 bdput(bdevp); 79 return -EBUSY; 80 } 81 /* all seems OK */ 82 fsync_bdev(bdevp); 83 invalidate_bdev(bdevp); 84 85 mutex_lock_nested(&bdev->bd_mutex, 1); 86 delete_partition(disk, part); 87 mutex_unlock(&bdev->bd_mutex); 88 mutex_unlock(&bdevp->bd_mutex); 89 bdput(bdevp); 90 91 return 0; 92 default: 93 return -EINVAL; 94 } 95 } 96 97 static int blkdev_reread_part(struct block_device *bdev) 98 { 99 struct gendisk *disk = bdev->bd_disk; 100 int res; 101 102 if (disk->minors == 1 || bdev != bdev->bd_contains) 103 return -EINVAL; 104 if (!capable(CAP_SYS_ADMIN)) 105 return -EACCES; 106 if (!mutex_trylock(&bdev->bd_mutex)) 107 return -EBUSY; 108 res = rescan_partitions(disk, bdev); 109 mutex_unlock(&bdev->bd_mutex); 110 return res; 111 } 112 113 static int put_ushort(unsigned long arg, unsigned short val) 114 { 115 return put_user(val, (unsigned short __user *)arg); 116 } 117 118 static int put_int(unsigned long arg, int val) 119 { 120 return put_user(val, (int __user *)arg); 121 } 122 123 static int put_long(unsigned long arg, long val) 124 { 125 return put_user(val, (long __user *)arg); 126 } 127 128 static int put_ulong(unsigned long arg, unsigned long val) 129 { 130 return put_user(val, (unsigned long __user *)arg); 131 } 132 133 static int put_u64(unsigned long arg, u64 val) 134 { 135 return put_user(val, (u64 __user *)arg); 136 } 137 138 static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev, 139 unsigned cmd, unsigned long arg) 140 { 141 struct backing_dev_info *bdi; 142 int ret, n; 143 144 switch (cmd) { 145 case BLKRAGET: 146 case BLKFRAGET: 147 if (!arg) 148 return -EINVAL; 149 bdi = blk_get_backing_dev_info(bdev); 150 if (bdi == NULL) 151 return -ENOTTY; 152 return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512); 153 case BLKROGET: 154 return put_int(arg, bdev_read_only(bdev) != 0); 155 case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ 156 return put_int(arg, block_size(bdev)); 157 case BLKSSZGET: /* get block device hardware sector size */ 158 return put_int(arg, bdev_hardsect_size(bdev)); 159 case BLKSECTGET: 160 return put_ushort(arg, bdev_get_queue(bdev)->max_sectors); 161 case BLKRASET: 162 case BLKFRASET: 163 if(!capable(CAP_SYS_ADMIN)) 164 return -EACCES; 165 bdi = blk_get_backing_dev_info(bdev); 166 if (bdi == NULL) 167 return -ENOTTY; 168 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; 169 return 0; 170 case BLKBSZSET: 171 /* set the logical block size */ 172 if (!capable(CAP_SYS_ADMIN)) 173 return -EACCES; 174 if (!arg) 175 return -EINVAL; 176 if (get_user(n, (int __user *) arg)) 177 return -EFAULT; 178 if (bd_claim(bdev, file) < 0) 179 return -EBUSY; 180 ret = set_blocksize(bdev, n); 181 bd_release(bdev); 182 return ret; 183 case BLKPG: 184 return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg); 185 case BLKRRPART: 186 return blkdev_reread_part(bdev); 187 case BLKGETSIZE: 188 if ((bdev->bd_inode->i_size >> 9) > ~0UL) 189 return -EFBIG; 190 return put_ulong(arg, bdev->bd_inode->i_size >> 9); 191 case BLKGETSIZE64: 192 return put_u64(arg, bdev->bd_inode->i_size); 193 case BLKTRACESTART: 194 case BLKTRACESTOP: 195 case BLKTRACESETUP: 196 case BLKTRACETEARDOWN: 197 return blk_trace_ioctl(bdev, cmd, (char __user *) arg); 198 } 199 return -ENOIOCTLCMD; 200 } 201 202 int blkdev_driver_ioctl(struct inode *inode, struct file *file, 203 struct gendisk *disk, unsigned cmd, unsigned long arg) 204 { 205 int ret; 206 if (disk->fops->unlocked_ioctl) 207 return disk->fops->unlocked_ioctl(file, cmd, arg); 208 209 if (disk->fops->ioctl) { 210 lock_kernel(); 211 ret = disk->fops->ioctl(inode, file, cmd, arg); 212 unlock_kernel(); 213 return ret; 214 } 215 216 return -ENOTTY; 217 } 218 EXPORT_SYMBOL_GPL(blkdev_driver_ioctl); 219 220 /* 221 * always keep this in sync with compat_blkdev_ioctl() and 222 * compat_blkdev_locked_ioctl() 223 */ 224 int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, 225 unsigned long arg) 226 { 227 struct block_device *bdev = inode->i_bdev; 228 struct gendisk *disk = bdev->bd_disk; 229 int ret, n; 230 231 switch(cmd) { 232 case BLKFLSBUF: 233 if (!capable(CAP_SYS_ADMIN)) 234 return -EACCES; 235 236 ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg); 237 /* -EINVAL to handle old uncorrected drivers */ 238 if (ret != -EINVAL && ret != -ENOTTY) 239 return ret; 240 241 lock_kernel(); 242 fsync_bdev(bdev); 243 invalidate_bdev(bdev); 244 unlock_kernel(); 245 return 0; 246 247 case BLKROSET: 248 ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg); 249 /* -EINVAL to handle old uncorrected drivers */ 250 if (ret != -EINVAL && ret != -ENOTTY) 251 return ret; 252 if (!capable(CAP_SYS_ADMIN)) 253 return -EACCES; 254 if (get_user(n, (int __user *)(arg))) 255 return -EFAULT; 256 lock_kernel(); 257 set_device_ro(bdev, n); 258 unlock_kernel(); 259 return 0; 260 case HDIO_GETGEO: { 261 struct hd_geometry geo; 262 263 if (!arg) 264 return -EINVAL; 265 if (!disk->fops->getgeo) 266 return -ENOTTY; 267 268 /* 269 * We need to set the startsect first, the driver may 270 * want to override it. 271 */ 272 geo.start = get_start_sect(bdev); 273 ret = disk->fops->getgeo(bdev, &geo); 274 if (ret) 275 return ret; 276 if (copy_to_user((struct hd_geometry __user *)arg, &geo, 277 sizeof(geo))) 278 return -EFAULT; 279 return 0; 280 } 281 } 282 283 lock_kernel(); 284 ret = blkdev_locked_ioctl(file, bdev, cmd, arg); 285 unlock_kernel(); 286 if (ret != -ENOIOCTLCMD) 287 return ret; 288 289 return blkdev_driver_ioctl(inode, file, disk, cmd, arg); 290 } 291 EXPORT_SYMBOL_GPL(blkdev_ioctl); 292