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