aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2007-12-11 19:49:21 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2008-01-25 03:11:46 -0500
commitda6dd40d59fa9617ed697b90114e197036901632 (patch)
tree49e869021ed1f911bf3cdf185e9c4ce75c67f42a /fs/gfs2
parente9e1ef2b6ee401d7c1e1eb38052857b4b206d172 (diff)
[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>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/incore.h11
-rw-r--r--fs/gfs2/log.c22
-rw-r--r--fs/gfs2/ops_fstype.c68
-rw-r--r--fs/gfs2/super.c13
4 files changed, 97 insertions, 17 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 330f4c73d0e7..51166c12c5d7 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 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 * This copyrighted material is made available to anyone wishing to use, 5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions 6 * modify, copy, or redistribute it subject to the terms and conditions
@@ -360,8 +360,17 @@ struct gfs2_ail {
360 u64 ai_sync_gen; 360 u64 ai_sync_gen;
361}; 361};
362 362
363struct 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
363struct gfs2_jdesc { 371struct gfs2_jdesc {
364 struct list_head jd_list; 372 struct list_head jd_list;
373 struct list_head extent_list;
365 374
366 struct inode *jd_inode; 375 struct inode *jd_inode;
367 unsigned int jd_jid; 376 unsigned int jd_jid;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 14333d81cf7d..69a583ec43c7 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 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 * This copyrighted material is made available to anyone wishing to use, 5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions 6 * modify, copy, or redistribute it subject to the terms and conditions
@@ -339,18 +339,14 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
339 339
340static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) 340static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
341{ 341{
342 struct inode *inode = sdp->sd_jdesc->jd_inode; 342 struct gfs2_journal_extent *je;
343 int error; 343
344 struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; 344 list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
345 345 if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
346 bh_map.b_size = 1 << inode->i_blkbits; 346 return je->dblock + lbn;
347 error = gfs2_block_map(inode, lbn, &bh_map, 0); 347 }
348 if (error || !bh_map.b_blocknr) 348
349 printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, 349 return -1;
350 (unsigned long long)bh_map.b_blocknr, lbn);
351 gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
352
353 return bh_map.b_blocknr;
354} 350}
355 351
356/** 352/**
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 1bba6ac0bcac..0921f17a164c 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 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 * This copyrighted material is made available to anyone wishing to use, 5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions 6 * modify, copy, or redistribute it subject to the terms and conditions
@@ -21,6 +21,7 @@
21 21
22#include "gfs2.h" 22#include "gfs2.h"
23#include "incore.h" 23#include "incore.h"
24#include "bmap.h"
24#include "daemon.h" 25#include "daemon.h"
25#include "glock.h" 26#include "glock.h"
26#include "glops.h" 27#include "glops.h"
@@ -302,6 +303,68 @@ out:
302 return error; 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 */
323static 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
305static int init_journal(struct gfs2_sbd *sdp, int undo) 368static int init_journal(struct gfs2_sbd *sdp, int undo)
306{ 369{
307 struct gfs2_holder ji_gh; 370 struct gfs2_holder ji_gh;
@@ -377,6 +440,9 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
377 goto fail_jinode_gh; 440 goto fail_jinode_gh;
378 } 441 }
379 atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); 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 if (sdp->sd_lockstruct.ls_first) { 448 if (sdp->sd_lockstruct.ls_first) {
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 2e74792ee487..22e09660d648 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 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 * This copyrighted material is made available to anyone wishing to use, 5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions 6 * modify, copy, or redistribute it subject to the terms and conditions
@@ -416,8 +416,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
416 416
417void gfs2_jindex_free(struct gfs2_sbd *sdp) 417void gfs2_jindex_free(struct gfs2_sbd *sdp)
418{ 418{
419 struct list_head list; 419 struct list_head list, *head;
420 struct gfs2_jdesc *jd; 420 struct gfs2_jdesc *jd;
421 struct gfs2_journal_extent *jext;
421 422
422 spin_lock(&sdp->sd_jindex_spin); 423 spin_lock(&sdp->sd_jindex_spin);
423 list_add(&list, &sdp->sd_jindex_list); 424 list_add(&list, &sdp->sd_jindex_list);
@@ -427,6 +428,14 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
427 428
428 while (!list_empty(&list)) { 429 while (!list_empty(&list)) {
429 jd = list_entry(list.next, struct gfs2_jdesc, jd_list); 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 list_del(&jd->jd_list); 439 list_del(&jd->jd_list);
431 iput(jd->jd_inode); 440 iput(jd->jd_inode);
432 kfree(jd); 441 kfree(jd);