diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/ioctl.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/block/ioctl.c b/block/ioctl.c index ca939fc1030..d510c2a4eff 100644 --- a/block/ioctl.c +++ b/block/ioctl.c | |||
@@ -180,6 +180,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, | |||
180 | EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); | 180 | EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); |
181 | 181 | ||
182 | /* | 182 | /* |
183 | * Is it an unrecognized ioctl? The correct returns are either | ||
184 | * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a | ||
185 | * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl | ||
186 | * code before returning. | ||
187 | * | ||
188 | * Confused drivers sometimes return EINVAL, which is wrong. It | ||
189 | * means "I understood the ioctl command, but the parameters to | ||
190 | * it were wrong". | ||
191 | * | ||
192 | * We should aim to just fix the broken drivers, the EINVAL case | ||
193 | * should go away. | ||
194 | */ | ||
195 | static inline int is_unrecognized_ioctl(int ret) | ||
196 | { | ||
197 | return ret == -EINVAL || | ||
198 | ret == -ENOTTY || | ||
199 | ret == -ENOIOCTLCMD; | ||
200 | } | ||
201 | |||
202 | /* | ||
183 | * always keep this in sync with compat_blkdev_ioctl() | 203 | * always keep this in sync with compat_blkdev_ioctl() |
184 | */ | 204 | */ |
185 | int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | 205 | int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, |
@@ -196,8 +216,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | |||
196 | return -EACCES; | 216 | return -EACCES; |
197 | 217 | ||
198 | ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); | 218 | ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
199 | /* -EINVAL to handle old uncorrected drivers */ | 219 | if (!is_unrecognized_ioctl(ret)) |
200 | if (ret != -EINVAL && ret != -ENOTTY) | ||
201 | return ret; | 220 | return ret; |
202 | 221 | ||
203 | fsync_bdev(bdev); | 222 | fsync_bdev(bdev); |
@@ -206,8 +225,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | |||
206 | 225 | ||
207 | case BLKROSET: | 226 | case BLKROSET: |
208 | ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); | 227 | ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
209 | /* -EINVAL to handle old uncorrected drivers */ | 228 | if (!is_unrecognized_ioctl(ret)) |
210 | if (ret != -EINVAL && ret != -ENOTTY) | ||
211 | return ret; | 229 | return ret; |
212 | if (!capable(CAP_SYS_ADMIN)) | 230 | if (!capable(CAP_SYS_ADMIN)) |
213 | return -EACCES; | 231 | return -EACCES; |