diff options
Diffstat (limited to 'fs/ioctl.c')
| -rw-r--r-- | fs/ioctl.c | 92 |
1 files changed, 53 insertions, 39 deletions
diff --git a/fs/ioctl.c b/fs/ioctl.c index 6c751106c2e5..7faefb4da939 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -228,14 +228,23 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
| 228 | 228 | ||
| 229 | #ifdef CONFIG_BLOCK | 229 | #ifdef CONFIG_BLOCK |
| 230 | 230 | ||
| 231 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | 231 | static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) |
| 232 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | 232 | { |
| 233 | return (offset >> inode->i_blkbits); | ||
| 234 | } | ||
| 235 | |||
| 236 | static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) | ||
| 237 | { | ||
| 238 | return (blk << inode->i_blkbits); | ||
| 239 | } | ||
| 233 | 240 | ||
| 234 | /** | 241 | /** |
| 235 | * __generic_block_fiemap - FIEMAP for block based inodes (no locking) | 242 | * __generic_block_fiemap - FIEMAP for block based inodes (no locking) |
| 236 | * @inode - the inode to map | 243 | * @inode: the inode to map |
| 237 | * @arg - the pointer to userspace where we copy everything to | 244 | * @fieinfo: the fiemap info struct that will be passed back to userspace |
| 238 | * @get_block - the fs's get_block function | 245 | * @start: where to start mapping in the inode |
| 246 | * @len: how much space to map | ||
| 247 | * @get_block: the fs's get_block function | ||
| 239 | * | 248 | * |
| 240 | * This does FIEMAP for block based inodes. Basically it will just loop | 249 | * This does FIEMAP for block based inodes. Basically it will just loop |
| 241 | * through get_block until we hit the number of extents we want to map, or we | 250 | * through get_block until we hit the number of extents we want to map, or we |
| @@ -250,58 +259,63 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
| 250 | */ | 259 | */ |
| 251 | 260 | ||
| 252 | int __generic_block_fiemap(struct inode *inode, | 261 | int __generic_block_fiemap(struct inode *inode, |
| 253 | struct fiemap_extent_info *fieinfo, u64 start, | 262 | struct fiemap_extent_info *fieinfo, loff_t start, |
| 254 | u64 len, get_block_t *get_block) | 263 | loff_t len, get_block_t *get_block) |
| 255 | { | 264 | { |
| 256 | struct buffer_head tmp; | 265 | struct buffer_head map_bh; |
| 257 | unsigned long long start_blk; | 266 | sector_t start_blk, last_blk; |
| 258 | long long length = 0, map_len = 0; | 267 | loff_t isize = i_size_read(inode); |
| 259 | u64 logical = 0, phys = 0, size = 0; | 268 | u64 logical = 0, phys = 0, size = 0; |
| 260 | u32 flags = FIEMAP_EXTENT_MERGED; | 269 | u32 flags = FIEMAP_EXTENT_MERGED; |
| 261 | int ret = 0, past_eof = 0, whole_file = 0; | 270 | bool past_eof = false, whole_file = false; |
| 271 | int ret = 0; | ||
| 262 | 272 | ||
| 263 | if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) | 273 | ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); |
| 274 | if (ret) | ||
| 264 | return ret; | 275 | return ret; |
| 265 | 276 | ||
| 266 | start_blk = logical_to_blk(inode, start); | 277 | /* |
| 267 | 278 | * Either the i_mutex or other appropriate locking needs to be held | |
| 268 | length = (long long)min_t(u64, len, i_size_read(inode)); | 279 | * since we expect isize to not change at all through the duration of |
| 269 | if (length < len) | 280 | * this call. |
| 270 | whole_file = 1; | 281 | */ |
| 282 | if (len >= isize) { | ||
| 283 | whole_file = true; | ||
| 284 | len = isize; | ||
| 285 | } | ||
| 271 | 286 | ||
| 272 | map_len = length; | 287 | start_blk = logical_to_blk(inode, start); |
| 288 | last_blk = logical_to_blk(inode, start + len - 1); | ||
| 273 | 289 | ||
| 274 | do { | 290 | do { |
| 275 | /* | 291 | /* |
| 276 | * we set b_size to the total size we want so it will map as | 292 | * we set b_size to the total size we want so it will map as |
| 277 | * many contiguous blocks as possible at once | 293 | * many contiguous blocks as possible at once |
| 278 | */ | 294 | */ |
| 279 | memset(&tmp, 0, sizeof(struct buffer_head)); | 295 | memset(&map_bh, 0, sizeof(struct buffer_head)); |
| 280 | tmp.b_size = map_len; | 296 | map_bh.b_size = len; |
| 281 | 297 | ||
| 282 | ret = get_block(inode, start_blk, &tmp, 0); | 298 | ret = get_block(inode, start_blk, &map_bh, 0); |
| 283 | if (ret) | 299 | if (ret) |
| 284 | break; | 300 | break; |
| 285 | 301 | ||
| 286 | /* HOLE */ | 302 | /* HOLE */ |
| 287 | if (!buffer_mapped(&tmp)) { | 303 | if (!buffer_mapped(&map_bh)) { |
| 288 | length -= blk_to_logical(inode, 1); | ||
| 289 | start_blk++; | 304 | start_blk++; |
| 290 | 305 | ||
| 291 | /* | 306 | /* |
| 292 | * we want to handle the case where there is an | 307 | * We want to handle the case where there is an |
| 293 | * allocated block at the front of the file, and then | 308 | * allocated block at the front of the file, and then |
| 294 | * nothing but holes up to the end of the file properly, | 309 | * nothing but holes up to the end of the file properly, |
| 295 | * to make sure that extent at the front gets properly | 310 | * to make sure that extent at the front gets properly |
| 296 | * marked with FIEMAP_EXTENT_LAST | 311 | * marked with FIEMAP_EXTENT_LAST |
| 297 | */ | 312 | */ |
| 298 | if (!past_eof && | 313 | if (!past_eof && |
| 299 | blk_to_logical(inode, start_blk) >= | 314 | blk_to_logical(inode, start_blk) >= isize) |
| 300 | blk_to_logical(inode, 0)+i_size_read(inode)) | ||
| 301 | past_eof = 1; | 315 | past_eof = 1; |
| 302 | 316 | ||
| 303 | /* | 317 | /* |
| 304 | * first hole after going past the EOF, this is our | 318 | * First hole after going past the EOF, this is our |
| 305 | * last extent | 319 | * last extent |
| 306 | */ | 320 | */ |
| 307 | if (past_eof && size) { | 321 | if (past_eof && size) { |
| @@ -309,15 +323,18 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 309 | ret = fiemap_fill_next_extent(fieinfo, logical, | 323 | ret = fiemap_fill_next_extent(fieinfo, logical, |
| 310 | phys, size, | 324 | phys, size, |
| 311 | flags); | 325 | flags); |
| 312 | break; | 326 | } else if (size) { |
| 327 | ret = fiemap_fill_next_extent(fieinfo, logical, | ||
| 328 | phys, size, flags); | ||
| 329 | size = 0; | ||
| 313 | } | 330 | } |
| 314 | 331 | ||
| 315 | /* if we have holes up to/past EOF then we're done */ | 332 | /* if we have holes up to/past EOF then we're done */ |
| 316 | if (length <= 0 || past_eof) | 333 | if (start_blk > last_blk || past_eof || ret) |
| 317 | break; | 334 | break; |
| 318 | } else { | 335 | } else { |
| 319 | /* | 336 | /* |
| 320 | * we have gone over the length of what we wanted to | 337 | * We have gone over the length of what we wanted to |
| 321 | * map, and it wasn't the entire file, so add the extent | 338 | * map, and it wasn't the entire file, so add the extent |
| 322 | * we got last time and exit. | 339 | * we got last time and exit. |
| 323 | * | 340 | * |
| @@ -331,7 +348,7 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 331 | * are good to go, just add the extent to the fieinfo | 348 | * are good to go, just add the extent to the fieinfo |
| 332 | * and break | 349 | * and break |
| 333 | */ | 350 | */ |
| 334 | if (length <= 0 && !whole_file) { | 351 | if (start_blk > last_blk && !whole_file) { |
| 335 | ret = fiemap_fill_next_extent(fieinfo, logical, | 352 | ret = fiemap_fill_next_extent(fieinfo, logical, |
| 336 | phys, size, | 353 | phys, size, |
| 337 | flags); | 354 | flags); |
| @@ -351,11 +368,10 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 351 | } | 368 | } |
| 352 | 369 | ||
| 353 | logical = blk_to_logical(inode, start_blk); | 370 | logical = blk_to_logical(inode, start_blk); |
| 354 | phys = blk_to_logical(inode, tmp.b_blocknr); | 371 | phys = blk_to_logical(inode, map_bh.b_blocknr); |
| 355 | size = tmp.b_size; | 372 | size = map_bh.b_size; |
| 356 | flags = FIEMAP_EXTENT_MERGED; | 373 | flags = FIEMAP_EXTENT_MERGED; |
| 357 | 374 | ||
| 358 | length -= tmp.b_size; | ||
| 359 | start_blk += logical_to_blk(inode, size); | 375 | start_blk += logical_to_blk(inode, size); |
| 360 | 376 | ||
| 361 | /* | 377 | /* |
| @@ -363,15 +379,13 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 363 | * soon as we find a hole that the last extent we found | 379 | * soon as we find a hole that the last extent we found |
| 364 | * is marked with FIEMAP_EXTENT_LAST | 380 | * is marked with FIEMAP_EXTENT_LAST |
| 365 | */ | 381 | */ |
| 366 | if (!past_eof && | 382 | if (!past_eof && logical + size >= isize) |
| 367 | logical+size >= | 383 | past_eof = true; |
| 368 | blk_to_logical(inode, 0)+i_size_read(inode)) | ||
| 369 | past_eof = 1; | ||
| 370 | } | 384 | } |
| 371 | cond_resched(); | 385 | cond_resched(); |
| 372 | } while (1); | 386 | } while (1); |
| 373 | 387 | ||
| 374 | /* if ret is 1 then we just hit the end of the extent array */ | 388 | /* If ret is 1 then we just hit the end of the extent array */ |
| 375 | if (ret == 1) | 389 | if (ret == 1) |
| 376 | ret = 0; | 390 | ret = 0; |
| 377 | 391 | ||
