aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Peterson <rpeterso@redhat.com>2007-05-09 10:37:57 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-07-09 03:22:12 -0400
commit7ae8fa8451dfb3879ecbc04f2760a707dc65b988 (patch)
tree568b3b6b8a1b39d0e4177d81d2e8262cbafa4fa4
parent3168b0780d06ace875696f8a648d04d6089654e5 (diff)
[GFS2] kernel changes to support new gfs2_grow command
This is another revision of my gfs2 kernel patch that allows gfs2_grow to function properly. Steve Whitehouse expressed some concerns about the previous patch and I restructured it based on his comments. The previous patch was doing the statfs_change at file close time, under its own transaction. The current patch does the statfs_change inside the gfs2_commit_write function, which keeps it under the umbrella of the inode transaction. I can't call ri_update to re-read the rindex file during the transaction because the transaction may have outstanding unwritten buffers attached to the rgrps that would be otherwise blown away. So instead, I created a new function, gfs2_ri_total, that will re-read the rindex file just to total the file system space for the sake of the statfs_change. The ri_update will happen later, when gfs2 realizes the version number has changed, as it happened before my patch. Since the statfs_change is happening at write_commit time and there may be multiple writes to the rindex file for one grow operation. So one consequence of this restructuring is that instead of getting one kernel message to indicate the change, you may see several. For example, before when you did a gfs2_grow, you'd get a single message like: GFS2: File system extended by 247876 blocks (968MB) Now you get something like: GFS2: File system extended by 207896 blocks (812MB) GFS2: File system extended by 39980 blocks (156MB) This version has also been successfully run against the hours-long "gfs2_fsck_hellfire" test that does several gfs2_grow and gfs2_fsck while interjecting file system damage. It does this repeatedly under a variety Resource Group conditions. Signed-off-By: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/ops_address.c29
-rw-r--r--fs/gfs2/ops_address.h5
-rw-r--r--fs/gfs2/rgrp.c60
3 files changed, 86 insertions, 8 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 30c15622174f..846c0ff75cff 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.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
@@ -450,6 +450,30 @@ out_uninit:
450} 450}
451 451
452/** 452/**
453 * adjust_fs_space - Adjusts the free space available due to gfs2_grow
454 * @inode: the rindex inode
455 */
456static void adjust_fs_space(struct inode *inode)
457{
458 struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
459 struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
460 struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
461 u64 fs_total, new_free;
462
463 /* Total up the file system space, according to the latest rindex. */
464 fs_total = gfs2_ri_total(sdp);
465
466 spin_lock(&sdp->sd_statfs_spin);
467 if (fs_total > (m_sc->sc_total + l_sc->sc_total))
468 new_free = fs_total - (m_sc->sc_total + l_sc->sc_total);
469 else
470 new_free = 0;
471 spin_unlock(&sdp->sd_statfs_spin);
472 fs_warn(sdp, "File system extended by %llu blocks.\n", new_free);
473 gfs2_statfs_change(sdp, new_free, new_free, 0);
474}
475
476/**
453 * gfs2_commit_write - Commit write to a file 477 * gfs2_commit_write - Commit write to a file
454 * @file: The file to write to 478 * @file: The file to write to
455 * @page: The page containing the data 479 * @page: The page containing the data
@@ -511,6 +535,9 @@ static int gfs2_commit_write(struct file *file, struct page *page,
511 di->di_size = cpu_to_be64(inode->i_size); 535 di->di_size = cpu_to_be64(inode->i_size);
512 } 536 }
513 537
538 if (inode == sdp->sd_rindex)
539 adjust_fs_space(inode);
540
514 brelse(dibh); 541 brelse(dibh);
515 gfs2_trans_end(sdp); 542 gfs2_trans_end(sdp);
516 if (al->al_requested) { 543 if (al->al_requested) {
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
index 35aaee4aa7e1..56c30daf895b 100644
--- a/fs/gfs2/ops_address.h
+++ b/fs/gfs2/ops_address.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
@@ -18,5 +18,8 @@ extern const struct address_space_operations gfs2_file_aops;
18extern int gfs2_get_block(struct inode *inode, sector_t lblock, 18extern int gfs2_get_block(struct inode *inode, sector_t lblock,
19 struct buffer_head *bh_result, int create); 19 struct buffer_head *bh_result, int create);
20extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); 20extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
21extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
22extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
23 s64 dinodes);
21 24
22#endif /* __OPS_ADDRESS_DOT_H__ */ 25#endif /* __OPS_ADDRESS_DOT_H__ */
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 1727f5012efe..e857f405353b 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.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
@@ -431,6 +431,38 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd)
431} 431}
432 432
433/** 433/**
434 * gfs2_ri_total - Total up the file system space, according to the rindex.
435 *
436 */
437u64 gfs2_ri_total(struct gfs2_sbd *sdp)
438{
439 u64 total_data = 0;
440 struct inode *inode = sdp->sd_rindex;
441 struct gfs2_inode *ip = GFS2_I(inode);
442 struct gfs2_rindex_host ri;
443 char buf[sizeof(struct gfs2_rindex)];
444 struct file_ra_state ra_state;
445 int error, rgrps;
446
447 mutex_lock(&sdp->sd_rindex_mutex);
448 file_ra_state_init(&ra_state, inode->i_mapping);
449 for (rgrps = 0;; rgrps++) {
450 loff_t pos = rgrps * sizeof(struct gfs2_rindex);
451
452 if (pos + sizeof(struct gfs2_rindex) >= ip->i_di.di_size)
453 break;
454 error = gfs2_internal_read(ip, &ra_state, buf, &pos,
455 sizeof(struct gfs2_rindex));
456 if (error != sizeof(struct gfs2_rindex))
457 break;
458 gfs2_rindex_in(&ri, buf);
459 total_data += ri.ri_data;
460 }
461 mutex_unlock(&sdp->sd_rindex_mutex);
462 return total_data;
463}
464
465/**
434 * gfs2_ri_update - Pull in a new resource index from the disk 466 * gfs2_ri_update - Pull in a new resource index from the disk
435 * @gl: The glock covering the rindex inode 467 * @gl: The glock covering the rindex inode
436 * 468 *
@@ -447,7 +479,12 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
447 u64 junk = ip->i_di.di_size; 479 u64 junk = ip->i_di.di_size;
448 int error; 480 int error;
449 481
450 if (do_div(junk, sizeof(struct gfs2_rindex))) { 482 /* If someone is holding the rindex file with a glock, they must
483 be updating it, in which case we may have partial entries.
484 In this case, we ignore the partials. */
485 if (!gfs2_glock_is_held_excl(ip->i_gl) &&
486 !gfs2_glock_is_held_shrd(ip->i_gl) &&
487 do_div(junk, sizeof(struct gfs2_rindex))) {
451 gfs2_consist_inode(ip); 488 gfs2_consist_inode(ip);
452 return -EIO; 489 return -EIO;
453 } 490 }
@@ -457,6 +494,9 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
457 file_ra_state_init(&ra_state, inode->i_mapping); 494 file_ra_state_init(&ra_state, inode->i_mapping);
458 for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { 495 for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
459 loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex); 496 loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
497
498 if (pos + sizeof(struct gfs2_rindex) >= ip->i_di.di_size)
499 break;
460 error = gfs2_internal_read(ip, &ra_state, buf, &pos, 500 error = gfs2_internal_read(ip, &ra_state, buf, &pos,
461 sizeof(struct gfs2_rindex)); 501 sizeof(struct gfs2_rindex));
462 if (!error) 502 if (!error)
@@ -978,18 +1018,25 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
978{ 1018{
979 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 1019 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
980 struct gfs2_alloc *al = &ip->i_alloc; 1020 struct gfs2_alloc *al = &ip->i_alloc;
981 int error; 1021 int error = 0;
982 1022
983 if (gfs2_assert_warn(sdp, al->al_requested)) 1023 if (gfs2_assert_warn(sdp, al->al_requested))
984 return -EINVAL; 1024 return -EINVAL;
985 1025
986 error = gfs2_rindex_hold(sdp, &al->al_ri_gh); 1026 /* We need to hold the rindex unless the inode we're using is
1027 the rindex itself, in which case it's already held. */
1028 if (ip != GFS2_I(sdp->sd_rindex))
1029 error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
1030 else if (!sdp->sd_rgrps) /* We may not have the rindex read in, so: */
1031 error = gfs2_ri_update(ip);
1032
987 if (error) 1033 if (error)
988 return error; 1034 return error;
989 1035
990 error = get_local_rgrp(ip); 1036 error = get_local_rgrp(ip);
991 if (error) { 1037 if (error) {
992 gfs2_glock_dq_uninit(&al->al_ri_gh); 1038 if (ip != GFS2_I(sdp->sd_rindex))
1039 gfs2_glock_dq_uninit(&al->al_ri_gh);
993 return error; 1040 return error;
994 } 1041 }
995 1042
@@ -1019,7 +1066,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
1019 1066
1020 al->al_rgd = NULL; 1067 al->al_rgd = NULL;
1021 gfs2_glock_dq_uninit(&al->al_rgd_gh); 1068 gfs2_glock_dq_uninit(&al->al_rgd_gh);
1022 gfs2_glock_dq_uninit(&al->al_ri_gh); 1069 if (ip != GFS2_I(sdp->sd_rindex))
1070 gfs2_glock_dq_uninit(&al->al_ri_gh);
1023} 1071}
1024 1072
1025/** 1073/**