aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2014-03-03 08:35:57 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2014-03-03 08:50:12 -0500
commitb50f227bddf110ae4ea2df1ebdf7e282ad481803 (patch)
treee3c968ae81f8ac2c2c425b13543728a32b359d2f /fs/gfs2
parentfcf10d38afd2d39d08bf76c48ff9c12345770678 (diff)
GFS2: Clean up journal extent mapping
This patch fixes a long standing issue in mapping the journal extents. Most journals will consist of only a single extent, and although the cache took account of that by merging extents, it did not actually map large extents, but instead was doing a block by block mapping. Since the journal was only being mapped on mount, this was not normally noticeable. With the updated code, it is now possible to use the same extent mapping system during journal recovery (which will be added in a later patch). This will allow checking of the integrity of the journal before any reply of the journal content is attempted. For this reason the code is moving to bmap.c, since it will be used more widely in due course. An exercise left for the reader is to compare the new function gfs2_map_journal_extents() with gfs2_write_alloc_required() Additionally, should there be a failure, the error reporting is also updated to show more detail about what went wrong. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/bmap.c115
-rw-r--r--fs/gfs2/bmap.h2
-rw-r--r--fs/gfs2/incore.h3
-rw-r--r--fs/gfs2/lops.c4
-rw-r--r--fs/gfs2/ops_fstype.c63
-rw-r--r--fs/gfs2/super.c12
6 files changed, 124 insertions, 75 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index fe0500c0af7a..c62d4b9f51dc 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1328,6 +1328,121 @@ int gfs2_file_dealloc(struct gfs2_inode *ip)
1328} 1328}
1329 1329
1330/** 1330/**
1331 * gfs2_free_journal_extents - Free cached journal bmap info
1332 * @jd: The journal
1333 *
1334 */
1335
1336void gfs2_free_journal_extents(struct gfs2_jdesc *jd)
1337{
1338 struct gfs2_journal_extent *jext;
1339
1340 while(!list_empty(&jd->extent_list)) {
1341 jext = list_entry(jd->extent_list.next, struct gfs2_journal_extent, list);
1342 list_del(&jext->list);
1343 kfree(jext);
1344 }
1345}
1346
1347/**
1348 * gfs2_add_jextent - Add or merge a new extent to extent cache
1349 * @jd: The journal descriptor
1350 * @lblock: The logical block at start of new extent
1351 * @pblock: The physical block at start of new extent
1352 * @blocks: Size of extent in fs blocks
1353 *
1354 * Returns: 0 on success or -ENOMEM
1355 */
1356
1357static int gfs2_add_jextent(struct gfs2_jdesc *jd, u64 lblock, u64 dblock, u64 blocks)
1358{
1359 struct gfs2_journal_extent *jext;
1360
1361 if (!list_empty(&jd->extent_list)) {
1362 jext = list_entry(jd->extent_list.prev, struct gfs2_journal_extent, list);
1363 if ((jext->dblock + jext->blocks) == dblock) {
1364 jext->blocks += blocks;
1365 return 0;
1366 }
1367 }
1368
1369 jext = kzalloc(sizeof(struct gfs2_journal_extent), GFP_NOFS);
1370 if (jext == NULL)
1371 return -ENOMEM;
1372 jext->dblock = dblock;
1373 jext->lblock = lblock;
1374 jext->blocks = blocks;
1375 list_add_tail(&jext->list, &jd->extent_list);
1376 jd->nr_extents++;
1377 return 0;
1378}
1379
1380/**
1381 * gfs2_map_journal_extents - Cache journal bmap info
1382 * @sdp: The super block
1383 * @jd: The journal to map
1384 *
1385 * Create a reusable "extent" mapping from all logical
1386 * blocks to all physical blocks for the given journal. This will save
1387 * us time when writing journal blocks. Most journals will have only one
1388 * extent that maps all their logical blocks. That's because gfs2.mkfs
1389 * arranges the journal blocks sequentially to maximize performance.
1390 * So the extent would map the first block for the entire file length.
1391 * However, gfs2_jadd can happen while file activity is happening, so
1392 * those journals may not be sequential. Less likely is the case where
1393 * the users created their own journals by mounting the metafs and
1394 * laying it out. But it's still possible. These journals might have
1395 * several extents.
1396 *
1397 * Returns: 0 on success, or error on failure
1398 */
1399
1400int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
1401{
1402 u64 lblock = 0;
1403 u64 lblock_stop;
1404 struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
1405 struct buffer_head bh;
1406 unsigned int shift = sdp->sd_sb.sb_bsize_shift;
1407 u64 size;
1408 int rc;
1409
1410 lblock_stop = i_size_read(jd->jd_inode) >> shift;
1411 size = (lblock_stop - lblock) << shift;
1412 jd->nr_extents = 0;
1413 WARN_ON(!list_empty(&jd->extent_list));
1414
1415 do {
1416 bh.b_state = 0;
1417 bh.b_blocknr = 0;
1418 bh.b_size = size;
1419 rc = gfs2_block_map(jd->jd_inode, lblock, &bh, 0);
1420 if (rc || !buffer_mapped(&bh))
1421 goto fail;
1422 rc = gfs2_add_jextent(jd, lblock, bh.b_blocknr, bh.b_size >> shift);
1423 if (rc)
1424 goto fail;
1425 size -= bh.b_size;
1426 lblock += (bh.b_size >> ip->i_inode.i_blkbits);
1427 } while(size > 0);
1428
1429 fs_info(sdp, "journal %d mapped with %u extents\n", jd->jd_jid,
1430 jd->nr_extents);
1431 return 0;
1432
1433fail:
1434 fs_warn(sdp, "error %d mapping journal %u at offset %llu (extent %u)\n",
1435 rc, jd->jd_jid,
1436 (unsigned long long)(i_size_read(jd->jd_inode) - size),
1437 jd->nr_extents);
1438 fs_warn(sdp, "bmap=%d lblock=%llu block=%llu, state=0x%08lx, size=%llu\n",
1439 rc, (unsigned long long)lblock, (unsigned long long)bh.b_blocknr,
1440 bh.b_state, (unsigned long long)bh.b_size);
1441 gfs2_free_journal_extents(jd);
1442 return rc;
1443}
1444
1445/**
1331 * gfs2_write_alloc_required - figure out if a write will require an allocation 1446 * gfs2_write_alloc_required - figure out if a write will require an allocation
1332 * @ip: the file being written to 1447 * @ip: the file being written to
1333 * @offset: the offset to write to 1448 * @offset: the offset to write to
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index 42fea03e2bd9..81ded5e2aaa2 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -55,5 +55,7 @@ extern int gfs2_truncatei_resume(struct gfs2_inode *ip);
55extern int gfs2_file_dealloc(struct gfs2_inode *ip); 55extern int gfs2_file_dealloc(struct gfs2_inode *ip);
56extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, 56extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
57 unsigned int len); 57 unsigned int len);
58extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd);
59extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd);
58 60
59#endif /* __BMAP_DOT_H__ */ 61#endif /* __BMAP_DOT_H__ */
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index d0c3928b2dea..456d8fa9da2b 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -485,7 +485,7 @@ struct gfs2_trans {
485}; 485};
486 486
487struct gfs2_journal_extent { 487struct gfs2_journal_extent {
488 struct list_head extent_list; 488 struct list_head list;
489 489
490 unsigned int lblock; /* First logical block */ 490 unsigned int lblock; /* First logical block */
491 u64 dblock; /* First disk block */ 491 u64 dblock; /* First disk block */
@@ -495,6 +495,7 @@ struct gfs2_journal_extent {
495struct gfs2_jdesc { 495struct gfs2_jdesc {
496 struct list_head jd_list; 496 struct list_head jd_list;
497 struct list_head extent_list; 497 struct list_head extent_list;
498 unsigned int nr_extents;
498 struct work_struct jd_work; 499 struct work_struct jd_work;
499 struct inode *jd_inode; 500 struct inode *jd_inode;
500 unsigned long jd_flags; 501 unsigned long jd_flags;
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 23c6e72f5164..ae1d6352a1eb 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -146,8 +146,8 @@ static u64 gfs2_log_bmap(struct gfs2_sbd *sdp)
146 struct gfs2_journal_extent *je; 146 struct gfs2_journal_extent *je;
147 u64 block; 147 u64 block;
148 148
149 list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) { 149 list_for_each_entry(je, &sdp->sd_jdesc->extent_list, list) {
150 if (lbn >= je->lblock && lbn < je->lblock + je->blocks) { 150 if ((lbn >= je->lblock) && (lbn < (je->lblock + je->blocks))) {
151 block = je->dblock + lbn - je->lblock; 151 block = je->dblock + lbn - je->lblock;
152 gfs2_log_incr_head(sdp); 152 gfs2_log_incr_head(sdp);
153 return block; 153 return block;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 1f855a74a4ec..e0d0db5f7fc6 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -517,67 +517,6 @@ out:
517 return ret; 517 return ret;
518} 518}
519 519
520/**
521 * map_journal_extents - create a reusable "extent" mapping from all logical
522 * blocks to all physical blocks for the given journal. This will save
523 * us time when writing journal blocks. Most journals will have only one
524 * extent that maps all their logical blocks. That's because gfs2.mkfs
525 * arranges the journal blocks sequentially to maximize performance.
526 * So the extent would map the first block for the entire file length.
527 * However, gfs2_jadd can happen while file activity is happening, so
528 * those journals may not be sequential. Less likely is the case where
529 * the users created their own journals by mounting the metafs and
530 * laying it out. But it's still possible. These journals might have
531 * several extents.
532 *
533 * TODO: This should be done in bigger chunks rather than one block at a time,
534 * but since it's only done at mount time, I'm not worried about the
535 * time it takes.
536 */
537static int map_journal_extents(struct gfs2_sbd *sdp)
538{
539 struct gfs2_jdesc *jd = sdp->sd_jdesc;
540 unsigned int lb;
541 u64 db, prev_db; /* logical block, disk block, prev disk block */
542 struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
543 struct gfs2_journal_extent *jext = NULL;
544 struct buffer_head bh;
545 int rc = 0;
546
547 prev_db = 0;
548
549 for (lb = 0; lb < i_size_read(jd->jd_inode) >> sdp->sd_sb.sb_bsize_shift; lb++) {
550 bh.b_state = 0;
551 bh.b_blocknr = 0;
552 bh.b_size = 1 << ip->i_inode.i_blkbits;
553 rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
554 db = bh.b_blocknr;
555 if (rc || !db) {
556 printk(KERN_INFO "GFS2 journal mapping error %d: lb="
557 "%u db=%llu\n", rc, lb, (unsigned long long)db);
558 break;
559 }
560 if (!prev_db || db != prev_db + 1) {
561 jext = kzalloc(sizeof(struct gfs2_journal_extent),
562 GFP_KERNEL);
563 if (!jext) {
564 printk(KERN_INFO "GFS2 error: out of memory "
565 "mapping journal extents.\n");
566 rc = -ENOMEM;
567 break;
568 }
569 jext->dblock = db;
570 jext->lblock = lb;
571 jext->blocks = 1;
572 list_add_tail(&jext->extent_list, &jd->extent_list);
573 } else {
574 jext->blocks++;
575 }
576 prev_db = db;
577 }
578 return rc;
579}
580
581static void gfs2_others_may_mount(struct gfs2_sbd *sdp) 520static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
582{ 521{
583 char *message = "FIRSTMOUNT=Done"; 522 char *message = "FIRSTMOUNT=Done";
@@ -779,7 +718,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
779 atomic_set(&sdp->sd_log_thresh2, 4*sdp->sd_jdesc->jd_blocks/5); 718 atomic_set(&sdp->sd_log_thresh2, 4*sdp->sd_jdesc->jd_blocks/5);
780 719
781 /* Map the extents for this journal's blocks */ 720 /* Map the extents for this journal's blocks */
782 map_journal_extents(sdp); 721 gfs2_map_journal_extents(sdp, sdp->sd_jdesc);
783 } 722 }
784 trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free)); 723 trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free));
785 724
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 60f60f6181f3..25747440ebbb 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -295,9 +295,8 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
295 295
296void gfs2_jindex_free(struct gfs2_sbd *sdp) 296void gfs2_jindex_free(struct gfs2_sbd *sdp)
297{ 297{
298 struct list_head list, *head; 298 struct list_head list;
299 struct gfs2_jdesc *jd; 299 struct gfs2_jdesc *jd;
300 struct gfs2_journal_extent *jext;
301 300
302 spin_lock(&sdp->sd_jindex_spin); 301 spin_lock(&sdp->sd_jindex_spin);
303 list_add(&list, &sdp->sd_jindex_list); 302 list_add(&list, &sdp->sd_jindex_list);
@@ -307,14 +306,7 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
307 306
308 while (!list_empty(&list)) { 307 while (!list_empty(&list)) {
309 jd = list_entry(list.next, struct gfs2_jdesc, jd_list); 308 jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
310 head = &jd->extent_list; 309 gfs2_free_journal_extents(jd);
311 while (!list_empty(head)) {
312 jext = list_entry(head->next,
313 struct gfs2_journal_extent,
314 extent_list);
315 list_del(&jext->extent_list);
316 kfree(jext);
317 }
318 list_del(&jd->jd_list); 310 list_del(&jd->jd_list);
319 iput(jd->jd_inode); 311 iput(jd->jd_inode);
320 kfree(jd); 312 kfree(jd);