Commit 3a3076f4d6e2fa31338a0b007df42a3b32f079e0
Committed by
Linus Torvalds
1 parent
1918ad77f7
Exists in
master
and in
20 other branches
Cleanup generic block based fiemap
This cleans up a few of the complaints of __generic_block_fiemap. I've fixed all the typing stuff, used inline functions instead of macros, gotten rid of a couple of variables, and made sure the size and block requests are all block aligned. It also fixes a problem where sometimes FIEMAP_EXTENT_LAST wasn't being set properly. Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 2 changed files with 56 additions and 41 deletions Side-by-side Diff
fs/ioctl.c
... | ... | @@ -228,14 +228,23 @@ |
228 | 228 | |
229 | 229 | #ifdef CONFIG_BLOCK |
230 | 230 | |
231 | -#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | |
232 | -#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | |
231 | +static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) | |
232 | +{ | |
233 | + return (offset >> inode->i_blkbits); | |
234 | +} | |
233 | 235 | |
236 | +static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) | |
237 | +{ | |
238 | + return (blk << inode->i_blkbits); | |
239 | +} | |
240 | + | |
234 | 241 | /** |
235 | 242 | * __generic_block_fiemap - FIEMAP for block based inodes (no locking) |
236 | - * @inode - the inode to map | |
237 | - * @arg - the pointer to userspace where we copy everything to | |
238 | - * @get_block - the fs's get_block function | |
243 | + * @inode: the inode to map | |
244 | + * @fieinfo: the fiemap info struct that will be passed back to userspace | |
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 | 249 | * This does FIEMAP for block based inodes. Basically it will just loop |
241 | 250 | * through get_block until we hit the number of extents we want to map, or we |
242 | 251 | |
243 | 252 | |
244 | 253 | |
245 | 254 | |
246 | 255 | |
247 | 256 | |
248 | 257 | |
249 | 258 | |
250 | 259 | |
251 | 260 | |
252 | 261 | |
253 | 262 | |
... | ... | @@ -250,58 +259,63 @@ |
250 | 259 | */ |
251 | 260 | |
252 | 261 | int __generic_block_fiemap(struct inode *inode, |
253 | - struct fiemap_extent_info *fieinfo, u64 start, | |
254 | - u64 len, get_block_t *get_block) | |
262 | + struct fiemap_extent_info *fieinfo, loff_t start, | |
263 | + loff_t len, get_block_t *get_block) | |
255 | 264 | { |
256 | - struct buffer_head tmp; | |
257 | - unsigned long long start_blk; | |
258 | - long long length = 0, map_len = 0; | |
265 | + struct buffer_head map_bh; | |
266 | + sector_t start_blk, last_blk; | |
267 | + loff_t isize = i_size_read(inode); | |
259 | 268 | u64 logical = 0, phys = 0, size = 0; |
260 | 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 | 275 | return ret; |
265 | 276 | |
277 | + /* | |
278 | + * Either the i_mutex or other appropriate locking needs to be held | |
279 | + * since we expect isize to not change at all through the duration of | |
280 | + * this call. | |
281 | + */ | |
282 | + if (len >= isize) { | |
283 | + whole_file = true; | |
284 | + len = isize; | |
285 | + } | |
286 | + | |
266 | 287 | start_blk = logical_to_blk(inode, start); |
288 | + last_blk = logical_to_blk(inode, start + len - 1); | |
267 | 289 | |
268 | - length = (long long)min_t(u64, len, i_size_read(inode)); | |
269 | - if (length < len) | |
270 | - whole_file = 1; | |
271 | - | |
272 | - map_len = length; | |
273 | - | |
274 | 290 | do { |
275 | 291 | /* |
276 | 292 | * we set b_size to the total size we want so it will map as |
277 | 293 | * many contiguous blocks as possible at once |
278 | 294 | */ |
279 | - memset(&tmp, 0, sizeof(struct buffer_head)); | |
280 | - tmp.b_size = map_len; | |
295 | + memset(&map_bh, 0, sizeof(struct buffer_head)); | |
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 | 299 | if (ret) |
284 | 300 | break; |
285 | 301 | |
286 | 302 | /* HOLE */ |
287 | - if (!buffer_mapped(&tmp)) { | |
288 | - length -= blk_to_logical(inode, 1); | |
303 | + if (!buffer_mapped(&map_bh)) { | |
289 | 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 | 308 | * allocated block at the front of the file, and then |
294 | 309 | * nothing but holes up to the end of the file properly, |
295 | 310 | * to make sure that extent at the front gets properly |
296 | 311 | * marked with FIEMAP_EXTENT_LAST |
297 | 312 | */ |
298 | 313 | if (!past_eof && |
299 | - blk_to_logical(inode, start_blk) >= | |
300 | - blk_to_logical(inode, 0)+i_size_read(inode)) | |
314 | + blk_to_logical(inode, start_blk) >= isize) | |
301 | 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 | 319 | * last extent |
306 | 320 | */ |
307 | 321 | if (past_eof && size) { |
308 | 322 | |
309 | 323 | |
... | ... | @@ -309,15 +323,18 @@ |
309 | 323 | ret = fiemap_fill_next_extent(fieinfo, logical, |
310 | 324 | phys, size, |
311 | 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 | 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 | 334 | break; |
318 | 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 | 338 | * map, and it wasn't the entire file, so add the extent |
322 | 339 | * we got last time and exit. |
323 | 340 | * |
... | ... | @@ -331,7 +348,7 @@ |
331 | 348 | * are good to go, just add the extent to the fieinfo |
332 | 349 | * and break |
333 | 350 | */ |
334 | - if (length <= 0 && !whole_file) { | |
351 | + if (start_blk > last_blk && !whole_file) { | |
335 | 352 | ret = fiemap_fill_next_extent(fieinfo, logical, |
336 | 353 | phys, size, |
337 | 354 | flags); |
338 | 355 | |
... | ... | @@ -351,11 +368,10 @@ |
351 | 368 | } |
352 | 369 | |
353 | 370 | logical = blk_to_logical(inode, start_blk); |
354 | - phys = blk_to_logical(inode, tmp.b_blocknr); | |
355 | - size = tmp.b_size; | |
371 | + phys = blk_to_logical(inode, map_bh.b_blocknr); | |
372 | + size = map_bh.b_size; | |
356 | 373 | flags = FIEMAP_EXTENT_MERGED; |
357 | 374 | |
358 | - length -= tmp.b_size; | |
359 | 375 | start_blk += logical_to_blk(inode, size); |
360 | 376 | |
361 | 377 | /* |
362 | 378 | |
... | ... | @@ -363,15 +379,13 @@ |
363 | 379 | * soon as we find a hole that the last extent we found |
364 | 380 | * is marked with FIEMAP_EXTENT_LAST |
365 | 381 | */ |
366 | - if (!past_eof && | |
367 | - logical+size >= | |
368 | - blk_to_logical(inode, 0)+i_size_read(inode)) | |
369 | - past_eof = 1; | |
382 | + if (!past_eof && logical + size >= isize) | |
383 | + past_eof = true; | |
370 | 384 | } |
371 | 385 | cond_resched(); |
372 | 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 | 389 | if (ret == 1) |
376 | 390 | ret = 0; |
377 | 391 |
include/linux/fs.h
... | ... | @@ -2315,8 +2315,9 @@ |
2315 | 2315 | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, |
2316 | 2316 | unsigned long arg); |
2317 | 2317 | extern int __generic_block_fiemap(struct inode *inode, |
2318 | - struct fiemap_extent_info *fieinfo, u64 start, | |
2319 | - u64 len, get_block_t *get_block); | |
2318 | + struct fiemap_extent_info *fieinfo, | |
2319 | + loff_t start, loff_t len, | |
2320 | + get_block_t *get_block); | |
2320 | 2321 | extern int generic_block_fiemap(struct inode *inode, |
2321 | 2322 | struct fiemap_extent_info *fieinfo, u64 start, |
2322 | 2323 | u64 len, get_block_t *get_block); |