diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-05-05 16:59:11 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-05-05 16:59:11 -0400 |
commit | fd88de569b802c4a04aaa6ee74667775f4aed8c6 (patch) | |
tree | 1766c45303798bf289059afc8f117cf8bc784086 /fs/gfs2/bmap.c | |
parent | 5bb76af1e089ac186c15c6aa792340d22b63d4b4 (diff) |
[GFS2] Readpages support
This adds readpages support (and also corrects a small bug in
the readpage error path at the same time). Hopefully this will
improve performance by allowing GFS to submit larger lumps of
I/O at a time.
In order to simplify the setting of BH_Boundary, it currently gets
set when we hit the end of a indirect pointer block. There is
always a boundary at this point with the current allocation code.
It doesn't get all the boundaries right though, so there is still
room for improvement in this.
See comments in fs/gfs2/ops_address.c for further information about
readpages with GFS2.
Signed-off-by: Steven Whitehouse
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 170 |
1 files changed, 108 insertions, 62 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cfe1a428c668..474b9a16f0f5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block, | |||
314 | * metadata tree. | 314 | * metadata tree. |
315 | */ | 315 | */ |
316 | 316 | ||
317 | static inline uint64_t *metapointer(struct buffer_head *bh, | 317 | static inline u64 *metapointer(struct buffer_head *bh, int *boundary, |
318 | unsigned int height, struct metapath *mp) | 318 | unsigned int height, const struct metapath *mp) |
319 | { | 319 | { |
320 | unsigned int head_size = (height > 0) ? | 320 | unsigned int head_size = (height > 0) ? |
321 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); | 321 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); |
322 | 322 | u64 *ptr; | |
323 | return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height]; | 323 | *boundary = 0; |
324 | ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height]; | ||
325 | if (ptr + 1 == (u64*)(bh->b_data + bh->b_size)) | ||
326 | *boundary = 1; | ||
327 | return ptr; | ||
324 | } | 328 | } |
325 | 329 | ||
326 | /** | 330 | /** |
@@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh, | |||
339 | * | 343 | * |
340 | */ | 344 | */ |
341 | 345 | ||
342 | static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | 346 | static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, |
343 | unsigned int height, struct metapath *mp, int create, | 347 | unsigned int height, struct metapath *mp, int create, |
344 | int *new, uint64_t *block) | 348 | int *new, uint64_t *block) |
345 | { | 349 | { |
346 | uint64_t *ptr = metapointer(bh, height, mp); | 350 | int boundary; |
351 | uint64_t *ptr = metapointer(bh, &boundary, height, mp); | ||
347 | 352 | ||
348 | if (*ptr) { | 353 | if (*ptr) { |
349 | *block = be64_to_cpu(*ptr); | 354 | *block = be64_to_cpu(*ptr); |
350 | return; | 355 | return boundary; |
351 | } | 356 | } |
352 | 357 | ||
353 | *block = 0; | 358 | *block = 0; |
354 | 359 | ||
355 | if (!create) | 360 | if (!create) |
356 | return; | 361 | return 0; |
357 | 362 | ||
358 | if (height == ip->i_di.di_height - 1 && | 363 | if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) |
359 | !gfs2_is_dir(ip)) | ||
360 | *block = gfs2_alloc_data(ip); | 364 | *block = gfs2_alloc_data(ip); |
361 | else | 365 | else |
362 | *block = gfs2_alloc_meta(ip); | 366 | *block = gfs2_alloc_meta(ip); |
@@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
367 | ip->i_di.di_blocks++; | 371 | ip->i_di.di_blocks++; |
368 | 372 | ||
369 | *new = 1; | 373 | *new = 1; |
374 | return 0; | ||
370 | } | 375 | } |
371 | 376 | ||
372 | /** | 377 | /** |
373 | * gfs2_block_map - Map a block from an inode to a disk block | 378 | * gfs2_block_pointers - Map a block from an inode to a disk block |
374 | * @ip: The GFS2 inode | 379 | * @inode: The inode |
375 | * @lblock: The logical block number | 380 | * @lblock: The logical block number |
376 | * @new: Value/Result argument (1 = may create/did create new blocks) | 381 | * @new: Value/Result argument (1 = may create/did create new blocks) |
377 | * @dblock: the disk block number of the start of an extent | 382 | * @boundary: gets set if we've hit a block boundary |
378 | * @extlen: the size of the extent | 383 | * @mp: metapath to use |
379 | * | 384 | * |
380 | * Find the block number on the current device which corresponds to an | 385 | * Find the block number on the current device which corresponds to an |
381 | * inode's block. If the block had to be created, "new" will be set. | 386 | * inode's block. If the block had to be created, "new" will be set. |
@@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
383 | * Returns: errno | 388 | * Returns: errno |
384 | */ | 389 | */ |
385 | 390 | ||
386 | int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | 391 | static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, |
387 | uint64_t *dblock, uint32_t *extlen) | 392 | int *new, u64 *dblock, |
393 | int *boundary, | ||
394 | struct metapath *mp) | ||
388 | { | 395 | { |
396 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
389 | struct gfs2_sbd *sdp = ip->i_sbd; | 397 | struct gfs2_sbd *sdp = ip->i_sbd; |
390 | struct buffer_head *bh; | 398 | struct buffer_head *bh; |
391 | struct metapath mp; | ||
392 | int create = *new; | 399 | int create = *new; |
393 | unsigned int bsize; | 400 | unsigned int bsize; |
394 | unsigned int height; | 401 | unsigned int height; |
@@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
398 | 405 | ||
399 | *new = 0; | 406 | *new = 0; |
400 | *dblock = 0; | 407 | *dblock = 0; |
401 | if (extlen) | ||
402 | *extlen = 0; | ||
403 | |||
404 | if (create) | ||
405 | down_write(&ip->i_rw_mutex); | ||
406 | else | ||
407 | down_read(&ip->i_rw_mutex); | ||
408 | 408 | ||
409 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) | 409 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) |
410 | goto out; | 410 | goto out; |
@@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
421 | goto out; | 421 | goto out; |
422 | } | 422 | } |
423 | 423 | ||
424 | find_metapath(ip, lblock, &mp); | 424 | find_metapath(ip, lblock, mp); |
425 | end_of_metadata = ip->i_di.di_height - 1; | 425 | end_of_metadata = ip->i_di.di_height - 1; |
426 | 426 | ||
427 | error = gfs2_meta_inode_buffer(ip, &bh); | 427 | error = gfs2_meta_inode_buffer(ip, &bh); |
@@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
429 | goto out; | 429 | goto out; |
430 | 430 | ||
431 | for (x = 0; x < end_of_metadata; x++) { | 431 | for (x = 0; x < end_of_metadata; x++) { |
432 | lookup_block(ip, bh, x, &mp, create, new, dblock); | 432 | lookup_block(ip, bh, x, mp, create, new, dblock); |
433 | brelse(bh); | 433 | brelse(bh); |
434 | if (!*dblock) | 434 | if (!*dblock) |
435 | goto out; | 435 | goto out; |
@@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
439 | goto out; | 439 | goto out; |
440 | } | 440 | } |
441 | 441 | ||
442 | lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock); | 442 | *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock); |
443 | |||
444 | if (extlen && *dblock) { | ||
445 | *extlen = 1; | ||
446 | |||
447 | if (!*new) { | ||
448 | uint64_t tmp_dblock; | ||
449 | int tmp_new; | ||
450 | unsigned int nptrs; | ||
451 | |||
452 | nptrs = (end_of_metadata) ? sdp->sd_inptrs : | ||
453 | sdp->sd_diptrs; | ||
454 | |||
455 | while (++mp.mp_list[end_of_metadata] < nptrs) { | ||
456 | lookup_block(ip, bh, end_of_metadata, &mp, | ||
457 | 0, &tmp_new, &tmp_dblock); | ||
458 | |||
459 | if (*dblock + *extlen != tmp_dblock) | ||
460 | break; | ||
461 | |||
462 | (*extlen)++; | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | |||
467 | brelse(bh); | ||
468 | |||
469 | if (*new) { | 443 | if (*new) { |
470 | error = gfs2_meta_inode_buffer(ip, &bh); | 444 | struct buffer_head *dibh; |
445 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
471 | if (!error) { | 446 | if (!error) { |
472 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | 447 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
473 | gfs2_dinode_out(&ip->i_di, bh->b_data); | 448 | gfs2_dinode_out(&ip->i_di, dibh->b_data); |
474 | brelse(bh); | 449 | brelse(dibh); |
475 | } | 450 | } |
476 | } | 451 | } |
452 | return bh; | ||
453 | out: | ||
454 | return ERR_PTR(error); | ||
455 | } | ||
477 | 456 | ||
478 | out: | 457 | |
458 | static inline void bmap_lock(struct inode *inode, int create) | ||
459 | { | ||
460 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
461 | if (create) | ||
462 | down_write(&ip->i_rw_mutex); | ||
463 | else | ||
464 | down_read(&ip->i_rw_mutex); | ||
465 | } | ||
466 | |||
467 | static inline void bmap_unlock(struct inode *inode, int create) | ||
468 | { | ||
469 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
479 | if (create) | 470 | if (create) |
480 | up_write(&ip->i_rw_mutex); | 471 | up_write(&ip->i_rw_mutex); |
481 | else | 472 | else |
482 | up_read(&ip->i_rw_mutex); | 473 | up_read(&ip->i_rw_mutex); |
474 | } | ||
483 | 475 | ||
484 | return error; | 476 | int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) |
477 | { | ||
478 | struct metapath mp; | ||
479 | struct buffer_head *bh; | ||
480 | int create = *new; | ||
481 | |||
482 | bmap_lock(inode, create); | ||
483 | bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp); | ||
484 | bmap_unlock(inode, create); | ||
485 | if (!bh) | ||
486 | return 0; | ||
487 | if (IS_ERR(bh)) | ||
488 | return PTR_ERR(bh); | ||
489 | brelse(bh); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) | ||
494 | { | ||
495 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
496 | struct gfs2_sbd *sdp = ip->i_sbd; | ||
497 | struct metapath mp; | ||
498 | struct buffer_head *bh; | ||
499 | int boundary; | ||
500 | int create = *new; | ||
501 | |||
502 | BUG_ON(!extlen); | ||
503 | BUG_ON(!dblock); | ||
504 | BUG_ON(!new); | ||
505 | |||
506 | bmap_lock(inode, create); | ||
507 | bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); | ||
508 | *extlen = 1; | ||
509 | |||
510 | if (bh && !IS_ERR(bh) && *dblock && !*new) { | ||
511 | u64 tmp_dblock; | ||
512 | int tmp_new; | ||
513 | unsigned int nptrs; | ||
514 | unsigned end_of_metadata = ip->i_di.di_height - 1; | ||
515 | |||
516 | nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs; | ||
517 | while (++mp.mp_list[end_of_metadata] < nptrs) { | ||
518 | lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock); | ||
519 | if (*dblock + *extlen != tmp_dblock) | ||
520 | break; | ||
521 | (*extlen)++; | ||
522 | } | ||
523 | } | ||
524 | bmap_unlock(inode, create); | ||
525 | if (!bh) | ||
526 | return 0; | ||
527 | if (IS_ERR(bh)) | ||
528 | return PTR_ERR(bh); | ||
529 | brelse(bh); | ||
530 | return 0; | ||
485 | } | 531 | } |
486 | 532 | ||
487 | /** | 533 | /** |
@@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, | |||
1053 | } | 1099 | } |
1054 | 1100 | ||
1055 | for (; lblock < lblock_stop; lblock += extlen) { | 1101 | for (; lblock < lblock_stop; lblock += extlen) { |
1056 | error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); | 1102 | error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); |
1057 | if (error) | 1103 | if (error) |
1058 | return error; | 1104 | return error; |
1059 | 1105 | ||