diff options
| -rw-r--r-- | drivers/block/loop.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0d567397c254..68b205a9338f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
| @@ -161,17 +161,19 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { | |||
| 161 | &xor_funcs | 161 | &xor_funcs |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | static loff_t get_loop_size(struct loop_device *lo, struct file *file) | 164 | static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) |
| 165 | { | 165 | { |
| 166 | loff_t size, offset, loopsize; | 166 | loff_t size, loopsize; |
| 167 | 167 | ||
| 168 | /* Compute loopsize in bytes */ | 168 | /* Compute loopsize in bytes */ |
| 169 | size = i_size_read(file->f_mapping->host); | 169 | size = i_size_read(file->f_mapping->host); |
| 170 | offset = lo->lo_offset; | ||
| 171 | loopsize = size - offset; | 170 | loopsize = size - offset; |
| 172 | if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) | 171 | /* offset is beyond i_size, wierd but possible */ |
| 173 | loopsize = lo->lo_sizelimit; | 172 | if (loopsize < 0) |
| 173 | return 0; | ||
| 174 | 174 | ||
| 175 | if (sizelimit > 0 && sizelimit < loopsize) | ||
| 176 | loopsize = sizelimit; | ||
| 175 | /* | 177 | /* |
| 176 | * Unfortunately, if we want to do I/O on the device, | 178 | * Unfortunately, if we want to do I/O on the device, |
| 177 | * the number of 512-byte sectors has to fit into a sector_t. | 179 | * the number of 512-byte sectors has to fit into a sector_t. |
| @@ -179,17 +181,25 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file) | |||
| 179 | return loopsize >> 9; | 181 | return loopsize >> 9; |
| 180 | } | 182 | } |
| 181 | 183 | ||
| 184 | static loff_t get_loop_size(struct loop_device *lo, struct file *file) | ||
| 185 | { | ||
| 186 | return get_size(lo->lo_offset, lo->lo_sizelimit, file); | ||
| 187 | } | ||
| 188 | |||
| 182 | static int | 189 | static int |
| 183 | figure_loop_size(struct loop_device *lo) | 190 | figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit) |
| 184 | { | 191 | { |
| 185 | loff_t size = get_loop_size(lo, lo->lo_backing_file); | 192 | loff_t size = get_size(offset, sizelimit, lo->lo_backing_file); |
| 186 | sector_t x = (sector_t)size; | 193 | sector_t x = (sector_t)size; |
| 187 | 194 | ||
| 188 | if (unlikely((loff_t)x != size)) | 195 | if (unlikely((loff_t)x != size)) |
| 189 | return -EFBIG; | 196 | return -EFBIG; |
| 190 | 197 | if (lo->lo_offset != offset) | |
| 198 | lo->lo_offset = offset; | ||
| 199 | if (lo->lo_sizelimit != sizelimit) | ||
| 200 | lo->lo_sizelimit = sizelimit; | ||
| 191 | set_capacity(lo->lo_disk, x); | 201 | set_capacity(lo->lo_disk, x); |
| 192 | return 0; | 202 | return 0; |
| 193 | } | 203 | } |
| 194 | 204 | ||
| 195 | static inline int | 205 | static inline int |
| @@ -1059,9 +1069,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) | |||
| 1059 | 1069 | ||
| 1060 | if (lo->lo_offset != info->lo_offset || | 1070 | if (lo->lo_offset != info->lo_offset || |
| 1061 | lo->lo_sizelimit != info->lo_sizelimit) { | 1071 | lo->lo_sizelimit != info->lo_sizelimit) { |
| 1062 | lo->lo_offset = info->lo_offset; | 1072 | if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) |
| 1063 | lo->lo_sizelimit = info->lo_sizelimit; | ||
| 1064 | if (figure_loop_size(lo)) | ||
| 1065 | return -EFBIG; | 1073 | return -EFBIG; |
| 1066 | } | 1074 | } |
| 1067 | loop_config_discard(lo); | 1075 | loop_config_discard(lo); |
| @@ -1247,7 +1255,7 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev) | |||
| 1247 | err = -ENXIO; | 1255 | err = -ENXIO; |
| 1248 | if (unlikely(lo->lo_state != Lo_bound)) | 1256 | if (unlikely(lo->lo_state != Lo_bound)) |
| 1249 | goto out; | 1257 | goto out; |
| 1250 | err = figure_loop_size(lo); | 1258 | err = figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit); |
| 1251 | if (unlikely(err)) | 1259 | if (unlikely(err)) |
| 1252 | goto out; | 1260 | goto out; |
| 1253 | sec = get_capacity(lo->lo_disk); | 1261 | sec = get_capacity(lo->lo_disk); |
| @@ -1285,13 +1293,19 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 1285 | goto out_unlocked; | 1293 | goto out_unlocked; |
| 1286 | break; | 1294 | break; |
| 1287 | case LOOP_SET_STATUS: | 1295 | case LOOP_SET_STATUS: |
| 1288 | err = loop_set_status_old(lo, (struct loop_info __user *) arg); | 1296 | err = -EPERM; |
| 1297 | if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) | ||
| 1298 | err = loop_set_status_old(lo, | ||
| 1299 | (struct loop_info __user *)arg); | ||
| 1289 | break; | 1300 | break; |
| 1290 | case LOOP_GET_STATUS: | 1301 | case LOOP_GET_STATUS: |
| 1291 | err = loop_get_status_old(lo, (struct loop_info __user *) arg); | 1302 | err = loop_get_status_old(lo, (struct loop_info __user *) arg); |
| 1292 | break; | 1303 | break; |
| 1293 | case LOOP_SET_STATUS64: | 1304 | case LOOP_SET_STATUS64: |
| 1294 | err = loop_set_status64(lo, (struct loop_info64 __user *) arg); | 1305 | err = -EPERM; |
| 1306 | if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) | ||
| 1307 | err = loop_set_status64(lo, | ||
| 1308 | (struct loop_info64 __user *) arg); | ||
| 1295 | break; | 1309 | break; |
| 1296 | case LOOP_GET_STATUS64: | 1310 | case LOOP_GET_STATUS64: |
| 1297 | err = loop_get_status64(lo, (struct loop_info64 __user *) arg); | 1311 | err = loop_get_status64(lo, (struct loop_info64 __user *) arg); |
