aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/bmap.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-05-05 16:59:11 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-05-05 16:59:11 -0400
commitfd88de569b802c4a04aaa6ee74667775f4aed8c6 (patch)
tree1766c45303798bf289059afc8f117cf8bc784086 /fs/gfs2/bmap.c
parent5bb76af1e089ac186c15c6aa792340d22b63d4b4 (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.c170
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
317static inline uint64_t *metapointer(struct buffer_head *bh, 317static 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
342static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, 346static 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
386int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, 391static 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;
453out:
454 return ERR_PTR(error);
455}
477 456
478 out: 457
458static 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
467static 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; 476int 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
493int 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