Commit da6dd40d59fa9617ed697b90114e197036901632

Authored by Bob Peterson
Committed by Steven Whitehouse
1 parent e9e1ef2b6e

[GFS2] Journal extent mapping

This patch saves a little time when gfs2 writes to the journals by
keeping a mapping between logical and physical blocks on disk.
That's better than constantly looking up indirect pointers in
buffers, when the journals are several levels of indirection
(which they typically are).

Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

Showing 4 changed files with 97 additions and 17 deletions Side-by-side Diff

1 1 /*
2 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3   - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  3 + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 4 *
5 5 * This copyrighted material is made available to anyone wishing to use,
6 6 * modify, copy, or redistribute it subject to the terms and conditions
7 7  
... ... @@ -360,8 +360,17 @@
360 360 u64 ai_sync_gen;
361 361 };
362 362  
  363 +struct gfs2_journal_extent {
  364 + struct list_head extent_list;
  365 +
  366 + unsigned int lblock; /* First logical block */
  367 + u64 dblock; /* First disk block */
  368 + u64 blocks;
  369 +};
  370 +
363 371 struct gfs2_jdesc {
364 372 struct list_head jd_list;
  373 + struct list_head extent_list;
365 374  
366 375 struct inode *jd_inode;
367 376 unsigned int jd_jid;
1 1 /*
2 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3   - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  3 + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 4 *
5 5 * This copyrighted material is made available to anyone wishing to use,
6 6 * modify, copy, or redistribute it subject to the terms and conditions
7 7  
8 8  
... ... @@ -339,18 +339,14 @@
339 339  
340 340 static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
341 341 {
342   - struct inode *inode = sdp->sd_jdesc->jd_inode;
343   - int error;
344   - struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
  342 + struct gfs2_journal_extent *je;
345 343  
346   - bh_map.b_size = 1 << inode->i_blkbits;
347   - error = gfs2_block_map(inode, lbn, &bh_map, 0);
348   - if (error || !bh_map.b_blocknr)
349   - printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error,
350   - (unsigned long long)bh_map.b_blocknr, lbn);
351   - gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
  344 + list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
  345 + if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
  346 + return je->dblock + lbn;
  347 + }
352 348  
353   - return bh_map.b_blocknr;
  349 + return -1;
354 350 }
355 351  
356 352 /**
fs/gfs2/ops_fstype.c
1 1 /*
2 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3   - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  3 + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 4 *
5 5 * This copyrighted material is made available to anyone wishing to use,
6 6 * modify, copy, or redistribute it subject to the terms and conditions
... ... @@ -21,6 +21,7 @@
21 21  
22 22 #include "gfs2.h"
23 23 #include "incore.h"
  24 +#include "bmap.h"
24 25 #include "daemon.h"
25 26 #include "glock.h"
26 27 #include "glops.h"
... ... @@ -302,6 +303,68 @@
302 303 return error;
303 304 }
304 305  
  306 +/**
  307 + * map_journal_extents - create a reusable "extent" mapping from all logical
  308 + * blocks to all physical blocks for the given journal. This will save
  309 + * us time when writing journal blocks. Most journals will have only one
  310 + * extent that maps all their logical blocks. That's because gfs2.mkfs
  311 + * arranges the journal blocks sequentially to maximize performance.
  312 + * So the extent would map the first block for the entire file length.
  313 + * However, gfs2_jadd can happen while file activity is happening, so
  314 + * those journals may not be sequential. Less likely is the case where
  315 + * the users created their own journals by mounting the metafs and
  316 + * laying it out. But it's still possible. These journals might have
  317 + * several extents.
  318 + *
  319 + * TODO: This should be done in bigger chunks rather than one block at a time,
  320 + * but since it's only done at mount time, I'm not worried about the
  321 + * time it takes.
  322 + */
  323 +static int map_journal_extents(struct gfs2_sbd *sdp)
  324 +{
  325 + struct gfs2_jdesc *jd = sdp->sd_jdesc;
  326 + unsigned int lb;
  327 + u64 db, prev_db; /* logical block, disk block, prev disk block */
  328 + struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
  329 + struct gfs2_journal_extent *jext = NULL;
  330 + struct buffer_head bh;
  331 + int rc = 0;
  332 +
  333 + INIT_LIST_HEAD(&jd->extent_list);
  334 + prev_db = 0;
  335 +
  336 + for (lb = 0; lb < ip->i_di.di_size / sdp->sd_sb.sb_bsize; lb++) {
  337 + bh.b_state = 0;
  338 + bh.b_blocknr = 0;
  339 + bh.b_size = 1 << ip->i_inode.i_blkbits;
  340 + rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
  341 + db = bh.b_blocknr;
  342 + if (rc || !db) {
  343 + printk(KERN_INFO "GFS2 journal mapping error %d: lb="
  344 + "%u db=%llu\n", rc, lb, (unsigned long long)db);
  345 + break;
  346 + }
  347 + if (!prev_db || db != prev_db + 1) {
  348 + jext = kzalloc(sizeof(struct gfs2_journal_extent),
  349 + GFP_KERNEL);
  350 + if (!jext) {
  351 + printk(KERN_INFO "GFS2 error: out of memory "
  352 + "mapping journal extents.\n");
  353 + rc = -ENOMEM;
  354 + break;
  355 + }
  356 + jext->dblock = db;
  357 + jext->lblock = lb;
  358 + jext->blocks = 1;
  359 + list_add_tail(&jext->extent_list, &jd->extent_list);
  360 + } else {
  361 + jext->blocks++;
  362 + }
  363 + prev_db = db;
  364 + }
  365 + return rc;
  366 +}
  367 +
305 368 static int init_journal(struct gfs2_sbd *sdp, int undo)
306 369 {
307 370 struct gfs2_holder ji_gh;
... ... @@ -377,6 +440,9 @@
377 440 goto fail_jinode_gh;
378 441 }
379 442 atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
  443 +
  444 + /* Map the extents for this journal's blocks */
  445 + map_journal_extents(sdp);
380 446 }
381 447  
382 448 if (sdp->sd_lockstruct.ls_first) {
1 1 /*
2 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3   - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  3 + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 4 *
5 5 * This copyrighted material is made available to anyone wishing to use,
6 6 * modify, copy, or redistribute it subject to the terms and conditions
7 7  
... ... @@ -416,8 +416,9 @@
416 416  
417 417 void gfs2_jindex_free(struct gfs2_sbd *sdp)
418 418 {
419   - struct list_head list;
  419 + struct list_head list, *head;
420 420 struct gfs2_jdesc *jd;
  421 + struct gfs2_journal_extent *jext;
421 422  
422 423 spin_lock(&sdp->sd_jindex_spin);
423 424 list_add(&list, &sdp->sd_jindex_list);
... ... @@ -427,6 +428,14 @@
427 428  
428 429 while (!list_empty(&list)) {
429 430 jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
  431 + head = &jd->extent_list;
  432 + while (!list_empty(head)) {
  433 + jext = list_entry(head->next,
  434 + struct gfs2_journal_extent,
  435 + extent_list);
  436 + list_del(&jext->extent_list);
  437 + kfree(jext);
  438 + }
430 439 list_del(&jd->jd_list);
431 440 iput(jd->jd_inode);
432 441 kfree(jd);