From 941e6d7d09aaf455c0d7ad383f7f5ae67e4ccf16 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Jan 2008 08:47:38 +0000 Subject: [GFS2] Speed up gfs2_write_alloc_required, deprecate gfs2_extent_map This patch removes the call to gfs2_extent_map from gfs2_write_alloc_required, instead we call gfs2_block_map directly. This results in fewer overall calls to gfs2_block_map in the multi-block case. Also, gfs2_extent_map is marked as deprecated so that people know that its going away as soon as all the callers have been converted. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e9456ebd3bb..a25444ac648 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -548,6 +548,9 @@ out_fail: return error; } +/* + * Deprecated: do not use in new code + */ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) { struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; @@ -1197,10 +1200,9 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, unsigned int len, int *alloc_required) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - u64 lblock, lblock_stop, dblock; - u32 extlen; - int new = 0; - int error = 0; + struct buffer_head bh; + unsigned int shift; + u64 lblock, lblock_stop, size; *alloc_required = 0; @@ -1214,6 +1216,8 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, return 0; } + *alloc_required = 1; + shift = sdp->sd_sb.sb_bsize_shift; if (gfs2_is_dir(ip)) { unsigned int bsize = sdp->sd_jbsize; lblock = offset; @@ -1221,27 +1225,25 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, lblock_stop = offset + len + bsize - 1; do_div(lblock_stop, bsize); } else { - unsigned int shift = sdp->sd_sb.sb_bsize_shift; u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift; lblock = offset >> shift; lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; - if (lblock_stop > end_of_file) { - *alloc_required = 1; + if (lblock_stop > end_of_file) return 0; - } } - for (; lblock < lblock_stop; lblock += extlen) { - error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); - if (error) - return error; - - if (!dblock) { - *alloc_required = 1; + size = (lblock_stop - lblock) << shift; + do { + bh.b_state = 0; + bh.b_size = size; + gfs2_block_map(&ip->i_inode, lblock, &bh, 0); + if (!buffer_mapped(&bh)) return 0; - } - } + size -= bh.b_size; + lblock += (bh.b_size >> ip->i_inode.i_blkbits); + } while(size > 0); + *alloc_required = 0; return 0; } -- cgit v1.2.3-70-g09d2 From ecc30c79157103e8bd7492043ee992b763443832 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Jan 2008 10:37:35 +0000 Subject: [GFS2] Streamline indirect pointer tree height calculation This patch improves the calculation of the tree height in order to reduce the number of operations which are carried out on each call to gfs2_block_map. In the common case, we now make a single comparison, rather than calculating the required tree height from scratch each time. Also in the case that the tree does need some extra height, we start from the current height rather from zero when we work out what the new height ought to be. In addition the di_height field is moved into the inode proper and reduced in size to a u8 since the value must be between 0 and GFS2_MAX_META_HEIGHT (10). Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 108 +++++++++++++++++++------------------------------------ fs/gfs2/incore.h | 6 ++-- fs/gfs2/inode.c | 20 ++++++----- fs/gfs2/inode.h | 2 +- fs/gfs2/super.c | 2 ++ 5 files changed, 55 insertions(+), 83 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index a25444ac648..5a3187049dd 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -166,7 +166,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); } - ip->i_di.di_height = 1; + ip->i_height = 1; di->di_height = cpu_to_be16(1); out_brelse: @@ -176,43 +176,6 @@ out: return error; } -/** - * calc_tree_height - Calculate the height of a metadata tree - * @ip: The GFS2 inode - * @size: The proposed size of the file - * - * Work out how tall a metadata tree needs to be in order to accommodate a - * file of a particular size. If size is less than the current size of - * the inode, then the current size of the inode is used instead of the - * supplied one. - * - * Returns: the height the tree should be - */ - -static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) -{ - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - u64 *arr; - unsigned int max, height; - - if (ip->i_di.di_size > size) - size = ip->i_di.di_size; - - if (gfs2_is_dir(ip)) { - arr = sdp->sd_jheightsize; - max = sdp->sd_max_jheight; - } else { - arr = sdp->sd_heightsize; - max = sdp->sd_max_height; - } - - for (height = 0; height < max; height++) - if (arr[height] >= size) - break; - - return height; -} - /** * build_height - Build a metadata tree of the requested height * @ip: The GFS2 inode @@ -225,7 +188,7 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) static int build_height(struct inode *inode, unsigned height) { struct gfs2_inode *ip = GFS2_I(inode); - unsigned new_height = height - ip->i_di.di_height; + unsigned new_height = height - ip->i_height; struct buffer_head *dibh; struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; struct gfs2_dinode *di; @@ -234,7 +197,7 @@ static int build_height(struct inode *inode, unsigned height) u64 bn; unsigned n; - if (height <= ip->i_di.di_height) + if (height <= ip->i_height) return 0; error = gfs2_meta_inode_buffer(ip, &dibh); @@ -270,10 +233,10 @@ static int build_height(struct inode *inode, unsigned height) di = (struct gfs2_dinode *)dibh->b_data; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); *(__be64 *)(di + 1) = cpu_to_be64(bn); - ip->i_di.di_height += new_height; + ip->i_height += new_height; ip->i_di.di_blocks += new_height; gfs2_set_inode_blocks(&ip->i_inode); - di->di_height = cpu_to_be16(ip->i_di.di_height); + di->di_height = cpu_to_be16(ip->i_height); di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); brelse(dibh); return error; @@ -345,7 +308,7 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, u64 b = block; unsigned int i; - for (i = ip->i_di.di_height; i--;) + for (i = ip->i_height; i--;) mp->mp_list[i] = do_div(b, sdp->sd_inptrs); } @@ -407,7 +370,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, if (!create) return 0; - if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) + if (height == ip->i_height - 1 && !gfs2_is_dir(ip)) *block = gfs2_alloc_data(ip); else *block = gfs2_alloc_meta(ip); @@ -458,8 +421,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; - unsigned int bsize; - unsigned int height; + unsigned int bsize = sdp->sd_sb.sb_bsize; unsigned int end_of_metadata; unsigned int x; int error = 0; @@ -470,7 +432,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, struct metapath mp; u64 size; struct buffer_head *dibh = NULL; - + const u64 *arr = sdp->sd_heightsize; BUG_ON(maxlen == 0); if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) @@ -480,23 +442,25 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, clear_buffer_mapped(bh_map); clear_buffer_new(bh_map); clear_buffer_boundary(bh_map); - bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; + if (gfs2_is_dir(ip)) { + bsize = sdp->sd_jbsize; + arr = sdp->sd_jheightsize; + } size = (lblock + 1) * bsize; - if (size > ip->i_di.di_size) { - height = calc_tree_height(ip, size); - if (ip->i_di.di_height < height) { - if (!create) - goto out_ok; - - error = build_height(inode, height); - if (error) - goto out_fail; - } + if (size > arr[ip->i_height]) { + u8 height = ip->i_height; + if (!create) + goto out_ok; + while (size > arr[height]) + height++; + error = build_height(inode, height); + if (error) + goto out_fail; } find_metapath(ip, lblock, &mp); - end_of_metadata = ip->i_di.di_height - 1; + end_of_metadata = ip->i_height - 1; error = gfs2_meta_inode_buffer(ip, &bh); if (error) goto out_fail; @@ -624,7 +588,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, if (error) goto out; - if (height < ip->i_di.di_height - 1) + if (height < ip->i_height - 1) for (; top < bottom; top++, first = 0) { if (!*top) continue; @@ -682,7 +646,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, sm->sm_first = 0; } - metadata = (height != ip->i_di.di_height - 1); + metadata = (height != ip->i_height - 1); if (metadata) revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; @@ -807,7 +771,6 @@ static int do_grow(struct gfs2_inode *ip, u64 size) struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct buffer_head *dibh; - unsigned int h; int error; al = gfs2_alloc_get(ip); @@ -833,20 +796,23 @@ static int do_grow(struct gfs2_inode *ip, u64 size) goto out_ipres; if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { + const u64 *arr = sdp->sd_heightsize; if (gfs2_is_stuffed(ip)) { error = gfs2_unstuff_dinode(ip, NULL); if (error) goto out_end_trans; } - h = calc_tree_height(ip, size); - if (ip->i_di.di_height < h) { - down_write(&ip->i_rw_mutex); - error = build_height(&ip->i_inode, h); - up_write(&ip->i_rw_mutex); - if (error) - goto out_end_trans; + down_write(&ip->i_rw_mutex); + if (size > arr[ip->i_height]) { + u8 height = ip->i_height; + while(size > arr[height]) + height++; + error = build_height(&ip->i_inode, height); } + up_write(&ip->i_rw_mutex); + if (error) + goto out_end_trans; } ip->i_di.di_size = size; @@ -989,7 +955,7 @@ out: static int trunc_dealloc(struct gfs2_inode *ip, u64 size) { - unsigned int height = ip->i_di.di_height; + unsigned int height = ip->i_height; u64 lblock; struct metapath mp; int error; @@ -1040,7 +1006,7 @@ static int trunc_end(struct gfs2_inode *ip) goto out; if (!ip->i_di.di_size) { - ip->i_di.di_height = 0; + ip->i_height = 0; ip->i_di.di_goal_meta = ip->i_di.di_goal_data = ip->i_no_addr; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 525dcae352d..43472baa92e 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -246,7 +246,6 @@ struct gfs2_dinode_host { u64 di_goal_data; /* data block goal */ u64 di_generation; /* generation number for NFS */ u32 di_flags; /* GFS2_DIF_... */ - u16 di_height; /* height of metadata */ /* These only apply to directories */ u16 di_depth; /* Number of bits in the table */ u32 di_entries; /* The number of entries in the directory */ @@ -268,6 +267,7 @@ struct gfs2_inode { u64 i_last_rg_alloc; struct rw_semaphore i_rw_mutex; + u8 i_height; }; /* @@ -490,9 +490,9 @@ struct gfs2_sbd { u32 sd_qc_per_block; u32 sd_max_dirres; /* Max blocks needed to add a directory entry */ u32 sd_max_height; /* Max height of a file's metadata tree */ - u64 sd_heightsize[GFS2_MAX_META_HEIGHT]; + u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1]; u32 sd_max_jheight; /* Max height of journaled file's meta tree */ - u64 sd_jheightsize[GFS2_MAX_META_HEIGHT]; + u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1]; struct gfs2_args sd_args; /* Mount arguments */ struct gfs2_tune sd_tune; /* Filesystem tuning structure */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 37725ade3c5..ff66ab7a17c 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -248,12 +248,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) { struct gfs2_dinode_host *di = &ip->i_di; const struct gfs2_dinode *str = buf; + u16 height; - if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - return -EIO; - } + if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) + goto corrupt; ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); ip->i_inode.i_mode = be32_to_cpu(str->di_mode); ip->i_inode.i_rdev = 0; @@ -290,7 +288,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) di->di_flags = be32_to_cpu(str->di_flags); gfs2_set_inode_flags(&ip->i_inode); - di->di_height = be16_to_cpu(str->di_height); + height = be16_to_cpu(str->di_height); + if (unlikely(height > GFS2_MAX_META_HEIGHT)) + goto corrupt; + ip->i_height = (u8)height; di->di_depth = be16_to_cpu(str->di_depth); di->di_entries = be32_to_cpu(str->di_entries); @@ -300,6 +301,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) gfs2_set_aops(&ip->i_inode); return 0; +corrupt: + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(ip); + return -EIO; } /** @@ -1401,7 +1406,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_generation = cpu_to_be64(di->di_generation); str->di_flags = cpu_to_be32(di->di_flags); - str->di_height = cpu_to_be16(di->di_height); + str->di_height = cpu_to_be16(ip->i_height); str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? GFS2_FORMAT_DE : 0); @@ -1430,7 +1435,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); - printk(KERN_INFO " di_height = %u\n", di->di_height); printk(KERN_INFO " di_depth = %u\n", di->di_depth); printk(KERN_INFO " di_entries = %u\n", di->di_entries); printk(KERN_INFO " di_eattr = %llu\n", diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index d4465066261..db738686ca1 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -12,7 +12,7 @@ static inline int gfs2_is_stuffed(const struct gfs2_inode *ip) { - return !ip->i_di.di_height; + return !ip->i_height; } static inline int gfs2_is_jdata(const struct gfs2_inode *ip) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index ef0562c3bc7..88497b0b733 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -316,6 +316,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) sdp->sd_heightsize[x] = space; } sdp->sd_max_height = x; + sdp->sd_heightsize[x] = ~0; gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - @@ -334,6 +335,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) sdp->sd_jheightsize[x] = space; } sdp->sd_max_jheight = x; + sdp->sd_jheightsize[x] = ~0; gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); return 0; -- cgit v1.2.3-70-g09d2 From fe6c991c52a0dd07d4a19d392fd65048226cb1bc Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 11:13:02 -0600 Subject: [GFS2] Get rid of unneeded parameter in gfs2_rlist_alloc This patch removed the unnecessary parameter from function gfs2_rlist_alloc. The parameter was always passed in as 0. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- fs/gfs2/dir.c | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/rgrp.c | 7 +++---- fs/gfs2/rgrp.h | 5 ++--- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 5a3187049dd..e8e48b690ce 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -680,7 +680,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, else goto out; /* Nothing to do */ - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c34709512b1..78c236fb34e 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1894,7 +1894,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, l_blocks++; } - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index bee99704ea1..04febbc17a1 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -1347,7 +1347,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) else goto out; - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 3552110b2e5..7b9d6f1d152 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -1699,8 +1699,7 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, * */ -void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, - int flags) +void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state) { unsigned int x; @@ -1708,7 +1707,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, GFP_NOFS | __GFP_NOFAIL); for (x = 0; x < rlist->rl_rgrps; x++) gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, - state, flags, + state, 0, &rlist->rl_ghs[x]); } diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 149bb161f4b..5683605695f 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -64,8 +64,7 @@ struct gfs2_rgrp_list { void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, u64 block); -void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, - int flags); +void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state); void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); u64 gfs2_ri_total(struct gfs2_sbd *sdp); -- cgit v1.2.3-70-g09d2 From ca390601a8bbb4ab8301a9469d23cdb1cf77e7cb Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 11:15:57 -0600 Subject: [GFS2] Fix debug inode printing I noticed that the latest change to i_height got rid of the value from the inode dump. This patch adds it back. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index ff66ab7a17c..db5961a9aa5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -1435,6 +1435,7 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); + printk(KERN_INFO " i_height = %u\n", ip->i_height); printk(KERN_INFO " di_depth = %u\n", di->di_depth); printk(KERN_INFO " di_entries = %u\n", di->di_entries); printk(KERN_INFO " di_eattr = %llu\n", -- cgit v1.2.3-70-g09d2 From d0109bfa84d6603becac8c2e87b3716f557f2039 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 11:20:10 -0600 Subject: [GFS2] Only do lo_incore_commit once This patch is performance related. When we're doing a log flush, I noticed we were calling buf_lo_incore_commit twice: once for data bufs and once for metadata bufs. Since this is the same function and does the same thing in both cases, there should be no reason to call it twice. Since we only need to call it once, we can also make it faster by removing it from the generic "lops" code and making it a stand-along static function. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 1 - fs/gfs2/log.c | 17 ++++++++++++++++- fs/gfs2/lops.c | 17 ----------------- fs/gfs2/lops.h | 11 +---------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 43472baa92e..7ae12d2b626 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -44,7 +44,6 @@ struct gfs2_log_header_host { struct gfs2_log_operations { void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le); - void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr); void (*lo_before_commit) (struct gfs2_sbd *sdp); void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai); void (*lo_before_scan) (struct gfs2_jdesc *jd, diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 161ab6f2058..b335304fc5d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -779,6 +779,21 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) gfs2_log_unlock(sdp); } +static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) +{ + struct list_head *head = &tr->tr_list_buf; + struct gfs2_bufdata *bd; + + gfs2_log_lock(sdp); + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr); + list_del_init(&bd->bd_list_tr); + tr->tr_num_buf--; + } + gfs2_log_unlock(sdp); + gfs2_assert_warn(sdp, !tr->tr_num_buf); +} + /** * gfs2_log_commit - Commit a transaction to the log * @sdp: the filesystem @@ -790,7 +805,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) { log_refund(sdp, tr); - lops_incore_commit(sdp, tr); + buf_lo_incore_commit(sdp, tr); sdp->sd_vfs->s_dirt = 1; up_read(&sdp->sd_log_flush_lock); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index fae59d69d01..71387372c88 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -152,21 +152,6 @@ out: unlock_buffer(bd->bd_bh); } -static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) -{ - struct list_head *head = &tr->tr_list_buf; - struct gfs2_bufdata *bd; - - gfs2_log_lock(sdp); - while (!list_empty(head)) { - bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr); - list_del_init(&bd->bd_list_tr); - tr->tr_num_buf--; - } - gfs2_log_unlock(sdp); - gfs2_assert_warn(sdp, !tr->tr_num_buf); -} - static void buf_lo_before_commit(struct gfs2_sbd *sdp) { struct buffer_head *bh; @@ -737,7 +722,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) const struct gfs2_log_operations gfs2_buf_lops = { .lo_add = buf_lo_add, - .lo_incore_commit = buf_lo_incore_commit, .lo_before_commit = buf_lo_before_commit, .lo_after_commit = buf_lo_after_commit, .lo_before_scan = buf_lo_before_scan, @@ -763,7 +747,6 @@ const struct gfs2_log_operations gfs2_rg_lops = { const struct gfs2_log_operations gfs2_databuf_lops = { .lo_add = databuf_lo_add, - .lo_incore_commit = buf_lo_incore_commit, .lo_before_commit = databuf_lo_before_commit, .lo_after_commit = databuf_lo_after_commit, .lo_scan_elements = databuf_lo_scan_elements, diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 41a00df7558..3c0b2737658 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -57,15 +57,6 @@ static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) le->le_ops->lo_add(sdp, le); } -static inline void lops_incore_commit(struct gfs2_sbd *sdp, - struct gfs2_trans *tr) -{ - int x; - for (x = 0; gfs2_log_ops[x]; x++) - if (gfs2_log_ops[x]->lo_incore_commit) - gfs2_log_ops[x]->lo_incore_commit(sdp, tr); -} - static inline void lops_before_commit(struct gfs2_sbd *sdp) { int x; -- cgit v1.2.3-70-g09d2 From 7eabb77e65c559d9c284da232b9ba5354898028a Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 11:24:35 -0600 Subject: [GFS2] Misc fixups This patch contains two small fixups that didn't fit elsewhere. They are: (1) get rid of temp variable in find_metapath. (2) Remove vestigial "ret" variable from gfs2_writepage_common. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 3 +-- fs/gfs2/ops_address.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e8e48b690ce..e84e3845a39 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -305,11 +305,10 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, struct metapath *mp) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - u64 b = block; unsigned int i; for (i = ip->i_height; i--;) - mp->mp_list[i] = do_div(b, sdp->sd_inptrs); + mp->mp_list[i] = do_div(block, sdp->sd_inptrs); } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index ac772b6d9db..7523999afc5 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -104,11 +104,9 @@ static int gfs2_writepage_common(struct page *page, loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; - int ret = -EIO; if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) goto out; - ret = 0; if (current->journal_info) goto redirty; /* Is the page fully outside i_size? (truncate in progress) */ -- cgit v1.2.3-70-g09d2 From ef8c441cb7fece75dbbdb1f59d3f82b6a4be7474 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 14:54:16 -0600 Subject: [GFS2] Only wake the reclaim daemon if we need to This patch only wakes up the glock reclaim daemon if there is actually something to be reclaimed. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 7175a4d0643..5752dec017c 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1594,10 +1594,10 @@ void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) gfs2_glock_hold(gl); list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list); atomic_inc(&sdp->sd_reclaim_count); - } - spin_unlock(&sdp->sd_reclaim_lock); - - wake_up(&sdp->sd_reclaim_wq); + spin_unlock(&sdp->sd_reclaim_lock); + wake_up(&sdp->sd_reclaim_wq); + } else + spin_unlock(&sdp->sd_reclaim_lock); } /** -- cgit v1.2.3-70-g09d2 From 048786f1e6042022a8fb2035157a8c8c3a82a4f2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 29 Jan 2008 00:11:34 +0200 Subject: [GFS2] make gfs2_glock_hold() static gfs2_glock_hold() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 2 +- fs/gfs2/glock.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 5752dec017c..befcda0e53a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -197,7 +197,7 @@ static void glock_free(struct gfs2_glock *gl) * */ -void gfs2_glock_hold(struct gfs2_glock *gl) +static void gfs2_glock_hold(struct gfs2_glock *gl) { atomic_inc(&gl->gl_ref); } diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 2f9c6d136b3..ace5770760c 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -79,7 +79,6 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp); -void gfs2_glock_hold(struct gfs2_glock *gl); int gfs2_glock_put(struct gfs2_glock *gl); void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, struct gfs2_holder *gh); -- cgit v1.2.3-70-g09d2 From 3ad62e87cd38817361e165cf4ad496ab76e19e81 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 16:35:13 -0600 Subject: [GFS2] Plug an unlikely leak Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 71387372c88..4390f6f4047 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -404,8 +404,10 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); error = gfs2_revoke_add(sdp, blkno, start); - if (error < 0) + if (error < 0) { + brelse(bh); return error; + } else if (error) sdp->sd_found_revokes++; -- cgit v1.2.3-70-g09d2 From 6bdd9be628fa5f4dd14eb89ebddc12840d684277 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 17:20:26 -0600 Subject: [GFS2] Allocate gfs2_rgrpd from slab memory This patch moves the gfs2_rgrpd structure to its own slab memory. This makes it easier to control and monitor, and yields less memory fragmentation. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/main.c | 10 ++++++++++ fs/gfs2/rgrp.c | 4 ++-- fs/gfs2/util.c | 1 + fs/gfs2/util.h | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 9c7765c12d6..053e2ebbbd5 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -89,6 +89,12 @@ static int __init init_gfs2_fs(void) if (!gfs2_bufdata_cachep) goto fail; + gfs2_rgrpd_cachep = kmem_cache_create("gfs2_rgrpd", + sizeof(struct gfs2_rgrpd), + 0, 0, NULL); + if (!gfs2_rgrpd_cachep) + goto fail; + error = register_filesystem(&gfs2_fs_type); if (error) goto fail; @@ -108,6 +114,9 @@ fail_unregister: fail: gfs2_glock_exit(); + if (gfs2_rgrpd_cachep) + kmem_cache_destroy(gfs2_rgrpd_cachep); + if (gfs2_bufdata_cachep) kmem_cache_destroy(gfs2_bufdata_cachep); @@ -133,6 +142,7 @@ static void __exit exit_gfs2_fs(void) unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2meta_fs_type); + kmem_cache_destroy(gfs2_rgrpd_cachep); kmem_cache_destroy(gfs2_bufdata_cachep); kmem_cache_destroy(gfs2_inode_cachep); kmem_cache_destroy(gfs2_glock_cachep); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7b9d6f1d152..dc7e83eed32 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -353,7 +353,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) } kfree(rgd->rd_bits); - kfree(rgd); + kmem_cache_free(gfs2_rgrpd_cachep, rgd); } } @@ -516,7 +516,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, return error; } - rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS); + rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS); error = -ENOMEM; if (!rgd) return error; diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 424a0774eda..fe9c28ef77b 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -25,6 +25,7 @@ struct kmem_cache *gfs2_glock_cachep __read_mostly; struct kmem_cache *gfs2_inode_cachep __read_mostly; struct kmem_cache *gfs2_bufdata_cachep __read_mostly; +struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 28938a46cf4..ac0c567ebc3 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -147,6 +147,7 @@ gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__); extern struct kmem_cache *gfs2_glock_cachep; extern struct kmem_cache *gfs2_inode_cachep; extern struct kmem_cache *gfs2_bufdata_cachep; +extern struct kmem_cache *gfs2_rgrpd_cachep; static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, unsigned int *p) -- cgit v1.2.3-70-g09d2 From 42d52e3818751633656fb90df1bd5cb5362fa8cc Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 18:38:07 -0600 Subject: [GFS2] Combine rg_flags and rd_flags This patch reduces the memory required by GFS2 by combining the rd_flags and rg_flags (in core only). Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 6 +++--- fs/gfs2/rgrp.c | 36 +++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 7ae12d2b626..39bab7b213e 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -69,7 +69,6 @@ struct gfs2_bitmap { }; struct gfs2_rgrp_host { - u32 rg_flags; u32 rg_free; u32 rg_dinodes; u64 rg_igeneration; @@ -95,8 +94,9 @@ struct gfs2_rgrpd { u32 rd_last_alloc_data; u32 rd_last_alloc_meta; struct gfs2_sbd *rd_sbd; - unsigned long rd_flags; -#define GFS2_RDF_CHECK 0x0001 /* Need to check for unlinked inodes */ + unsigned char rd_flags; +#define GFS2_RDF_CHECK 0x01 /* Need to check for unlinked inodes */ +#define GFS2_RDF_NOALLOC 0x02 /* rg prohibits allocation */ }; enum gfs2_state_bits { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index dc7e83eed32..da60ce8c5d7 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -655,21 +655,31 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) return error; } -static void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf) +static void gfs2_rgrp_in(struct gfs2_rgrpd *rgd, const void *buf) { const struct gfs2_rgrp *str = buf; + struct gfs2_rgrp_host *rg = &rgd->rd_rg; + u32 rg_flags; - rg->rg_flags = be32_to_cpu(str->rg_flags); + rg_flags = be32_to_cpu(str->rg_flags); + if (rg_flags & GFS2_RGF_NOALLOC) + rgd->rd_flags |= GFS2_RDF_NOALLOC; + else + rgd->rd_flags &= ~GFS2_RDF_NOALLOC; rg->rg_free = be32_to_cpu(str->rg_free); rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); } -static void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf) +static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) { struct gfs2_rgrp *str = buf; + struct gfs2_rgrp_host *rg = &rgd->rd_rg; + u32 rg_flags = 0; - str->rg_flags = cpu_to_be32(rg->rg_flags); + if (rgd->rd_flags & GFS2_RDF_NOALLOC) + rg_flags |= GFS2_RGF_NOALLOC; + str->rg_flags = cpu_to_be32(rg_flags); str->rg_free = cpu_to_be32(rg->rg_free); str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); str->__pad = cpu_to_be32(0); @@ -727,7 +737,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) } if (rgd->rd_rg_vn != gl->gl_vn) { - gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data); + gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data); rgd->rd_rg_vn = gl->gl_vn; } @@ -840,7 +850,7 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) struct gfs2_sbd *sdp = rgd->rd_sbd; int ret = 0; - if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC) + if (rgd->rd_flags & GFS2_RDF_NOALLOC) return 0; spin_lock(&sdp->sd_rindex_spin); @@ -1431,7 +1441,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) rgd->rd_rg.rg_free--; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); al->al_alloced++; @@ -1476,7 +1486,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) rgd->rd_rg.rg_free--; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); al->al_alloced++; @@ -1519,7 +1529,7 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) rgd->rd_rg.rg_dinodes++; *generation = rgd->rd_rg.rg_igeneration++; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); al->al_alloced++; @@ -1553,7 +1563,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) rgd->rd_rg.rg_free += blen; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_trans_add_rg(rgd); @@ -1581,7 +1591,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) rgd->rd_rg.rg_free += blen; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_trans_add_rg(rgd); @@ -1601,7 +1611,7 @@ void gfs2_unlink_di(struct inode *inode) if (!rgd) return; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_trans_add_rg(rgd); } @@ -1621,7 +1631,7 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) rgd->rd_rg.rg_free++; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_statfs_change(sdp, 0, +1, -1); gfs2_trans_add_rg(rgd); -- cgit v1.2.3-70-g09d2 From 29d38cd16358dcaef4a6c50866ecee28025b481a Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 28 Jan 2008 22:31:39 -0600 Subject: [GFS2] Get rid of gl_waiters2 This patch reduces memory by replacing the int variable gl_waiters2 by a single bit in the gl_flags. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 7 ++++--- fs/gfs2/incore.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index befcda0e53a..951cb91e7dd 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -595,11 +595,12 @@ static void run_queue(struct gfs2_glock *gl) blocked = rq_mutex(gh); } else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) { blocked = rq_demote(gl); - if (gl->gl_waiters2 && !blocked) { + if (test_bit(GLF_WAITERS2, &gl->gl_flags) && + !blocked) { set_bit(GLF_DEMOTE, &gl->gl_flags); gl->gl_demote_state = LM_ST_UNLOCKED; } - gl->gl_waiters2 = 0; + clear_bit(GLF_WAITERS2, &gl->gl_flags); } else if (!list_empty(&gl->gl_waiters3)) { gh = list_entry(gl->gl_waiters3.next, struct gfs2_holder, gh_list); @@ -710,7 +711,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, } else if (gl->gl_demote_state != LM_ST_UNLOCKED && gl->gl_demote_state != state) { if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) - gl->gl_waiters2 = 1; + set_bit(GLF_WAITERS2, &gl->gl_flags); else gl->gl_demote_state = LM_ST_UNLOCKED; } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 39bab7b213e..fe14f6a417b 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -167,6 +167,7 @@ enum { GLF_DIRTY = 5, GLF_DEMOTE_IN_PROGRESS = 6, GLF_LFLUSH = 7, + GLF_WAITERS2 = 8, }; struct gfs2_glock { @@ -186,7 +187,6 @@ struct gfs2_glock { struct list_head gl_holders; struct list_head gl_waiters1; /* HIF_MUTEX */ struct list_head gl_waiters3; /* HIF_PROMOTE */ - int gl_waiters2; /* GIF_DEMOTE */ const struct gfs2_glock_operations *gl_ops; -- cgit v1.2.3-70-g09d2 From 11707ea05e85290d10c482b87e195c198f5eb3cf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Jan 2008 15:10:29 +0000 Subject: [GFS2] Move part of gfs2_block_map into a separate function This is required to enable future changes to the block mapping code. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 57 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e84e3845a39..08d1be492ef 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -384,6 +384,35 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, return 0; } +static int lookup_metapath(struct inode *inode, struct metapath *mp, + int create, int *new, u64 *dblock, + struct buffer_head **dibh, struct buffer_head **bh) +{ + struct gfs2_inode *ip = GFS2_I(inode); + unsigned int end_of_metadata = ip->i_height - 1; + unsigned int x; + int ret = gfs2_meta_inode_buffer(ip, bh); + if (ret) + return ret; + + *dibh = *bh; + get_bh(*dibh); + + for (x = 0; x < end_of_metadata; x++) { + lookup_block(ip, *bh, x, mp, create, new, dblock); + brelse(*bh); + *bh = NULL; + if (!dblock) + return 0; + + ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, bh); + if (ret) + return ret; + } + + return lookup_block(ip, *bh, end_of_metadata, mp, create, new, dblock); +} + static inline void bmap_lock(struct inode *inode, int create) { struct gfs2_inode *ip = GFS2_I(inode); @@ -419,10 +448,8 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - struct buffer_head *bh; unsigned int bsize = sdp->sd_sb.sb_bsize; - unsigned int end_of_metadata; - unsigned int x; + struct buffer_head *bh = NULL; int error = 0; int new = 0; u64 dblock = 0; @@ -459,25 +486,11 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, } find_metapath(ip, lblock, &mp); - end_of_metadata = ip->i_height - 1; - error = gfs2_meta_inode_buffer(ip, &bh); - if (error) + error = lookup_metapath(inode, &mp, create, &new, &dblock, &dibh, &bh); + if (error < 0) goto out_fail; - dibh = bh; - get_bh(dibh); - - for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, bh, x, &mp, create, &new, &dblock); - brelse(bh); - if (!dblock) - goto out_ok; + boundary = error; - error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); - if (error) - goto out_fail; - } - - boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock); if (dblock) { map_bh(bh_map, inode->i_sb, dblock); if (boundary) @@ -489,6 +502,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, goto out_brelse; } while(--maxlen && !buffer_boundary(bh_map)) { + unsigned int end_of_metadata = ip->i_height - 1; u64 eblock; mp.mp_list[end_of_metadata]++; @@ -501,7 +515,8 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, } } out_brelse: - brelse(bh); + if (bh) + brelse(bh); out_ok: error = 0; out_fail: -- cgit v1.2.3-70-g09d2 From dbac6710a6dfcec7fbe7d9571c183d86a4237623 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Jan 2008 09:12:55 +0000 Subject: [GFS2] Introduce array of buffers to struct metapath The reason for doing this is to allow all the block mapping code to share the same array. As a result we can remove two arguments from lookup_metapath since they are now returned via the array. We also add a function to drop all refs to buffer heads when we are done with the metapath. The build_height function shares the struct metapath, but currently still frees its own buffers, and this will change in a future patch. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 97 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 08d1be492ef..2011dd27f8d 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -33,6 +33,7 @@ * keep it small. */ struct metapath { + struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT]; __u16 mp_list[GFS2_MAX_META_HEIGHT]; }; @@ -185,12 +186,11 @@ out: * Returns: errno */ -static int build_height(struct inode *inode, unsigned height) +static int build_height(struct inode *inode, struct metapath *mp, unsigned height) { struct gfs2_inode *ip = GFS2_I(inode); unsigned new_height = height - ip->i_height; struct buffer_head *dibh; - struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; struct gfs2_dinode *di; int error; __be64 *bp; @@ -206,29 +206,29 @@ static int build_height(struct inode *inode, unsigned height) for(n = 0; n < new_height; n++) { bn = gfs2_alloc_meta(ip); - blocks[n] = gfs2_meta_new(ip->i_gl, bn); - gfs2_trans_add_bh(ip->i_gl, blocks[n], 1); + mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn); + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1); } n = 0; - bn = blocks[0]->b_blocknr; + bn = mp->mp_bh[0]->b_blocknr; if (new_height > 1) { for(; n < new_height-1; n++) { - gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, + gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); - gfs2_buffer_clear_tail(blocks[n], + gfs2_buffer_clear_tail(mp->mp_bh[n], sizeof(struct gfs2_meta_header)); - bp = (__be64 *)(blocks[n]->b_data + + bp = (__be64 *)(mp->mp_bh[n]->b_data + sizeof(struct gfs2_meta_header)); - *bp = cpu_to_be64(blocks[n+1]->b_blocknr); - brelse(blocks[n]); - blocks[n] = NULL; + *bp = cpu_to_be64(mp->mp_bh[n+1]->b_blocknr); + brelse(mp->mp_bh[n]); + mp->mp_bh[n] = NULL; } } - gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); - gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header), + gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_copy_tail(mp->mp_bh[n], sizeof(struct gfs2_meta_header), dibh, sizeof(struct gfs2_dinode)); - brelse(blocks[n]); + brelse(mp->mp_bh[n]); gfs2_trans_add_bh(ip->i_gl, dibh, 1); di = (struct gfs2_dinode *)dibh->b_data; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); @@ -314,7 +314,6 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, /** * metapointer - Return pointer to start of metadata in a buffer - * @bh: The buffer * @height: The metadata height (0 = dinode) * @mp: The metapath * @@ -323,9 +322,10 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, * metadata tree. */ -static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, - unsigned int height, const struct metapath *mp) +static inline __be64 *metapointer(int *boundary, unsigned int height, + const struct metapath *mp) { + struct buffer_head *bh = mp->mp_bh[height]; unsigned int head_size = (height > 0) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); __be64 *ptr; @@ -339,7 +339,6 @@ static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, /** * lookup_block - Get the next metadata block in metadata tree * @ip: The GFS2 inode - * @bh: Buffer containing the pointers to metadata blocks * @height: The height of the tree (0 = dinode) * @mp: The metapath * @create: Non-zero if we may create a new meatdata block @@ -352,12 +351,12 @@ static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, * */ -static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, - unsigned int height, struct metapath *mp, int create, +static int lookup_block(struct gfs2_inode *ip, unsigned int height, + struct metapath *mp, int create, int *new, u64 *block) { int boundary; - __be64 *ptr = metapointer(bh, &boundary, height, mp); + __be64 *ptr = metapointer(&boundary, height, mp); if (*ptr) { *block = be64_to_cpu(*ptr); @@ -374,7 +373,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, else *block = gfs2_alloc_meta(ip); - gfs2_trans_add_bh(ip->i_gl, bh, 1); + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); *ptr = cpu_to_be64(*block); ip->i_di.di_blocks++; @@ -385,32 +384,38 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, } static int lookup_metapath(struct inode *inode, struct metapath *mp, - int create, int *new, u64 *dblock, - struct buffer_head **dibh, struct buffer_head **bh) + int create, int *new, u64 *dblock) { + struct buffer_head *bh; struct gfs2_inode *ip = GFS2_I(inode); unsigned int end_of_metadata = ip->i_height - 1; unsigned int x; - int ret = gfs2_meta_inode_buffer(ip, bh); + int ret = gfs2_meta_inode_buffer(ip, &bh); if (ret) return ret; - *dibh = *bh; - get_bh(*dibh); + mp->mp_bh[0] = bh; for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, *bh, x, mp, create, new, dblock); - brelse(*bh); - *bh = NULL; + lookup_block(ip, x, mp, create, new, dblock); if (!dblock) return 0; - ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, bh); + ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &mp->mp_bh[x+1]); if (ret) return ret; } - return lookup_block(ip, *bh, end_of_metadata, mp, create, new, dblock); + return lookup_block(ip, end_of_metadata, mp, create, new, dblock); +} + +static void release_metapath(struct metapath *mp) +{ + int i; + + for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) + if (mp->mp_bh[i]) + brelse(mp->mp_bh[i]); } static inline void bmap_lock(struct inode *inode, int create) @@ -449,7 +454,6 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); unsigned int bsize = sdp->sd_sb.sb_bsize; - struct buffer_head *bh = NULL; int error = 0; int new = 0; u64 dblock = 0; @@ -457,13 +461,13 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; struct metapath mp; u64 size; - struct buffer_head *dibh = NULL; const u64 *arr = sdp->sd_heightsize; BUG_ON(maxlen == 0); if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) return 0; + memset(mp.mp_bh, 0, sizeof(mp.mp_bh)); bmap_lock(inode, create); clear_buffer_mapped(bh_map); clear_buffer_new(bh_map); @@ -480,13 +484,13 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, goto out_ok; while (size > arr[height]) height++; - error = build_height(inode, height); + error = build_height(inode, &mp, height); if (error) goto out_fail; } find_metapath(ip, lblock, &mp); - error = lookup_metapath(inode, &mp, create, &new, &dblock, &dibh, &bh); + error = lookup_metapath(inode, &mp, create, &new, &dblock); if (error < 0) goto out_fail; boundary = error; @@ -496,17 +500,15 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, if (boundary) set_buffer_boundary(bh_map); if (new) { - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); + gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); + gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); set_buffer_new(bh_map); - goto out_brelse; + goto out_ok; } while(--maxlen && !buffer_boundary(bh_map)) { - unsigned int end_of_metadata = ip->i_height - 1; u64 eblock; - - mp.mp_list[end_of_metadata]++; - boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock); + mp.mp_list[ip->i_height - 1]++; + boundary = lookup_block(ip, ip->i_height - 1, &mp, 0, &new, &eblock); if (eblock != ++dblock) break; bh_map->b_size += (1 << inode->i_blkbits); @@ -514,14 +516,10 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, set_buffer_boundary(bh_map); } } -out_brelse: - if (bh) - brelse(bh); out_ok: error = 0; out_fail: - if (dibh) - brelse(dibh); + release_metapath(&mp); bmap_unlock(inode, create); return error; } @@ -819,10 +817,11 @@ static int do_grow(struct gfs2_inode *ip, u64 size) down_write(&ip->i_rw_mutex); if (size > arr[ip->i_height]) { + struct metapath mp; u8 height = ip->i_height; while(size > arr[height]) height++; - error = build_height(&ip->i_inode, height); + error = build_height(&ip->i_inode, &mp, height); } up_write(&ip->i_rw_mutex); if (error) -- cgit v1.2.3-70-g09d2 From 110acf38377b5b341b11644bfe98389eccec627d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Jan 2008 13:30:20 +0000 Subject: [GFS2] Add consts to various bits of rgrp.c There are a couple of routines which scan bitmaps where we can mark the bitmaps const, plus a couple of call sites that can be updated too. Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index da60ce8c5d7..5fd87104e59 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -126,23 +126,24 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * Return: the block number (bitmap buffer scope) that was found */ -static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, - unsigned char old_state) +static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal, + u8 old_state) { - unsigned char *byte; + const u8 *byte; u32 blk = goal; unsigned int bit, bitlong; - unsigned long *plong, plong55; + const unsigned long *plong; +#if BITS_PER_LONG == 32 + const unsigned long plong55 = 0x55555555; +#else + const unsigned long plong55 = 0x5555555555555555; +#endif byte = buffer + (goal / GFS2_NBBY); - plong = (unsigned long *)(buffer + (goal / GFS2_NBBY)); + plong = (const unsigned long *)(buffer + (goal / GFS2_NBBY)); bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; bitlong = bit; -#if BITS_PER_LONG == 32 - plong55 = 0x55555555; -#else - plong55 = 0x5555555555555555; -#endif + while (byte < buffer + buflen) { if (bitlong == 0 && old_state == 0 && *plong == plong55) { @@ -179,14 +180,14 @@ static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, * Returns: The number of bits */ -static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, unsigned char state) +static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, const u8 *buffer, + unsigned int buflen, u8 state) { - unsigned char *byte = buffer; - unsigned char *end = buffer + buflen; - unsigned char state1 = state << 2; - unsigned char state2 = state << 4; - unsigned char state3 = state << 6; + const u8 *byte = buffer; + const u8 *end = buffer + buflen; + const u8 state1 = state << 2; + const u8 state2 = state << 4; + const u8 state3 = state << 6; u32 count = 0; for (; byte < end; byte++) { @@ -1327,12 +1328,11 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, for (x = 0; x <= length; x++) { /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone bitmaps, so we must search the originals for that. */ + const u8 *buffer = bi->bi_bh->b_data + bi->bi_offset; if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) - blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset, - bi->bi_len, goal, old_state); - else - blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset, - bi->bi_len, goal, old_state); + buffer = bi->bi_clone + bi->bi_offset; + + blk = gfs2_bitfit(buffer, bi->bi_len, goal, old_state); if (blk != BFITNOENT) break; -- cgit v1.2.3-70-g09d2 From ab0d756681c9502a2ab9e2e4ab3685bc0567f4ee Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 29 Jan 2008 13:56:15 -0600 Subject: [GFS2] Eliminate gl_req_bh This patch further reduces the memory needs of GFS2 by eliminating the gl_req_bh variable from struct gfs2_glock. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 107 ++++++++++++++++++++++++++----------------------------- fs/gfs2/incore.h | 1 - 2 files changed, 51 insertions(+), 57 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 951cb91e7dd..a8387e0b506 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -338,7 +338,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_ip = 0; gl->gl_ops = glops; gl->gl_req_gh = NULL; - gl->gl_req_bh = NULL; gl->gl_vn = 0; gl->gl_stamp = jiffies; gl->gl_tchange = jiffies; @@ -743,6 +742,50 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) gl->gl_tchange = jiffies; } +/** + * drop_bh - Called after a lock module unlock completes + * @gl: the glock + * @ret: the return status + * + * Doesn't wake up the process waiting on the struct gfs2_holder (if any) + * Doesn't drop the reference on the glock the top half took out + * + */ + +static void drop_bh(struct gfs2_glock *gl, unsigned int ret) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + const struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_holder *gh = gl->gl_req_gh; + + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); + gfs2_assert_warn(sdp, !ret); + + state_change(gl, LM_ST_UNLOCKED); + + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA); + + if (gh) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + } + + spin_lock(&gl->gl_spin); + gfs2_demote_wake(gl); + gl->gl_req_gh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + gfs2_glock_put(gl); + + if (gh) + gfs2_holder_wake(gh); +} + /** * xmote_bh - Called after the lock module is done acquiring a lock * @gl: The glock in question @@ -758,6 +801,11 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) int prev_state = gl->gl_state; int op_done = 1; + if ((ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) { + drop_bh(gl, ret); + return; + } + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC)); @@ -783,7 +831,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) } else { spin_lock(&gl->gl_spin); if (gl->gl_state != gl->gl_demote_state) { - gl->gl_req_bh = NULL; spin_unlock(&gl->gl_spin); gfs2_glock_drop_th(gl); gfs2_glock_put(gl); @@ -825,7 +872,6 @@ out: if (op_done) { spin_lock(&gl->gl_spin); gl->gl_req_gh = NULL; - gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); spin_unlock(&gl->gl_spin); } @@ -864,7 +910,6 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) gfs2_assert_warn(sdp, state != gl->gl_state); gfs2_glock_hold(gl); - gl->gl_req_bh = xmote_bh; lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags); @@ -877,51 +922,6 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) xmote_bh(gl, lck_ret); } -/** - * drop_bh - Called after a lock module unlock completes - * @gl: the glock - * @ret: the return status - * - * Doesn't wake up the process waiting on the struct gfs2_holder (if any) - * Doesn't drop the reference on the glock the top half took out - * - */ - -static void drop_bh(struct gfs2_glock *gl, unsigned int ret) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - const struct gfs2_glock_operations *glops = gl->gl_ops; - struct gfs2_holder *gh = gl->gl_req_gh; - - gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); - gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); - gfs2_assert_warn(sdp, !ret); - - state_change(gl, LM_ST_UNLOCKED); - - if (glops->go_inval) - glops->go_inval(gl, DIO_METADATA); - - if (gh) { - spin_lock(&gl->gl_spin); - list_del_init(&gh->gh_list); - gh->gh_error = 0; - spin_unlock(&gl->gl_spin); - } - - spin_lock(&gl->gl_spin); - gfs2_demote_wake(gl); - gl->gl_req_gh = NULL; - gl->gl_req_bh = NULL; - clear_bit(GLF_LOCK, &gl->gl_flags); - spin_unlock(&gl->gl_spin); - - gfs2_glock_put(gl); - - if (gh) - gfs2_holder_wake(gh); -} - /** * gfs2_glock_drop_th - call into the lock module to unlock a lock * @gl: the glock @@ -942,7 +942,6 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); gfs2_glock_hold(gl); - gl->gl_req_bh = drop_bh; ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state); @@ -971,8 +970,7 @@ static void do_cancels(struct gfs2_holder *gh) while (gl->gl_req_gh != gh && !test_bit(HIF_HOLDER, &gh->gh_iflags) && !list_empty(&gh->gh_list)) { - if (gl->gl_req_bh && !(gl->gl_req_gh && - (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) { + if (!(gl->gl_req_gh && (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) { spin_unlock(&gl->gl_spin); gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock); msleep(100); @@ -1042,7 +1040,6 @@ static int glock_wait_internal(struct gfs2_holder *gh) spin_lock(&gl->gl_spin); gl->gl_req_gh = NULL; - gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); run_queue(gl); spin_unlock(&gl->gl_spin); @@ -1535,8 +1532,7 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) gl = gfs2_glock_find(sdp, &async->lc_name); if (gfs2_assert_warn(sdp, gl)) return; - if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) - gl->gl_req_bh(gl, async->lc_ret); + xmote_bh(gl, async->lc_ret); if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gfs2_glock_put(gl); up_read(&gfs2_umount_flush_sem); @@ -1898,7 +1894,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl) print_dbg(gi, " gl_owner = -1\n"); print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip); print_dbg(gi, " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); - print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no"); print_dbg(gi, " reclaim = %s\n", diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index fe14f6a417b..65aa46acb08 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -191,7 +191,6 @@ struct gfs2_glock { const struct gfs2_glock_operations *gl_ops; struct gfs2_holder *gl_req_gh; - gfs2_glop_bh_t gl_req_bh; void *gl_lock; char *gl_lvb; -- cgit v1.2.3-70-g09d2 From da755fdb414470d6dce3df12ad188de9131cf96c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Jan 2008 15:34:04 +0000 Subject: [GFS2] Remove lm.[ch] and distribute content The functions in lm.c were just wrappers which were mostly only used in one other file. By moving the functions to the files where they are being used, they can be marked static and also this will usually result in them being inlined since they are often only used from one point in the code. A couple of really trivial functions have been inlined by hand into the function which called them as it makes the code clearer to do that. We also gain from one fewer function call in the glock lock and unlock paths. Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 2 +- fs/gfs2/glock.c | 51 ++++++++++++- fs/gfs2/incore.h | 2 + fs/gfs2/lm.c | 210 --------------------------------------------------- fs/gfs2/lm.h | 42 ----------- fs/gfs2/ops_file.c | 31 +++++++- fs/gfs2/ops_fstype.c | 71 ++++++++++++++++- fs/gfs2/ops_super.c | 1 - fs/gfs2/recovery.c | 11 ++- fs/gfs2/super.h | 1 + fs/gfs2/sys.c | 1 - fs/gfs2/util.c | 23 +++++- fs/gfs2/util.h | 1 + 13 files changed, 184 insertions(+), 263 deletions(-) delete mode 100644 fs/gfs2/lm.c delete mode 100644 fs/gfs2/lm.h diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 8fff11058ce..e2350df02a0 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ - glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \ + glops.o inode.o log.o lops.o locking.o main.o meta_io.o \ mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ ops_fstype.o ops_inode.o ops_super.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a8387e0b506..611f84d2257 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -35,7 +35,6 @@ #include "glock.h" #include "glops.h" #include "inode.h" -#include "lm.h" #include "lops.h" #include "meta_io.h" #include "quota.h" @@ -183,7 +182,8 @@ static void glock_free(struct gfs2_glock *gl) struct gfs2_sbd *sdp = gl->gl_sbd; struct inode *aspace = gl->gl_aspace; - gfs2_lm_put_lock(sdp, gl->gl_lock); + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_put_lock(gl->gl_lock); if (aspace) gfs2_aspace_put(aspace); @@ -293,6 +293,16 @@ static void glock_work_func(struct work_struct *work) gfs2_glock_put(gl); } +static int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, + void **lockp) +{ + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = sdp->sd_lockstruct.ls_ops->lm_get_lock( + sdp->sd_lockstruct.ls_lockspace, name, lockp); + return error; +} + /** * gfs2_glock_get() - Get a glock, or create one if one doesn't exist * @sdp: The GFS2 superblock @@ -882,6 +892,17 @@ out: gfs2_holder_wake(gh); } +static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, + unsigned int cur_state, unsigned int req_state, + unsigned int flags) +{ + int ret = 0; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state, + req_state, flags); + return ret; +} + /** * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock * @gl: The glock in question @@ -922,6 +943,15 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) xmote_bh(gl, lck_ret); } +static unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock, + unsigned int cur_state) +{ + int ret = 0; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); + return ret; +} + /** * gfs2_glock_drop_th - call into the lock module to unlock a lock * @gl: the glock @@ -964,6 +994,7 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) static void do_cancels(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; spin_lock(&gl->gl_spin); @@ -972,7 +1003,8 @@ static void do_cancels(struct gfs2_holder *gh) !list_empty(&gh->gh_list)) { if (!(gl->gl_req_gh && (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) { spin_unlock(&gl->gl_spin); - gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock); + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_cancel(gl->gl_lock); msleep(100); spin_lock(&gl->gl_spin); } else { @@ -1426,6 +1458,14 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) gfs2_glock_dq_uninit(&ghs[x]); } +static int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp) +{ + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); + return error; +} + /** * gfs2_lvb_hold - attach a LVB from a glock * @gl: The glock in question @@ -1461,12 +1501,15 @@ int gfs2_lvb_hold(struct gfs2_glock *gl) void gfs2_lvb_unhold(struct gfs2_glock *gl) { + struct gfs2_sbd *sdp = gl->gl_sbd; + gfs2_glock_hold(gl); gfs2_glmutex_lock(gl); gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0); if (atomic_dec_and_test(&gl->gl_lvb_count)) { - gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(gl->gl_lock, gl->gl_lvb); gl->gl_lvb = NULL; gfs2_glock_put(gl); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 65aa46acb08..8dee4672c3d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -211,6 +211,8 @@ struct gfs2_glock { struct delayed_work gl_work; }; +#define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ + struct gfs2_alloc { /* Quota stuff */ diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c deleted file mode 100644 index cfcc39b86a5..00000000000 --- a/fs/gfs2/lm.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "gfs2.h" -#include "incore.h" -#include "glock.h" -#include "lm.h" -#include "super.h" -#include "util.h" - -/** - * gfs2_lm_mount - mount a locking protocol - * @sdp: the filesystem - * @args: mount arguements - * @silent: if 1, don't complain if the FS isn't a GFS2 fs - * - * Returns: errno - */ - -int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) -{ - char *proto = sdp->sd_proto_name; - char *table = sdp->sd_table_name; - int flags = 0; - int error; - - if (sdp->sd_args.ar_spectator) - flags |= LM_MFLAG_SPECTATOR; - - fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table); - - error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, - gfs2_glock_cb, sdp, - GFS2_MIN_LVB_SIZE, flags, - &sdp->sd_lockstruct, &sdp->sd_kobj); - if (error) { - fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n", - proto, table, sdp->sd_args.ar_hostdata); - goto out; - } - - if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) || - gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || - gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= - GFS2_MIN_LVB_SIZE)) { - gfs2_unmount_lockproto(&sdp->sd_lockstruct); - goto out; - } - - if (sdp->sd_args.ar_spectator) - snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table); - else - snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, - sdp->sd_lockstruct.ls_jid); - - fs_info(sdp, "Joined cluster. Now mounting FS...\n"); - - if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && - !sdp->sd_args.ar_ignore_local_fs) { - sdp->sd_args.ar_localflocks = 1; - sdp->sd_args.ar_localcaching = 1; - } - -out: - return error; -} - -void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_others_may_mount( - sdp->sd_lockstruct.ls_lockspace); -} - -void gfs2_lm_unmount(struct gfs2_sbd *sdp) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - gfs2_unmount_lockproto(&sdp->sd_lockstruct); -} - -int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) -{ - va_list args; - - if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) - return 0; - - va_start(args, fmt); - vprintk(fmt, args); - va_end(args); - - fs_err(sdp, "about to withdraw this file system\n"); - BUG_ON(sdp->sd_args.ar_debug); - - fs_err(sdp, "telling LM to withdraw\n"); - gfs2_withdraw_lockproto(&sdp->sd_lockstruct); - fs_err(sdp, "withdrawn\n"); - dump_stack(); - - return -1; -} - -int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, - void **lockp) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_get_lock( - sdp->sd_lockstruct.ls_lockspace, name, lockp); - return error; -} - -void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_put_lock(lock); -} - -unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, - unsigned int cur_state, unsigned int req_state, - unsigned int flags) -{ - int ret = 0; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state, - req_state, flags); - return ret; -} - -unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock, - unsigned int cur_state) -{ - int ret = 0; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); - return ret; -} - -void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_cancel(lock); -} - -int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); - return error; -} - -void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); -} - -int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_plock_get( - sdp->sd_lockstruct.ls_lockspace, name, file, fl); - return error; -} - -int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_plock( - sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl); - return error; -} - -int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_punlock( - sdp->sd_lockstruct.ls_lockspace, name, file, fl); - return error; -} - -void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, - unsigned int message) -{ - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_recovery_done( - sdp->sd_lockstruct.ls_lockspace, jid, message); -} - diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h deleted file mode 100644 index 21cdc30ee08..00000000000 --- a/fs/gfs2/lm.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef __LM_DOT_H__ -#define __LM_DOT_H__ - -struct gfs2_sbd; - -#define GFS2_MIN_LVB_SIZE 32 - -int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent); -void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp); -void gfs2_lm_unmount(struct gfs2_sbd *sdp); -int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) - __attribute__ ((format(printf, 2, 3))); -int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, - void **lockp); -void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock); -unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, - unsigned int cur_state, unsigned int req_state, - unsigned int flags); -unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock, - unsigned int cur_state); -void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock); -int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp); -void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb); -int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl); -int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl); -int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl); -void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, - unsigned int message); - -#endif /* __LM_DOT_H__ */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index f4842f2548c..f97a8b86c48 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -30,7 +30,6 @@ #include "glock.h" #include "glops.h" #include "inode.h" -#include "lm.h" #include "log.h" #include "meta_io.h" #include "quota.h" @@ -596,6 +595,36 @@ static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl) return generic_setlease(file, arg, fl); } +static int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = sdp->sd_lockstruct.ls_ops->lm_plock_get( + sdp->sd_lockstruct.ls_lockspace, name, file, fl); + return error; +} + +static int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = sdp->sd_lockstruct.ls_ops->lm_plock( + sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl); + return error; +} + +static int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = sdp->sd_lockstruct.ls_ops->lm_punlock( + sdp->sd_lockstruct.ls_lockspace, name, file, fl); + return error; +} + /** * gfs2_lock - acquire/release a posix lock on a file * @file: the file pointer diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 4bee6aa845e..5b6a3451716 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -26,7 +26,6 @@ #include "glock.h" #include "glops.h" #include "inode.h" -#include "lm.h" #include "mount.h" #include "ops_fstype.h" #include "ops_dentry.h" @@ -363,6 +362,13 @@ static int map_journal_extents(struct gfs2_sbd *sdp) return rc; } +static void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_others_may_mount( + sdp->sd_lockstruct.ls_lockspace); +} + static int init_journal(struct gfs2_sbd *sdp, int undo) { struct gfs2_holder ji_gh; @@ -704,6 +710,69 @@ fail: return error; } +/** + * gfs2_lm_mount - mount a locking protocol + * @sdp: the filesystem + * @args: mount arguements + * @silent: if 1, don't complain if the FS isn't a GFS2 fs + * + * Returns: errno + */ + +static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) +{ + char *proto = sdp->sd_proto_name; + char *table = sdp->sd_table_name; + int flags = 0; + int error; + + if (sdp->sd_args.ar_spectator) + flags |= LM_MFLAG_SPECTATOR; + + fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table); + + error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, + gfs2_glock_cb, sdp, + GFS2_MIN_LVB_SIZE, flags, + &sdp->sd_lockstruct, &sdp->sd_kobj); + if (error) { + fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n", + proto, table, sdp->sd_args.ar_hostdata); + goto out; + } + + if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) || + gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || + gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= + GFS2_MIN_LVB_SIZE)) { + gfs2_unmount_lockproto(&sdp->sd_lockstruct); + goto out; + } + + if (sdp->sd_args.ar_spectator) + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table); + else + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, + sdp->sd_lockstruct.ls_jid); + + fs_info(sdp, "Joined cluster. Now mounting FS...\n"); + + if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && + !sdp->sd_args.ar_ignore_local_fs) { + sdp->sd_args.ar_localflocks = 1; + sdp->sd_args.ar_localcaching = 1; + } + +out: + return error; +} + +void gfs2_lm_unmount(struct gfs2_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + gfs2_unmount_lockproto(&sdp->sd_lockstruct); +} + /** * fill_super - Read in superblock * @sb: The VFS superblock diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 5e524217944..2278c68b7e3 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -25,7 +25,6 @@ #include "incore.h" #include "glock.h" #include "inode.h" -#include "lm.h" #include "log.h" #include "mount.h" #include "ops_super.h" diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 6fb07d67ca8..b17d3b8b232 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -20,7 +20,6 @@ #include "bmap.h" #include "glock.h" #include "glops.h" -#include "lm.h" #include "lops.h" #include "meta_io.h" #include "recovery.h" @@ -425,6 +424,16 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea return error; } + +static void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, + unsigned int message) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_recovery_done( + sdp->sd_lockstruct.ls_lockspace, jid, message); +} + + /** * gfs2_recover_journal - recovery a given journal * @jd: the struct gfs2_jdesc describing the journal diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 60a870e430b..44361ecc44f 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -17,6 +17,7 @@ void gfs2_tune_init(struct gfs2_tune *gt); int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent); int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector); +void gfs2_lm_unmount(struct gfs2_sbd *sdp); static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) { diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index eaa3b7b2f99..cc35ec862ee 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -20,7 +20,6 @@ #include "gfs2.h" #include "incore.h" -#include "lm.h" #include "sys.h" #include "super.h" #include "glock.h" diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index fe9c28ef77b..d31e355c61f 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -19,7 +19,6 @@ #include "gfs2.h" #include "incore.h" #include "glock.h" -#include "lm.h" #include "util.h" struct kmem_cache *gfs2_glock_cachep __read_mostly; @@ -33,6 +32,28 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) sdp->sd_fsname); } +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) +{ + va_list args; + + if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return 0; + + va_start(args, fmt); + vprintk(fmt, args); + va_end(args); + + fs_err(sdp, "about to withdraw this file system\n"); + BUG_ON(sdp->sd_args.ar_debug); + + fs_err(sdp, "telling LM to withdraw\n"); + gfs2_withdraw_lockproto(&sdp->sd_lockstruct); + fs_err(sdp, "withdrawn\n"); + dump_stack(); + + return -1; +} + /** * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false * Returns: -1 if this call withdrew the machine, diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index ac0c567ebc3..509c5d60bd8 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -164,6 +164,7 @@ gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap, unsigned int bit, int new_value); +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...); #endif /* __UTIL_DOT_H__ */ -- cgit v1.2.3-70-g09d2 From cf45b752c9f23939e40d823b0600bf876e97b0e0 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 31 Jan 2008 10:31:39 -0600 Subject: [GFS2] Remove rgrp and glock version numbers This patch further reduces GFS2's memory requirements by eliminating the 64-bit version number fields in lieu of a couple bits. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 3 +-- fs/gfs2/glops.c | 10 ++++++++-- fs/gfs2/incore.h | 5 ++--- fs/gfs2/ops_fstype.c | 4 ++-- fs/gfs2/rgrp.c | 14 +++++++------- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 611f84d2257..d00dc37e3d5 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -348,7 +348,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_ip = 0; gl->gl_ops = glops; gl->gl_req_gh = NULL; - gl->gl_vn = 0; gl->gl_stamp = jiffies; gl->gl_tchange = jiffies; gl->gl_object = NULL; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index c663b7a0f41..d31badadef8 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -126,7 +126,13 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) return; gfs2_meta_inval(gl); - gl->gl_vn++; + if (gl->gl_object == GFS2_I(gl->gl_sbd->sd_rindex)) + gl->gl_sbd->sd_rindex_uptodate = 0; + else if (gl->gl_ops == &gfs2_rgrp_glops && gl->gl_object) { + struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; + + rgd->rd_flags &= ~GFS2_RDF_UPTODATE; + } } /** diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8dee4672c3d..e9c58dc7686 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -85,7 +85,6 @@ struct gfs2_rgrpd { u32 rd_data; /* num of data blocks in rgrp */ u32 rd_bitbytes; /* number of bytes in data bitmaps */ struct gfs2_rgrp_host rd_rg; - u64 rd_rg_vn; struct gfs2_bitmap *rd_bits; unsigned int rd_bh_count; struct mutex rd_mutex; @@ -97,6 +96,7 @@ struct gfs2_rgrpd { unsigned char rd_flags; #define GFS2_RDF_CHECK 0x01 /* Need to check for unlinked inodes */ #define GFS2_RDF_NOALLOC 0x02 /* rg prohibits allocation */ +#define GFS2_RDF_UPTODATE 0x04 /* rg is up to date */ }; enum gfs2_state_bits { @@ -196,7 +196,6 @@ struct gfs2_glock { char *gl_lvb; atomic_t gl_lvb_count; - u64 gl_vn; unsigned long gl_stamp; unsigned long gl_tchange; void *gl_object; @@ -533,7 +532,7 @@ struct gfs2_sbd { /* Resource group stuff */ - u64 sd_rindex_vn; + int sd_rindex_uptodate; spinlock_t sd_rindex_spin; struct mutex sd_rindex_mutex; struct list_head sd_rindex_list; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5b6a3451716..c4b7a210c0c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -548,7 +548,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) } ip = GFS2_I(sdp->sd_rindex); set_bit(GLF_STICKY, &ip->i_gl->gl_flags); - sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1; + sdp->sd_rindex_uptodate = 0; /* Read in the quota inode */ sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota"); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5fd87104e59..3f10b1fafd6 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -540,7 +540,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, return error; rgd->rd_gl->gl_object = rgd; - rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; + rgd->rd_flags &= ~GFS2_RDF_UPTODATE; rgd->rd_flags |= GFS2_RDF_CHECK; return error; } @@ -576,7 +576,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) } } - sdp->sd_rindex_vn = ip->i_gl->gl_vn; + sdp->sd_rindex_uptodate = 1; return 0; } @@ -610,7 +610,7 @@ static int gfs2_ri_update_special(struct gfs2_inode *ip) } } - sdp->sd_rindex_vn = ip->i_gl->gl_vn; + sdp->sd_rindex_uptodate = 1; return 0; } @@ -643,9 +643,9 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) return error; /* Read new copy from disk if we don't have the latest */ - if (sdp->sd_rindex_vn != gl->gl_vn) { + if (!sdp->sd_rindex_uptodate) { mutex_lock(&sdp->sd_rindex_mutex); - if (sdp->sd_rindex_vn != gl->gl_vn) { + if (!sdp->sd_rindex_uptodate) { error = gfs2_ri_update(ip); if (error) gfs2_glock_dq_uninit(ri_gh); @@ -737,9 +737,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) } } - if (rgd->rd_rg_vn != gl->gl_vn) { + if (!(rgd->rd_flags & GFS2_RDF_UPTODATE)) { gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data); - rgd->rd_rg_vn = gl->gl_vn; + rgd->rd_flags |= GFS2_RDF_UPTODATE; } spin_lock(&sdp->sd_rindex_spin); -- cgit v1.2.3-70-g09d2 From 9a0045088d888c9c539c8c626a366cb52c0fbdab Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 1 Feb 2008 09:23:44 +0000 Subject: [GFS2] Shrink & rename di_depth This patch forms a pair with the previous patch which shrunk di_height. Like that patch di_depth is renamed i_depth and moved into struct gfs2_inode directly. Also the field goes from 16 bits to 8 bits since it is also limited to a max value which is rather small (17 in this case). In addition we also now validate the field against this maximum value when its read in. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 34 +++++++++++++++++----------------- fs/gfs2/incore.h | 2 +- fs/gfs2/inode.c | 11 +++++++---- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 78c236fb34e..081daa96a9d 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -757,7 +757,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { struct gfs2_leaf *leaf; - unsigned hsize = 1 << ip->i_di.di_depth; + unsigned hsize = 1 << ip->i_depth; unsigned index; u64 ln; if (hsize * sizeof(u64) != ip->i_di.di_size) { @@ -765,7 +765,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, return ERR_PTR(-EIO); } - index = name->hash >> (32 - ip->i_di.di_depth); + index = name->hash >> (32 - ip->i_depth); error = get_first_leaf(ip, index, &bh); if (error) return ERR_PTR(error); @@ -910,7 +910,7 @@ static int dir_make_exhash(struct inode *inode) dip->i_di.di_flags |= GFS2_DIF_EXHASH; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; - dip->i_di.di_depth = y; + dip->i_depth = y; gfs2_dinode_out(dip, dibh->b_data); @@ -941,7 +941,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) int x, moved = 0; int error; - index = name->hash >> (32 - dip->i_di.di_depth); + index = name->hash >> (32 - dip->i_depth); error = get_leaf_nr(dip, index, &leaf_no); if (error) return error; @@ -952,7 +952,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) return error; oleaf = (struct gfs2_leaf *)obh->b_data; - if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) { + if (dip->i_depth == be16_to_cpu(oleaf->lf_depth)) { brelse(obh); return 1; /* can't split */ } @@ -967,10 +967,10 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) bn = nbh->b_blocknr; /* Compute the start and len of leaf pointers in the hash table. */ - len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); + len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { - printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index); + printk(KERN_WARNING "i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; @@ -997,7 +997,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) kfree(lp); /* Compute the divider */ - divider = (start + half_len) << (32 - dip->i_di.di_depth); + divider = (start + half_len) << (32 - dip->i_depth); /* Copy the entries */ dirent_first(dip, obh, &dent); @@ -1082,7 +1082,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) int x; int error = 0; - hsize = 1 << dip->i_di.di_depth; + hsize = 1 << dip->i_depth; if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; @@ -1125,7 +1125,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { - dip->i_di.di_depth++; + dip->i_depth++; gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1370,14 +1370,14 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, int error = 0; unsigned depth = 0; - hsize = 1 << dip->i_di.di_depth; + hsize = 1 << dip->i_depth; if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; } hash = gfs2_dir_offset2hash(*offset); - index = hash >> (32 - dip->i_di.di_depth); + index = hash >> (32 - dip->i_depth); lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); if (!lp) @@ -1405,7 +1405,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, if (error) break; - len = 1 << (dip->i_di.di_depth - depth); + len = 1 << (dip->i_depth - depth); index = (index & ~(len - 1)) + len; } @@ -1549,7 +1549,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) u32 index; u64 bn; - index = name->hash >> (32 - ip->i_di.di_depth); + index = name->hash >> (32 - ip->i_depth); error = get_first_leaf(ip, index, &obh); if (error) return error; @@ -1641,7 +1641,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, continue; if (error < 0) break; - if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { + if (ip->i_depth < GFS2_DIR_MAX_DEPTH) { error = dir_double_exhash(ip); if (error) break; @@ -1785,7 +1785,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) u64 leaf_no; int error = 0; - hsize = 1 << dip->i_di.di_depth; + hsize = 1 << dip->i_depth; if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; @@ -1817,7 +1817,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (error) goto out; leaf = (struct gfs2_leaf *)bh->b_data; - len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); + len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); brelse(bh); error = lc(dip, index, len, leaf_no, data); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e9c58dc7686..9dfdde3612a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -246,7 +246,6 @@ struct gfs2_dinode_host { u64 di_generation; /* generation number for NFS */ u32 di_flags; /* GFS2_DIF_... */ /* These only apply to directories */ - u16 di_depth; /* Number of bits in the table */ u32 di_entries; /* The number of entries in the directory */ u64 di_eattr; /* extended attribute block number */ }; @@ -267,6 +266,7 @@ struct gfs2_inode { struct rw_semaphore i_rw_mutex; u8 i_height; + u8 i_depth; }; /* diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index db5961a9aa5..65fdfee9ca9 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -248,7 +248,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) { struct gfs2_dinode_host *di = &ip->i_di; const struct gfs2_dinode *str = buf; - u16 height; + u16 height, depth; if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) goto corrupt; @@ -293,7 +293,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) goto corrupt; ip->i_height = (u8)height; - di->di_depth = be16_to_cpu(str->di_depth); + depth = be16_to_cpu(str->di_depth); + if (unlikely(depth > GFS2_DIR_MAX_DEPTH)) + goto corrupt; + ip->i_depth = (u8)depth; di->di_entries = be32_to_cpu(str->di_entries); di->di_eattr = be64_to_cpu(str->di_eattr); @@ -1410,7 +1413,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? GFS2_FORMAT_DE : 0); - str->di_depth = cpu_to_be16(di->di_depth); + str->di_depth = cpu_to_be16(ip->i_depth); str->di_entries = cpu_to_be32(di->di_entries); str->di_eattr = cpu_to_be64(di->di_eattr); @@ -1436,7 +1439,7 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) (unsigned long long)di->di_goal_data); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); printk(KERN_INFO " i_height = %u\n", ip->i_height); - printk(KERN_INFO " di_depth = %u\n", di->di_depth); + printk(KERN_INFO " i_depth = %u\n", ip->i_depth); printk(KERN_INFO " di_entries = %u\n", di->di_entries); printk(KERN_INFO " di_eattr = %llu\n", (unsigned long long)di->di_eattr); -- cgit v1.2.3-70-g09d2 From 9feb7c889f2a3b088a7f6583e609bd39997c0f47 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 5 Feb 2008 17:11:40 -0600 Subject: [GFS2] Remove unused counters This is kind of trivial in the greater scheme of things, but this removes three counters that AFAICT are never used. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 3 --- fs/gfs2/sys.c | 6 ------ 2 files changed, 9 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 9dfdde3612a..b67e44baa73 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -636,9 +636,6 @@ struct gfs2_sbd { /* Counters */ - atomic_t sd_glock_count; - atomic_t sd_glock_held_count; - atomic_t sd_inode_count; atomic_t sd_reclaimed; char sd_fsname[GFS2_FSNAME_LEN]; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index cc35ec862ee..9ab9fc85ecd 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -327,15 +327,9 @@ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ } \ static struct counters_attr counters_attr_##name = __ATTR_RO(name) -COUNTERS_ATTR(glock_count, "%u\n"); -COUNTERS_ATTR(glock_held_count, "%u\n"); -COUNTERS_ATTR(inode_count, "%u\n"); COUNTERS_ATTR(reclaimed, "%u\n"); static struct attribute *counters_attrs[] = { - &counters_attr_glock_count.attr, - &counters_attr_glock_held_count.attr, - &counters_attr_inode_count.attr, &counters_attr_reclaimed.attr, NULL, }; -- cgit v1.2.3-70-g09d2 From ce276b06e8b81845926387e93f77bf81e14b5cc2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 6 Feb 2008 09:25:45 +0000 Subject: [GFS2] Reduce inode size by merging fields There were three fields being used to keep track of the location of the most recently allocated block for each inode. These have been merged into a single field in order to better keep the data and metadata for an inode close on disk, and also to reduce the space required for storage. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 4 +--- fs/gfs2/incore.h | 5 +---- fs/gfs2/inode.c | 13 +++++-------- fs/gfs2/rgrp.c | 40 +++++++++++++++++----------------------- 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 2011dd27f8d..30d718b3438 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1020,9 +1020,7 @@ static int trunc_end(struct gfs2_inode *ip) if (!ip->i_di.di_size) { ip->i_height = 0; - ip->i_di.di_goal_meta = - ip->i_di.di_goal_data = - ip->i_no_addr; + ip->i_goal = ip->i_no_addr; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); } ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b67e44baa73..c50dcdf7992 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -241,8 +241,6 @@ enum { struct gfs2_dinode_host { u64 di_size; /* number of bytes in file */ u64 di_blocks; /* number of blocks in file */ - u64 di_goal_meta; /* rgrp to alloc from next */ - u64 di_goal_data; /* data block goal */ u64 di_generation; /* generation number for NFS */ u32 di_flags; /* GFS2_DIF_... */ /* These only apply to directories */ @@ -262,8 +260,7 @@ struct gfs2_inode { struct gfs2_holder i_iopen_gh; struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_alloc *i_alloc; - u64 i_last_rg_alloc; - + u64 i_goal; /* goal block for allocations */ struct rw_semaphore i_rw_mutex; u8 i_height; u8 i_depth; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 65fdfee9ca9..c3fe8aa03c4 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -282,8 +282,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); - di->di_goal_meta = be64_to_cpu(str->di_goal_meta); - di->di_goal_data = be64_to_cpu(str->di_goal_data); + ip->i_goal = be64_to_cpu(str->di_goal_meta); di->di_generation = be64_to_cpu(str->di_generation); di->di_flags = be32_to_cpu(str->di_flags); @@ -1404,8 +1403,8 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); - str->di_goal_meta = cpu_to_be64(di->di_goal_meta); - str->di_goal_data = cpu_to_be64(di->di_goal_data); + str->di_goal_meta = cpu_to_be64(ip->i_goal); + str->di_goal_data = cpu_to_be64(ip->i_goal); str->di_generation = cpu_to_be64(di->di_generation); str->di_flags = cpu_to_be32(di->di_flags); @@ -1433,10 +1432,8 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks); - printk(KERN_INFO " di_goal_meta = %llu\n", - (unsigned long long)di->di_goal_meta); - printk(KERN_INFO " di_goal_data = %llu\n", - (unsigned long long)di->di_goal_data); + printk(KERN_INFO " i_goal = %llu\n", + (unsigned long long)ip->i_goal); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); printk(KERN_INFO " i_height = %u\n", ip->i_height); printk(KERN_INFO " i_depth = %u\n", ip->i_depth); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 3f10b1fafd6..66193b45e50 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -915,24 +915,20 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, u64 rglast) { - struct gfs2_rgrpd *rgd = NULL; + struct gfs2_rgrpd *rgd; spin_lock(&sdp->sd_rindex_spin); - if (list_empty(&sdp->sd_rindex_recent_list)) - goto out; - - if (!rglast) - goto first; - - list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { - if (rgd->rd_addr == rglast) - goto out; + if (rglast) { + list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { + if (rgrp_contains_block(rgd, rglast)) + goto out; + } } - -first: - rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd, - rd_recent); + rgd = NULL; + if (!list_empty(&sdp->sd_rindex_recent_list)) + rgd = list_entry(sdp->sd_rindex_recent_list.next, + struct gfs2_rgrpd, rd_recent); out: spin_unlock(&sdp->sd_rindex_spin); return rgd; @@ -1078,7 +1074,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) /* Try recently successful rgrps */ - rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); + rgd = recent_rgrp_first(sdp, ip->i_goal); while (rgd) { rg_locked = 0; @@ -1162,8 +1158,6 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) } out: - ip->i_last_rg_alloc = rgd->rd_addr; - if (begin) { recent_rgrp_add(rgd); rgd = gfs2_rgrpd_get_next(rgd); @@ -1425,8 +1419,8 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) u32 goal, blk; u64 block; - if (rgrp_contains_block(rgd, ip->i_di.di_goal_data)) - goal = ip->i_di.di_goal_data - rgd->rd_data0; + if (rgrp_contains_block(rgd, ip->i_goal)) + goal = ip->i_goal - rgd->rd_data0; else goal = rgd->rd_last_alloc_data; @@ -1435,7 +1429,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) rgd->rd_last_alloc_data = blk; block = rgd->rd_data0 + blk; - ip->i_di.di_goal_data = block; + ip->i_goal = block; gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); rgd->rd_rg.rg_free--; @@ -1470,8 +1464,8 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) u32 goal, blk; u64 block; - if (rgrp_contains_block(rgd, ip->i_di.di_goal_meta)) - goal = ip->i_di.di_goal_meta - rgd->rd_data0; + if (rgrp_contains_block(rgd, ip->i_goal)) + goal = ip->i_goal - rgd->rd_data0; else goal = rgd->rd_last_alloc_meta; @@ -1480,7 +1474,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) rgd->rd_last_alloc_meta = blk; block = rgd->rd_data0 + blk; - ip->i_di.di_goal_meta = block; + ip->i_goal = block; gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); rgd->rd_rg.rg_free--; -- cgit v1.2.3-70-g09d2 From ac576cc5bed0dd7759e2b196468c7df93d6aeeee Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 1 Feb 2008 10:34:15 +0000 Subject: [GFS2] Merge the rd_last_alloc_meta and rd_last_alloc_data fields We don't need to keep track of when we last allocated data and metadata separately since the only thing thats important when searching for a free block is whether its free or not, which is independent from what type of block it is. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 3 +-- fs/gfs2/rgrp.c | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index c50dcdf7992..898b456b386 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -90,8 +90,7 @@ struct gfs2_rgrpd { struct mutex rd_mutex; u32 rd_free_clone; struct gfs2_log_element rd_le; - u32 rd_last_alloc_data; - u32 rd_last_alloc_meta; + u32 rd_last_alloc; struct gfs2_sbd *rd_sbd; unsigned char rd_flags; #define GFS2_RDF_CHECK 0x01 /* Need to check for unlinked inodes */ diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 66193b45e50..cc28845ba6f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1422,11 +1422,11 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) if (rgrp_contains_block(rgd, ip->i_goal)) goal = ip->i_goal - rgd->rd_data0; else - goal = rgd->rd_last_alloc_data; + goal = rgd->rd_last_alloc; blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); BUG_ON(blk == BFITNOENT); - rgd->rd_last_alloc_data = blk; + rgd->rd_last_alloc = blk; block = rgd->rd_data0 + blk; ip->i_goal = block; @@ -1467,11 +1467,11 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) if (rgrp_contains_block(rgd, ip->i_goal)) goal = ip->i_goal - rgd->rd_data0; else - goal = rgd->rd_last_alloc_meta; + goal = rgd->rd_last_alloc; blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); BUG_ON(blk == BFITNOENT); - rgd->rd_last_alloc_meta = blk; + rgd->rd_last_alloc = blk; block = rgd->rd_data0 + blk; ip->i_goal = block; @@ -1510,11 +1510,11 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) u32 blk; u64 block; - blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, + blk = rgblk_search(rgd, rgd->rd_last_alloc, GFS2_BLKST_FREE, GFS2_BLKST_DINODE); BUG_ON(blk == BFITNOENT); - rgd->rd_last_alloc_meta = blk; + rgd->rd_last_alloc = blk; block = rgd->rd_data0 + blk; -- cgit v1.2.3-70-g09d2 From 5731be53e3d82aedd06e02574f833a57b07a08d2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 1 Feb 2008 13:16:55 +0000 Subject: [GFS2] Update gfs2_trans_add_unrevoke to accept extents By adding an extra argument to gfs2_trans_add_unrevoke we can now specify an extent length of blocks to unrevoke. This means that we only need to make one pass through the list for each extent rather than each block. Currently the only extent length which is used is 1, but that will change in the future. Also gfs2_trans_add_unrevoke is removed from gfs2_alloc_meta since its the only difference between this and gfs2_alloc_data which is left. This will allow a future patch to merge these two functions into one (i.e. one call to allocate both data and metadata in a single extent in the future). Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 7 +++++-- fs/gfs2/dir.c | 2 +- fs/gfs2/eattr.c | 6 +++--- fs/gfs2/rgrp.c | 3 +-- fs/gfs2/trans.c | 25 ++++++++++--------------- fs/gfs2/trans.h | 2 +- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 30d718b3438..651e5320bb4 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -138,7 +138,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) if (isdir) { block = gfs2_alloc_meta(ip); - + gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1); error = gfs2_dir_get_new_buffer(ip, block, &bh); if (error) goto out_brelse; @@ -206,6 +206,7 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh for(n = 0; n < new_height; n++) { bn = gfs2_alloc_meta(ip); + gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn); gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1); } @@ -370,8 +371,10 @@ static int lookup_block(struct gfs2_inode *ip, unsigned int height, if (height == ip->i_height - 1 && !gfs2_is_dir(ip)) *block = gfs2_alloc_data(ip); - else + else { *block = gfs2_alloc_meta(ip); + gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1); + } gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 081daa96a9d..55514ee06dd 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -810,7 +810,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, struct qstr name = { .name = "", .len = 0, .hash = 0 }; if (!bh) return NULL; - + gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); leaf = (struct gfs2_leaf *)bh->b_data; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 04febbc17a1..c7fa0a8b164 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -585,7 +585,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) u64 block; block = gfs2_alloc_meta(ip); - + gfs2_trans_add_unrevoke(sdp, block, 1); *bhp = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, *bhp, 1); gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); @@ -644,7 +644,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, int mh_size = sizeof(struct gfs2_meta_header); block = gfs2_alloc_meta(ip); - + gfs2_trans_add_unrevoke(sdp, block, 1); bh = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); @@ -968,7 +968,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, u64 blk; blk = gfs2_alloc_meta(ip); - + gfs2_trans_add_unrevoke(sdp, blk, 1); indbh = gfs2_meta_new(ip->i_gl, blk); gfs2_trans_add_bh(ip->i_gl, indbh, 1); gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index cc28845ba6f..9f28463e62e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1486,7 +1486,6 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) gfs2_statfs_change(sdp, 0, -1, 0); gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); - gfs2_trans_add_unrevoke(sdp, block); spin_lock(&sdp->sd_rindex_spin); rgd->rd_free_clone--; @@ -1528,7 +1527,7 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) al->al_alloced++; gfs2_statfs_change(sdp, 0, -1, +1); - gfs2_trans_add_unrevoke(sdp, block); + gfs2_trans_add_unrevoke(sdp, block, 1); spin_lock(&sdp->sd_rindex_spin); rgd->rd_free_clone--; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 73e5d92a657..f677b8a83f0 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -146,30 +146,25 @@ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) lops_add(sdp, &bd->bd_le); } -void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len) { - struct gfs2_bufdata *bd; - int found = 0; + struct gfs2_bufdata *bd, *tmp; + struct gfs2_trans *tr = current->journal_info; + unsigned int n = len; gfs2_log_lock(sdp); - - list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) { - if (bd->bd_blkno == blkno) { + list_for_each_entry_safe(bd, tmp, &sdp->sd_log_le_revoke, bd_le.le_list) { + if ((bd->bd_blkno >= blkno) && (bd->bd_blkno < (blkno + len))) { list_del_init(&bd->bd_le.le_list); gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; - found = 1; - break; + kmem_cache_free(gfs2_bufdata_cachep, bd); + tr->tr_num_revoke_rm++; + if (--n == 0) + break; } } - gfs2_log_unlock(sdp); - - if (found) { - struct gfs2_trans *tr = current->journal_info; - kmem_cache_free(gfs2_bufdata_cachep, bd); - tr->tr_num_revoke_rm++; - } } void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd) diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index e826f0dab80..edf9d4bd908 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp); void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); -void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); #endif /* __TRANS_DOT_H__ */ -- cgit v1.2.3-70-g09d2 From 1639431a3f57b43da1e15e9268a1d691ac01ba26 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 1 Feb 2008 14:52:30 +0000 Subject: [GFS2] Merge gfs2_alloc_meta and gfs2_alloc_data Thanks to the preceeding patches, the only difference between these two functions is their name. We can thus merge them and call the new function gfs2_alloc_block to reflect the fact that it can allocate either kind of block. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 13 +++++-------- fs/gfs2/dir.c | 2 +- fs/gfs2/eattr.c | 6 +++--- fs/gfs2/rgrp.c | 51 +++------------------------------------------------ fs/gfs2/rgrp.h | 3 +-- 5 files changed, 13 insertions(+), 62 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 651e5320bb4..e3a75a27cee 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -137,7 +137,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) and write it out to disk */ if (isdir) { - block = gfs2_alloc_meta(ip); + block = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1); error = gfs2_dir_get_new_buffer(ip, block, &bh); if (error) @@ -146,7 +146,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) dibh, sizeof(struct gfs2_dinode)); brelse(bh); } else { - block = gfs2_alloc_data(ip); + block = gfs2_alloc_block(ip); error = gfs2_unstuffer_page(ip, dibh, block, page); if (error) @@ -205,7 +205,7 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh return error; for(n = 0; n < new_height; n++) { - bn = gfs2_alloc_meta(ip); + bn = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn); gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1); @@ -369,12 +369,9 @@ static int lookup_block(struct gfs2_inode *ip, unsigned int height, if (!create) return 0; - if (height == ip->i_height - 1 && !gfs2_is_dir(ip)) - *block = gfs2_alloc_data(ip); - else { - *block = gfs2_alloc_meta(ip); + *block = gfs2_alloc_block(ip); + if (height != ip->i_height - 1 || gfs2_is_dir(ip)) gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1); - } gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 55514ee06dd..fbdf31957cb 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -803,7 +803,7 @@ got_dent: static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { struct gfs2_inode *ip = GFS2_I(inode); - u64 bn = gfs2_alloc_meta(ip); + u64 bn = gfs2_alloc_block(ip); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; struct gfs2_dirent *dent; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index c7fa0a8b164..f9f63bc21cd 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -584,7 +584,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) struct gfs2_ea_header *ea; u64 block; - block = gfs2_alloc_meta(ip); + block = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(sdp, block, 1); *bhp = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, *bhp, 1); @@ -643,7 +643,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, u64 block; int mh_size = sizeof(struct gfs2_meta_header); - block = gfs2_alloc_meta(ip); + block = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(sdp, block, 1); bh = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, bh, 1); @@ -967,7 +967,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, } else { u64 blk; - blk = gfs2_alloc_meta(ip); + blk = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(sdp, blk, 1); indbh = gfs2_meta_new(ip->i_gl, blk); gfs2_trans_add_bh(ip->i_gl, indbh, 1); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 9f28463e62e..274a2df13f0 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1405,58 +1405,13 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, } /** - * gfs2_alloc_data - Allocate a data block - * @ip: the inode to allocate the data block for + * gfs2_alloc_block - Allocate a block + * @ip: the inode to allocate the block for * * Returns: the allocated block */ -u64 gfs2_alloc_data(struct gfs2_inode *ip) -{ - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = ip->i_alloc; - struct gfs2_rgrpd *rgd = al->al_rgd; - u32 goal, blk; - u64 block; - - if (rgrp_contains_block(rgd, ip->i_goal)) - goal = ip->i_goal - rgd->rd_data0; - else - goal = rgd->rd_last_alloc; - - blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); - BUG_ON(blk == BFITNOENT); - rgd->rd_last_alloc = blk; - - block = rgd->rd_data0 + blk; - ip->i_goal = block; - - gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); - rgd->rd_rg.rg_free--; - - gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); - gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); - - al->al_alloced++; - - gfs2_statfs_change(sdp, 0, -1, 0); - gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); - - spin_lock(&sdp->sd_rindex_spin); - rgd->rd_free_clone--; - spin_unlock(&sdp->sd_rindex_spin); - - return block; -} - -/** - * gfs2_alloc_meta - Allocate a metadata block - * @ip: the inode to allocate the metadata block for - * - * Returns: the allocated block - */ - -u64 gfs2_alloc_meta(struct gfs2_inode *ip) +u64 gfs2_alloc_block(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = ip->i_alloc; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 5683605695f..5e66613b33d 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -46,8 +46,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip); unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); -u64 gfs2_alloc_data(struct gfs2_inode *ip); -u64 gfs2_alloc_meta(struct gfs2_inode *ip); +u64 gfs2_alloc_block(struct gfs2_inode *ip); u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); -- cgit v1.2.3-70-g09d2 From b45e41d7d56dfef1ae9e02e6c59990066ba82e5c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 6 Feb 2008 10:11:15 +0000 Subject: [GFS2] Add extent allocation to block allocator Rather than having to allocate a single block at a time, this patch allows the block allocator to allocate an extent. Since there is no difference (so far as the block allocator is concerned) between data blocks and indirect blocks, it is posible to allocate a single extent and for the caller to unrevoke just the blocks required for indirect blocks. Currently the only bit of GFS2 to make use of this feature is the build height function. The intention is that gfs2_block_map will be changed to make use of this feature in future patches. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 26 ++++++++------- fs/gfs2/dir.c | 3 +- fs/gfs2/eattr.c | 10 +++--- fs/gfs2/rgrp.c | 100 +++++++++++++++++++++++++++++++++++--------------------- fs/gfs2/rgrp.h | 2 +- 5 files changed, 87 insertions(+), 54 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e3a75a27cee..1fda731c074 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -136,8 +136,9 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) /* Get a free block, fill it with the stuffed data, and write it out to disk */ + unsigned int n = 1; + block = gfs2_alloc_block(ip, &n); if (isdir) { - block = gfs2_alloc_block(ip); gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1); error = gfs2_dir_get_new_buffer(ip, block, &bh); if (error) @@ -146,8 +147,6 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) dibh, sizeof(struct gfs2_dinode)); brelse(bh); } else { - block = gfs2_alloc_block(ip); - error = gfs2_unstuffer_page(ip, dibh, block, page); if (error) goto out_brelse; @@ -195,7 +194,7 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh int error; __be64 *bp; u64 bn; - unsigned n; + unsigned n, i = 0; if (height <= ip->i_height) return 0; @@ -204,12 +203,16 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh if (error) return error; - for(n = 0; n < new_height; n++) { - bn = gfs2_alloc_block(ip); - gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); - mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn); - gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1); - } + do { + n = new_height - i; + bn = gfs2_alloc_block(ip, &n); + gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, n); + do { + mp->mp_bh[i] = gfs2_meta_new(ip->i_gl, bn++); + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i], 1); + i++; + } while(i < n); + } while(i < new_height); n = 0; bn = mp->mp_bh[0]->b_blocknr; @@ -358,6 +361,7 @@ static int lookup_block(struct gfs2_inode *ip, unsigned int height, { int boundary; __be64 *ptr = metapointer(&boundary, height, mp); + unsigned int n = 1; if (*ptr) { *block = be64_to_cpu(*ptr); @@ -369,7 +373,7 @@ static int lookup_block(struct gfs2_inode *ip, unsigned int height, if (!create) return 0; - *block = gfs2_alloc_block(ip); + *block = gfs2_alloc_block(ip, &n); if (height != ip->i_height - 1 || gfs2_is_dir(ip)) gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index fbdf31957cb..93a2e6afbd8 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -803,7 +803,8 @@ got_dent: static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { struct gfs2_inode *ip = GFS2_I(inode); - u64 bn = gfs2_alloc_block(ip); + unsigned int n = 1; + u64 bn = gfs2_alloc_block(ip, &n); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; struct gfs2_dirent *dent; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index f9f63bc21cd..0e79cd54349 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -582,9 +582,10 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_ea_header *ea; + unsigned int n = 1; u64 block; - block = gfs2_alloc_block(ip); + block = gfs2_alloc_block(ip, &n); gfs2_trans_add_unrevoke(sdp, block, 1); *bhp = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, *bhp, 1); @@ -642,8 +643,9 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, struct buffer_head *bh; u64 block; int mh_size = sizeof(struct gfs2_meta_header); + unsigned int n = 1; - block = gfs2_alloc_block(ip); + block = gfs2_alloc_block(ip, &n); gfs2_trans_add_unrevoke(sdp, block, 1); bh = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, bh, 1); @@ -966,8 +968,8 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, gfs2_trans_add_bh(ip->i_gl, indbh, 1); } else { u64 blk; - - blk = gfs2_alloc_block(ip); + unsigned int n = 1; + blk = gfs2_alloc_block(ip, &n); gfs2_trans_add_unrevoke(sdp, blk, 1); indbh = gfs2_meta_new(ip->i_gl, blk); gfs2_trans_add_bh(ip->i_gl, indbh, 1); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 274a2df13f0..77eba0a3804 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -53,7 +53,8 @@ static const char valid_change[16] = { }; static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, - unsigned char old_state, unsigned char new_state); + unsigned char old_state, unsigned char new_state, + unsigned int *n); /** * gfs2_setbit - Set a bit in the bitmaps @@ -64,26 +65,32 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, * */ -static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, u32 block, - unsigned char new_state) +static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf1, + unsigned char *buf2, unsigned int offset, + unsigned int buflen, u32 block, + unsigned char new_state) { - unsigned char *byte, *end, cur_state; - unsigned int bit; + unsigned char *byte1, *byte2, *end, cur_state; + const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; - byte = buffer + (block / GFS2_NBBY); - bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; - end = buffer + buflen; + byte1 = buf1 + offset + (block / GFS2_NBBY); + end = buf1 + offset + buflen; - gfs2_assert(rgd->rd_sbd, byte < end); + BUG_ON(byte1 >= end); - cur_state = (*byte >> bit) & GFS2_BIT_MASK; + cur_state = (*byte1 >> bit) & GFS2_BIT_MASK; - if (valid_change[new_state * 4 + cur_state]) { - *byte ^= cur_state << bit; - *byte |= new_state << bit; - } else + if (unlikely(!valid_change[new_state * 4 + cur_state])) { gfs2_consist_rgrpd(rgd); + return; + } + *byte1 ^= (cur_state ^ new_state) << bit; + + if (buf2) { + byte2 = buf2 + offset + (block / GFS2_NBBY); + cur_state = (*byte2 >> bit) & GFS2_BIT_MASK; + *byte2 ^= (cur_state ^ new_state) << bit; + } } /** @@ -94,10 +101,12 @@ static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * */ -static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, u32 block) +static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, + const unsigned char *buffer, + unsigned int buflen, u32 block) { - unsigned char *byte, *end, cur_state; + const unsigned char *byte, *end; + unsigned char cur_state; unsigned int bit; byte = buffer + (block / GFS2_NBBY); @@ -877,13 +886,15 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) u32 goal = 0, block; u64 no_addr; struct gfs2_sbd *sdp = rgd->rd_sbd; + unsigned int n; for(;;) { if (goal >= rgd->rd_data) break; down_write(&sdp->sd_log_flush_lock); + n = 1; block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, - GFS2_BLKST_UNLINKED); + GFS2_BLKST_UNLINKED, &n); up_write(&sdp->sd_log_flush_lock); if (block == BFITNOENT) break; @@ -1280,6 +1291,7 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) * @goal: the goal block within the RG (start here to search for avail block) * @old_state: GFS2_BLKST_XXX the before-allocation state to find * @new_state: GFS2_BLKST_XXX the after-allocation block state + * @n: The extent length * * Walk rgrp's bitmap to find bits that represent a block in @old_state. * Add the found bitmap buffer to the transaction. @@ -1295,13 +1307,17 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) */ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, - unsigned char old_state, unsigned char new_state) + unsigned char old_state, unsigned char new_state, + unsigned int *n) { struct gfs2_bitmap *bi = NULL; - u32 length = rgd->rd_length; + const u32 length = rgd->rd_length; u32 blk = 0; unsigned int buf, x; + const unsigned int elen = *n; + const u8 *buffer; + *n = 0; /* Find bitmap block that contains bits for goal block */ for (buf = 0; buf < length; buf++) { bi = rgd->rd_bits + buf; @@ -1322,7 +1338,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, for (x = 0; x <= length; x++) { /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone bitmaps, so we must search the originals for that. */ - const u8 *buffer = bi->bi_bh->b_data + bi->bi_offset; + buffer = bi->bi_bh->b_data + bi->bi_offset; if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) buffer = bi->bi_clone + bi->bi_offset; @@ -1337,12 +1353,21 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, } if (blk != BFITNOENT && old_state != new_state) { + *n = 1; gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); - gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, + gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, bi->bi_len, blk, new_state); - if (bi->bi_clone) - gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, - bi->bi_len, blk, new_state); + while(*n < elen) { + goal++; + if (goal >= (bi->bi_len / GFS2_NBBY)) + break; + if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) != + GFS2_BLKST_FREE) + break; + (*n)++; + gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, + bi->bi_offset, bi->bi_len, blk, new_state); + } } return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk; @@ -1397,7 +1422,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, bi->bi_len); } gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); - gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, + gfs2_setbit(rgd, bi->bi_bh->b_data, NULL, bi->bi_offset, bi->bi_len, buf_blk, new_state); } @@ -1411,7 +1436,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, * Returns: the allocated block */ -u64 gfs2_alloc_block(struct gfs2_inode *ip) +u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = ip->i_alloc; @@ -1424,26 +1449,26 @@ u64 gfs2_alloc_block(struct gfs2_inode *ip) else goal = rgd->rd_last_alloc; - blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); + blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED, n); BUG_ON(blk == BFITNOENT); - rgd->rd_last_alloc = blk; + rgd->rd_last_alloc = blk; block = rgd->rd_data0 + blk; ip->i_goal = block; - gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); - rgd->rd_rg.rg_free--; + gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free >= *n); + rgd->rd_rg.rg_free -= *n; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); - al->al_alloced++; + al->al_alloced += *n; - gfs2_statfs_change(sdp, 0, -1, 0); - gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); + gfs2_statfs_change(sdp, 0, -*n, 0); + gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid); spin_lock(&sdp->sd_rindex_spin); - rgd->rd_free_clone--; + rgd->rd_free_clone -= *n; spin_unlock(&sdp->sd_rindex_spin); return block; @@ -1463,9 +1488,10 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) struct gfs2_rgrpd *rgd = al->al_rgd; u32 blk; u64 block; + unsigned int n = 1; blk = rgblk_search(rgd, rgd->rd_last_alloc, - GFS2_BLKST_FREE, GFS2_BLKST_DINODE); + GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n); BUG_ON(blk == BFITNOENT); rgd->rd_last_alloc = blk; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 5e66613b33d..3181c7e624b 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -46,7 +46,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip); unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); -u64 gfs2_alloc_block(struct gfs2_inode *ip); +u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n); u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); -- cgit v1.2.3-70-g09d2 From c85a665f064863cc8a2fe88e5f1eb4def5446e90 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 12 Feb 2008 12:14:59 +0000 Subject: [GFS2] The case of the missing asterisk A dereference was forgotten. This adds it back correctly. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 1fda731c074..7f72564e059 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -402,7 +402,7 @@ static int lookup_metapath(struct inode *inode, struct metapath *mp, for (x = 0; x < end_of_metadata; x++) { lookup_block(ip, x, mp, create, new, dblock); - if (!dblock) + if (!*dblock) return 0; ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &mp->mp_bh[x+1]); -- cgit v1.2.3-70-g09d2 From 30cbf189cd2a1ba13ff3c8c8ee2103dbdb18578a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 8 Feb 2008 13:18:11 +0000 Subject: [GFS2] Add a function to interate over an extent This adds a function (currently the only use is during mapping of already allocated blocks, but watch this space) which iterates over a number of pointers in a block and returns the extent length. If the initial pointer is 0 (i.e. unallocated) it will return the number of unallocated blocks in the extent. If the initial pointer is allocated, then it returns the number of contiguously allocated blocks in the extent. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 68 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 7f72564e059..6780aa5841b 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -422,6 +422,42 @@ static void release_metapath(struct metapath *mp) brelse(mp->mp_bh[i]); } +/** + * gfs2_extent_length - Returns length of an extent of blocks + * @start: Start of the buffer + * @len: Length of the buffer in bytes + * @ptr: Current position in the buffer + * @limit: Max extent length to return (0 = unlimited) + * @eob: Set to 1 if we hit "end of block" + * + * If the first block is zero (unallocated) it will return the number of + * unallocated blocks in the extent, otherwise it will return the number + * of contiguous blocks in the extent. + * + * Returns: The length of the extent (minimum of one block) + */ + +static inline unsigned int gfs2_extent_length(void *start, unsigned int len, __be64 *ptr, unsigned limit, int *eob) +{ + const __be64 *end = (start + len); + const __be64 *first = ptr; + u64 d = be64_to_cpu(*ptr); + + *eob = 0; + do { + ptr++; + if (ptr >= end) + break; + if (limit && --limit == 0) + break; + if (d) + d++; + } while(be64_to_cpu(*ptr) == d); + if (ptr >= end) + *eob = 1; + return (ptr - first); +} + static inline void bmap_lock(struct inode *inode, int create) { struct gfs2_inode *ip = GFS2_I(inode); @@ -499,26 +535,26 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, goto out_fail; boundary = error; + if (new) { + map_bh(bh_map, inode->i_sb, dblock); + if (boundary) + set_buffer_boundary(bh_map); + gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); + gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); + set_buffer_new(bh_map); + goto out_ok; + } + if (dblock) { + unsigned int len; + struct buffer_head *bh = mp.mp_bh[ip->i_height - 1]; + __be64 *ptr = metapointer(&boundary, ip->i_height - 1, &mp); map_bh(bh_map, inode->i_sb, dblock); + len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, + &boundary); + bh_map->b_size = (len << inode->i_blkbits); if (boundary) set_buffer_boundary(bh_map); - if (new) { - gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); - gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); - set_buffer_new(bh_map); - goto out_ok; - } - while(--maxlen && !buffer_boundary(bh_map)) { - u64 eblock; - mp.mp_list[ip->i_height - 1]++; - boundary = lookup_block(ip, ip->i_height - 1, &mp, 0, &new, &eblock); - if (eblock != ++dblock) - break; - bh_map->b_size += (1 << inode->i_blkbits); - if (boundary) - set_buffer_boundary(bh_map); - } } out_ok: error = 0; -- cgit v1.2.3-70-g09d2 From 77658aad226866fb94097236d14d41a88aaab2ec Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 12 Feb 2008 14:17:27 +0000 Subject: [GFS2] Eliminate (almost) duplicate field from gfs2_inode The blocks counter is almost a duplicate of the i_blocks field in the VFS inode. The only difference is that i_blocks can be only 32bits long for 32bit arch without large single file support. Since GFS2 doesn't handle the non-large single file case (for 32 bit anyway) this adds a new config dependency on 64BIT || LSF. This has always been the case, however we've never explicitly said so before. Even if we do add support for the non-LSF case, we will still not require this field to be duplicated since we will not be able to access oversized files anyway. So the net result of all this is that we shave 8 bytes from a gfs2_inode and get our config deps correct. Signed-off-by: Steven Whitehouse --- fs/gfs2/Kconfig | 2 +- fs/gfs2/bmap.c | 18 ++++++------------ fs/gfs2/dir.c | 15 ++++----------- fs/gfs2/eattr.c | 24 ++++++------------------ fs/gfs2/incore.h | 1 - fs/gfs2/inode.c | 11 +++++------ fs/gfs2/inode.h | 20 +++++++++++++++++--- fs/gfs2/ops_inode.c | 5 +++-- 8 files changed, 42 insertions(+), 54 deletions(-) diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index de8e64c03f7..d147b53ef52 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -1,6 +1,6 @@ config GFS2_FS tristate "GFS2 file system support" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && (64BIT || LSF) select FS_POSIX_ACL select CRC32 help diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 6780aa5841b..e27e66046f0 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -161,9 +161,8 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) if (ip->i_di.di_size) { *(__be64 *)(di + 1) = cpu_to_be64(block); - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); - di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); + gfs2_add_inode_blocks(&ip->i_inode, 1); + di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); } ip->i_height = 1; @@ -238,10 +237,9 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); *(__be64 *)(di + 1) = cpu_to_be64(bn); ip->i_height += new_height; - ip->i_di.di_blocks += new_height; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, new_height); di->di_height = cpu_to_be16(ip->i_height); - di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); + di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); brelse(dibh); return error; } @@ -380,8 +378,7 @@ static int lookup_block(struct gfs2_inode *ip, unsigned int height, gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); *ptr = cpu_to_be64(*block); - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, 1); *new = 1; return 0; @@ -779,10 +776,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, } *p = 0; - if (!ip->i_di.di_blocks) - gfs2_consist_inode(ip); - ip->i_di.di_blocks--; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, -1); } if (bstart) { if (metadata) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 93a2e6afbd8..862aa3228f7 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -906,8 +906,7 @@ static int dir_make_exhash(struct inode *inode) *lp = cpu_to_be64(bn); dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; - dip->i_di.di_blocks++; - gfs2_set_inode_blocks(&dip->i_inode); + gfs2_add_inode_blocks(&dip->i_inode, 1); dip->i_di.di_flags |= GFS2_DIF_EXHASH; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; @@ -1045,8 +1044,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { gfs2_trans_add_bh(dip->i_gl, dibh, 1); - dip->i_di.di_blocks++; - gfs2_set_inode_blocks(&dip->i_inode); + gfs2_add_inode_blocks(&dip->i_inode, 1); gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1580,8 +1578,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) if (error) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, 1); gfs2_dinode_out(ip, bh->b_data); brelse(bh); return 0; @@ -1922,11 +1919,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, brelse(bh); gfs2_free_meta(dip, blk, 1); - - if (!dip->i_di.di_blocks) - gfs2_consist_inode(dip); - dip->i_di.di_blocks--; - gfs2_set_inode_blocks(&dip->i_inode); + gfs2_add_inode_blocks(&dip->i_inode, -1); } error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 0e79cd54349..76ead1acfcc 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -277,10 +277,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, } *dataptrs = 0; - if (!ip->i_di.di_blocks) - gfs2_consist_inode(ip); - ip->i_di.di_blocks--; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, -1); } if (bstart) gfs2_free_meta(ip, bstart, blen); @@ -598,8 +595,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) ea->ea_flags = GFS2_EAFLAG_LAST; ea->ea_num_ptrs = 0; - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, 1); return 0; } @@ -651,8 +647,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, 1); copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize : data_len; @@ -980,8 +975,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, *eablk = cpu_to_be64(ip->i_di.di_eattr); ip->i_di.di_eattr = blk; ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT; - ip->i_di.di_blocks++; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, 1); eablk++; } @@ -1389,10 +1383,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) } *eablk = 0; - if (!ip->i_di.di_blocks) - gfs2_consist_inode(ip); - ip->i_di.di_blocks--; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, -1); } if (bstart) gfs2_free_meta(ip, bstart, blen); @@ -1444,10 +1435,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip) gfs2_free_meta(ip, ip->i_di.di_eattr, 1); ip->i_di.di_eattr = 0; - if (!ip->i_di.di_blocks) - gfs2_consist_inode(ip); - ip->i_di.di_blocks--; - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_add_inode_blocks(&ip->i_inode, -1); error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 898b456b386..4ba2ea63119 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -239,7 +239,6 @@ enum { struct gfs2_dinode_host { u64 di_size; /* number of bytes in file */ - u64 di_blocks; /* number of blocks in file */ u64 di_generation; /* generation number for NFS */ u32 di_flags; /* GFS2_DIF_... */ /* These only apply to directories */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c3fe8aa03c4..5f50dd53bf6 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -273,8 +273,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); di->di_size = be64_to_cpu(str->di_size); i_size_write(&ip->i_inode, di->di_size); - di->di_blocks = be64_to_cpu(str->di_blocks); - gfs2_set_inode_blocks(&ip->i_inode); + gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime); ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); @@ -344,7 +343,7 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) struct gfs2_rgrpd *rgd; int error; - if (ip->i_di.di_blocks != 1) { + if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; @@ -1398,7 +1397,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_gid = cpu_to_be32(ip->i_inode.i_gid); str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); str->di_size = cpu_to_be64(di->di_size); - str->di_blocks = cpu_to_be64(di->di_blocks); + str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); @@ -1430,8 +1429,8 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)ip->i_no_addr); printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); - printk(KERN_INFO " di_blocks = %llu\n", - (unsigned long long)di->di_blocks); + printk(KERN_INFO " blocks = %llu\n", + (unsigned long long)gfs2_get_inode_blocks(&ip->i_inode)); printk(KERN_INFO " i_goal = %llu\n", (unsigned long long)ip->i_goal); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index db738686ca1..580da454b38 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -10,6 +10,8 @@ #ifndef __INODE_DOT_H__ #define __INODE_DOT_H__ +#include "util.h" + static inline int gfs2_is_stuffed(const struct gfs2_inode *ip) { return !ip->i_height; @@ -37,13 +39,25 @@ static inline int gfs2_is_dir(const struct gfs2_inode *ip) return S_ISDIR(ip->i_inode.i_mode); } -static inline void gfs2_set_inode_blocks(struct inode *inode) +static inline void gfs2_set_inode_blocks(struct inode *inode, u64 blocks) +{ + inode->i_blocks = blocks << + (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); +} + +static inline u64 gfs2_get_inode_blocks(const struct inode *inode) { - struct gfs2_inode *ip = GFS2_I(inode); - inode->i_blocks = ip->i_di.di_blocks << + return inode->i_blocks >> (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); } +static inline void gfs2_add_inode_blocks(struct inode *inode, s64 change) +{ + gfs2_assert(GFS2_SB(inode), (change >= 0 || inode->i_blocks > -change)); + change *= (GFS2_SB(inode)->sd_sb.sb_bsize/GFS2_BASIC_BLOCK); + inode->i_blocks += change; +} + static inline int gfs2_check_inum(const struct gfs2_inode *ip, u64 no_addr, u64 no_formal_ino) { diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index e87412902be..301c9459667 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -981,8 +981,9 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) brelse(dibh); if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { - gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid); - gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid); + u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); + gfs2_quota_change(ip, -blocks, ouid, ogid); + gfs2_quota_change(ip, blocks, nuid, ngid); } out_end_trans: -- cgit v1.2.3-70-g09d2 From e23159d2a7b2df5bce5f0ee8d57d3292243abf66 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 12 Feb 2008 14:48:39 +0000 Subject: [GFS2] Get inode buffer only once per block map call In the case that we needed to grow the height of the metadata tree we were looking up the inode buffer and then brelse()ing it despite the fact that it is needed later in the block map process. This patch ensures that we look up the inode's buffer once and only once during the block map process. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e27e66046f0..f1f38ca77a5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -188,50 +188,45 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh { struct gfs2_inode *ip = GFS2_I(inode); unsigned new_height = height - ip->i_height; - struct buffer_head *dibh; + struct buffer_head *dibh = mp->mp_bh[0]; struct gfs2_dinode *di; - int error; __be64 *bp; u64 bn; unsigned n, i = 0; - if (height <= ip->i_height) - return 0; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; + BUG_ON(height <= ip->i_height); do { n = new_height - i; bn = gfs2_alloc_block(ip, &n); gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, n); do { - mp->mp_bh[i] = gfs2_meta_new(ip->i_gl, bn++); - gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i], 1); + mp->mp_bh[i + 1] = gfs2_meta_new(ip->i_gl, bn++); + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i + 1], 1); i++; } while(i < n); } while(i < new_height); n = 0; - bn = mp->mp_bh[0]->b_blocknr; + bn = mp->mp_bh[1]->b_blocknr; if (new_height > 1) { for(; n < new_height-1; n++) { - gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, + gfs2_metatype_set(mp->mp_bh[n + 1], GFS2_METATYPE_IN, GFS2_FORMAT_IN); - gfs2_buffer_clear_tail(mp->mp_bh[n], + gfs2_buffer_clear_tail(mp->mp_bh[n + 1], sizeof(struct gfs2_meta_header)); - bp = (__be64 *)(mp->mp_bh[n]->b_data + + bp = (__be64 *)(mp->mp_bh[n + 1]->b_data + sizeof(struct gfs2_meta_header)); - *bp = cpu_to_be64(mp->mp_bh[n+1]->b_blocknr); - brelse(mp->mp_bh[n]); - mp->mp_bh[n] = NULL; + *bp = cpu_to_be64(mp->mp_bh[n+2]->b_blocknr); + brelse(mp->mp_bh[n+1]); + mp->mp_bh[n+1] = NULL; } } - gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); - gfs2_buffer_copy_tail(mp->mp_bh[n], sizeof(struct gfs2_meta_header), + gfs2_metatype_set(mp->mp_bh[n+1], GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_copy_tail(mp->mp_bh[n+1], sizeof(struct gfs2_meta_header), dibh, sizeof(struct gfs2_dinode)); - brelse(mp->mp_bh[n]); + brelse(mp->mp_bh[n+1]); + mp->mp_bh[n+1] = NULL; gfs2_trans_add_bh(ip->i_gl, dibh, 1); di = (struct gfs2_dinode *)dibh->b_data; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); @@ -240,8 +235,7 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh gfs2_add_inode_blocks(&ip->i_inode, new_height); di->di_height = cpu_to_be16(ip->i_height); di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); - brelse(dibh); - return error; + return 0; } /** @@ -391,11 +385,7 @@ static int lookup_metapath(struct inode *inode, struct metapath *mp, struct gfs2_inode *ip = GFS2_I(inode); unsigned int end_of_metadata = ip->i_height - 1; unsigned int x; - int ret = gfs2_meta_inode_buffer(ip, &bh); - if (ret) - return ret; - - mp->mp_bh[0] = bh; + int ret; for (x = 0; x < end_of_metadata; x++) { lookup_block(ip, x, mp, create, new, dblock); @@ -515,6 +505,10 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, } size = (lblock + 1) * bsize; + error = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]); + if (error) + goto out_fail; + if (size > arr[ip->i_height]) { u8 height = ip->i_height; if (!create) -- cgit v1.2.3-70-g09d2 From 840ca0ec70903ce8e0fba1596460876c796e4f60 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 12 Feb 2008 15:28:21 +0000 Subject: [GFS2] Fix bug where we called drop_bh incorrectly As a result of an earlier patch, drop_bh was being called in cases when it shouldn't have been. Since we never have a gh in the drop case and we always have a gh in the promote case, we can use that extra information to tell which case has been seen. Signed-off-by: Steven Whitehouse Cc: Bob Peterson --- fs/gfs2/glock.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d00dc37e3d5..63981e2fb83 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -765,7 +765,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) { struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_glock_operations *glops = gl->gl_ops; - struct gfs2_holder *gh = gl->gl_req_gh; gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -776,23 +775,11 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) if (glops->go_inval) glops->go_inval(gl, DIO_METADATA); - if (gh) { - spin_lock(&gl->gl_spin); - list_del_init(&gh->gh_list); - gh->gh_error = 0; - spin_unlock(&gl->gl_spin); - } - spin_lock(&gl->gl_spin); gfs2_demote_wake(gl); - gl->gl_req_gh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); spin_unlock(&gl->gl_spin); - gfs2_glock_put(gl); - - if (gh) - gfs2_holder_wake(gh); } /** @@ -810,7 +797,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) int prev_state = gl->gl_state; int op_done = 1; - if ((ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) { + if (!gh && (ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) { drop_bh(gl, ret); return; } -- cgit v1.2.3-70-g09d2 From bb16b342b2e2c83fa47dbb042400db91b748ded7 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 13 Feb 2008 00:06:10 +0100 Subject: [GFS2] be*_add_cpu conversion replace all: big_endian_variable = cpu_to_beX(beX_to_cpu(big_endian_variable) + expression_in_cpu_byteorder); with: beX_add_cpu(&big_endian_variable, expression_in_cpu_byteorder); generated with semantic patch Signed-off-by: Marcin Slusarz Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 862aa3228f7..34dc8dfaba1 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1021,13 +1021,13 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) new->de_inum = dent->de_inum; /* No endian worries */ new->de_type = dent->de_type; /* No endian worries */ - nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1); + be16_add_cpu(&nleaf->lf_entries, 1); dirent_del(dip, obh, prev, dent); if (!oleaf->lf_entries) gfs2_consist_inode(dip); - oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1); + be16_add_cpu(&oleaf->lf_entries, -1); if (!prev) prev = dent; @@ -1614,7 +1614,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, dent->de_type = cpu_to_be16(type); if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { leaf = (struct gfs2_leaf *)bh->b_data; - leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1); + be16_add_cpu(&leaf->lf_entries, 1); } brelse(bh); error = gfs2_meta_inode_buffer(ip, &bh); -- cgit v1.2.3-70-g09d2 From 8af4c72f7df2442230fca3ff49a97f978cfb4a04 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 17 Feb 2008 10:17:12 +0200 Subject: [GFS2] gfs2/ops_file.c should #include "ops_inode.h" Every file should include the headers containing the prototypes for its global functions (in this case for gfs2_set_inode_flags()). Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index f97a8b86c48..2b25a5f7a1c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -38,6 +38,7 @@ #include "util.h" #include "eaops.h" #include "ops_address.h" +#include "ops_inode.h" /** * gfs2_llseek - seek to a location in a file -- cgit v1.2.3-70-g09d2 From 60b779cfc1fa52034a996ee12a23b62d32e86000 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 17 Feb 2008 10:20:34 +0200 Subject: [GFS2] proper extern for gfs2/locking/dlm/mount.c:gdlm_ops This patch adds a proper extern declaration for gdlm_ops in fs/gfs2/locking/dlm/lock_dlm.h Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/lock_dlm.h | 5 +++++ fs/gfs2/locking/dlm/main.c | 2 -- fs/gfs2/locking/dlm/sysfs.c | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 9e8265d2837..58fcf8c5bf3 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -183,5 +183,10 @@ int gdlm_plock_get(void *, struct lm_lockname *, struct file *, struct file_lock *); int gdlm_punlock(void *, struct lm_lockname *, struct file *, struct file_lock *); + +/* mount.c */ + +extern const struct lm_lockops gdlm_ops; + #endif diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index a0e7eda643e..36a225850bd 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -11,8 +11,6 @@ #include "lock_dlm.h" -extern struct lm_lockops gdlm_ops; - static int __init init_lock_dlm(void) { int error; diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index a87b0983976..8479da47049 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -12,8 +12,6 @@ #include "lock_dlm.h" -extern struct lm_lockops gdlm_ops; - static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf) { return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name); -- cgit v1.2.3-70-g09d2 From 7afd88d9166a752b52517648bcbe923e05d393fc Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 22 Feb 2008 16:07:18 +0000 Subject: [GFS2] Fix a page lock / glock deadlock We've previously been using a "try lock" in readpage on the basis that it would prevent deadlocks due to the inverted lock ordering (our normal lock ordering is glock first and then page lock). Unfortunately tests have shown that this isn't enough. If the glock has a demote request queued such that run_queue() in the glock code tries to do a demote when its called under readpage then it will try and write out all the dirty pages which requires locking them. This then deadlocks with the page locked by readpage. The solution is to always require two calls into readpage. The first unlocks the page, gets the glock and returns AOP_TRUNCATED_PAGE, the second does the actual readpage and unlocks the glock & page as required. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.h | 13 ++++++------- fs/gfs2/inode.c | 2 +- fs/gfs2/ops_address.c | 27 +++++++++++++++------------ fs/gfs2/ops_dentry.c | 4 ++-- fs/gfs2/ops_inode.c | 4 ++-- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index ace5770760c..cdad3e6f815 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -32,24 +32,23 @@ #define GLR_TRYFAILED 13 #define GLR_CANCELED 14 -static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) +static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) { struct gfs2_holder *gh; - int locked = 0; struct pid *pid; /* Look in glock's list of holders for one with current task as owner */ spin_lock(&gl->gl_spin); pid = task_pid(current); list_for_each_entry(gh, &gl->gl_holders, gh_list) { - if (gh->gh_owner_pid == pid) { - locked = 1; - break; - } + if (gh->gh_owner_pid == pid) + goto out; } + gh = NULL; +out: spin_unlock(&gl->gl_spin); - return locked; + return gh; } static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5f50dd53bf6..810ff023fb1 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -493,7 +493,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, return dir; } - if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) { + if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) { error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) return ERR_PTR(error); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 7523999afc5..fbb4a6aa158 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -508,23 +508,26 @@ static int __gfs2_readpage(void *file, struct page *page) static int gfs2_readpage(struct file *file, struct page *page) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); - struct gfs2_holder gh; + struct gfs2_holder *gh; int error; - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); - error = gfs2_glock_nq_atime(&gh); - if (unlikely(error)) { + gh = gfs2_glock_is_locked_by_me(ip->i_gl); + if (!gh) { + gh = kmalloc(sizeof(struct gfs2_holder), GFP_NOFS); + if (!gh) + return -ENOBUFS; + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, gh); unlock_page(page); - goto out; + error = gfs2_glock_nq_atime(gh); + if (likely(error != 0)) + goto out; + return AOP_TRUNCATED_PAGE; } error = __gfs2_readpage(file, page); - gfs2_glock_dq(&gh); + gfs2_glock_dq(gh); out: - gfs2_holder_uninit(&gh); - if (error == GLR_TRYFAILED) { - yield(); - return AOP_TRUNCATED_PAGE; - } + gfs2_holder_uninit(gh); + kfree(gh); return error; } @@ -826,7 +829,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, unsigned int to = from + len; int ret; - BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == 0); + BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == NULL); ret = gfs2_meta_inode_buffer(ip, &dibh); if (unlikely(ret)) { diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 793e334d098..4a5e676b442 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -43,7 +43,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) struct gfs2_holder d_gh; struct gfs2_inode *ip = NULL; int error; - int had_lock=0; + int had_lock = 0; if (inode) { if (is_bad_inode(inode)) @@ -54,7 +54,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) if (sdp->sd_args.ar_localcaching) goto valid; - had_lock = gfs2_glock_is_locked_by_me(dip->i_gl); + had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL); if (!had_lock) { error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 301c9459667..af7097a514c 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -898,7 +898,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) int error; int unlock = 0; - if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { + if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; @@ -1065,7 +1065,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, int error; int unlock = 0; - if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { + if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (error) return error; -- cgit v1.2.3-70-g09d2 From 9b8c81d1de49943ec69d157234b8981008c30d31 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 22 Feb 2008 16:09:31 +0000 Subject: [GFS2] Allow bmap to allocate extents We've supported mapping of extents when no block allocation is required for some time. This patch extends that to mapping of extents when an allocation has been requested. In that case we try to allocate as many blocks as are requested, but we might return fewer in case there is something preventing us from returning the complete amount (e.g. an already allocated block is in the way). Currently the only code path which can actually request multiple data blocks in a single bmap call is the page_mkwrite path and even then it only happens if there are multiple blocks per page. What this patch does do however, is merge the allocation requests for metadata (growing the metadata tree in either height or depth) with the allocation of the data blocks in the case that both are needed. This results in lower overheads even in the single block allocation case. The one thing which we can't handle here at the moment is unstuffing. I would like to be able to do that, but the problem which arises is that in order to unstuff one has to get a locked page from the page cache which results in locking problems in the (usual) case that the caller is holding the page lock on the page it wishes to map. So that case will have to be addressed in future patches. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 502 +++++++++++++++++++++++++++++++++------------------------ fs/gfs2/dir.c | 2 +- fs/gfs2/rgrp.c | 10 +- 3 files changed, 295 insertions(+), 219 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index f1f38ca77a5..c1ee6355ced 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -175,74 +175,13 @@ out: return error; } -/** - * build_height - Build a metadata tree of the requested height - * @ip: The GFS2 inode - * @height: The height to build to - * - * - * Returns: errno - */ - -static int build_height(struct inode *inode, struct metapath *mp, unsigned height) -{ - struct gfs2_inode *ip = GFS2_I(inode); - unsigned new_height = height - ip->i_height; - struct buffer_head *dibh = mp->mp_bh[0]; - struct gfs2_dinode *di; - __be64 *bp; - u64 bn; - unsigned n, i = 0; - - BUG_ON(height <= ip->i_height); - - do { - n = new_height - i; - bn = gfs2_alloc_block(ip, &n); - gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, n); - do { - mp->mp_bh[i + 1] = gfs2_meta_new(ip->i_gl, bn++); - gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i + 1], 1); - i++; - } while(i < n); - } while(i < new_height); - - n = 0; - bn = mp->mp_bh[1]->b_blocknr; - if (new_height > 1) { - for(; n < new_height-1; n++) { - gfs2_metatype_set(mp->mp_bh[n + 1], GFS2_METATYPE_IN, - GFS2_FORMAT_IN); - gfs2_buffer_clear_tail(mp->mp_bh[n + 1], - sizeof(struct gfs2_meta_header)); - bp = (__be64 *)(mp->mp_bh[n + 1]->b_data + - sizeof(struct gfs2_meta_header)); - *bp = cpu_to_be64(mp->mp_bh[n+2]->b_blocknr); - brelse(mp->mp_bh[n+1]); - mp->mp_bh[n+1] = NULL; - } - } - gfs2_metatype_set(mp->mp_bh[n+1], GFS2_METATYPE_IN, GFS2_FORMAT_IN); - gfs2_buffer_copy_tail(mp->mp_bh[n+1], sizeof(struct gfs2_meta_header), - dibh, sizeof(struct gfs2_dinode)); - brelse(mp->mp_bh[n+1]); - mp->mp_bh[n+1] = NULL; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - di = (struct gfs2_dinode *)dibh->b_data; - gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - *(__be64 *)(di + 1) = cpu_to_be64(bn); - ip->i_height += new_height; - gfs2_add_inode_blocks(&ip->i_inode, new_height); - di->di_height = cpu_to_be16(ip->i_height); - di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); - return 0; -} /** * find_metapath - Find path through the metadata tree - * @ip: The inode pointer + * @sdp: The superblock * @mp: The metapath to return the result in * @block: The disk block to look up + * @height: The pre-calculated height of the metadata tree * * This routine returns a struct metapath structure that defines a path * through the metadata of inode "ip" to get to block "block". @@ -297,17 +236,27 @@ static int build_height(struct inode *inode, struct metapath *mp, unsigned heigh * */ -static void find_metapath(struct gfs2_inode *ip, u64 block, - struct metapath *mp) +static void find_metapath(const struct gfs2_sbd *sdp, u64 block, + struct metapath *mp, unsigned int height) { - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); unsigned int i; - for (i = ip->i_height; i--;) + for (i = height; i--;) mp->mp_list[i] = do_div(block, sdp->sd_inptrs); } +static inline unsigned int zero_metapath_length(const struct metapath *mp, + unsigned height) +{ + unsigned int i; + for (i = 0; i < height - 1; i++) { + if (mp->mp_list[i] != 0) + return i; + } + return height; +} + /** * metapointer - Return pointer to start of metadata in a buffer * @height: The metadata height (0 = dinode) @@ -318,95 +267,62 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, * metadata tree. */ -static inline __be64 *metapointer(int *boundary, unsigned int height, - const struct metapath *mp) +static inline __be64 *metapointer(unsigned int height, const struct metapath *mp) { struct buffer_head *bh = mp->mp_bh[height]; unsigned int head_size = (height > 0) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); - __be64 *ptr; - *boundary = 0; - ptr = ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height]; - if (ptr + 1 == (__be64 *)(bh->b_data + bh->b_size)) - *boundary = 1; - return ptr; + return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height]; } /** - * lookup_block - Get the next metadata block in metadata tree - * @ip: The GFS2 inode - * @height: The height of the tree (0 = dinode) + * lookup_metapath - Walk the metadata tree to a specific point + * @ip: The inode * @mp: The metapath - * @create: Non-zero if we may create a new meatdata block - * @new: Used to indicate if we did create a new metadata block - * @block: the returned disk block number * - * Given a metatree, complete to a particular height, checks to see if the next - * height of the tree exists. If not the next height of the tree is created. - * The block number of the next height of the metadata tree is returned. + * Assumes that the inode's buffer has already been looked up and + * hooked onto mp->mp_bh[0] and that the metapath has been initialised + * by find_metapath(). * + * If this function encounters part of the tree which has not been + * allocated, it returns the current height of the tree at the point + * at which it found the unallocated block. Blocks which are found are + * added to the mp->mp_bh[] list. + * + * Returns: error or height of metadata tree */ -static int lookup_block(struct gfs2_inode *ip, unsigned int height, - struct metapath *mp, int create, - int *new, u64 *block) +static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp) { - int boundary; - __be64 *ptr = metapointer(&boundary, height, mp); - unsigned int n = 1; - - if (*ptr) { - *block = be64_to_cpu(*ptr); - return boundary; - } - - *block = 0; - - if (!create) - return 0; - - *block = gfs2_alloc_block(ip, &n); - if (height != ip->i_height - 1 || gfs2_is_dir(ip)) - gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1); - - gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); - - *ptr = cpu_to_be64(*block); - gfs2_add_inode_blocks(&ip->i_inode, 1); - - *new = 1; - return 0; -} - -static int lookup_metapath(struct inode *inode, struct metapath *mp, - int create, int *new, u64 *dblock) -{ - struct buffer_head *bh; - struct gfs2_inode *ip = GFS2_I(inode); unsigned int end_of_metadata = ip->i_height - 1; unsigned int x; + __be64 *ptr; + u64 dblock; int ret; for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, x, mp, create, new, dblock); - if (!*dblock) - return 0; + ptr = metapointer(x, mp); + dblock = be64_to_cpu(*ptr); + if (!dblock) + return x + 1; - ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &mp->mp_bh[x+1]); + ret = gfs2_meta_indirect_buffer(ip, x+1, dblock, 0, &mp->mp_bh[x+1]); if (ret) return ret; } - return lookup_block(ip, end_of_metadata, mp, create, new, dblock); + return ip->i_height; } -static void release_metapath(struct metapath *mp) +static inline void release_metapath(struct metapath *mp) { int i; - for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) - if (mp->mp_bh[i]) - brelse(mp->mp_bh[i]); + for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) { + if (mp->mp_bh[i] == NULL) + break; + brelse(mp->mp_bh[i]); + } } /** @@ -445,32 +361,208 @@ static inline unsigned int gfs2_extent_length(void *start, unsigned int len, __b return (ptr - first); } -static inline void bmap_lock(struct inode *inode, int create) +static inline void bmap_lock(struct gfs2_inode *ip, int create) { - struct gfs2_inode *ip = GFS2_I(inode); if (create) down_write(&ip->i_rw_mutex); else down_read(&ip->i_rw_mutex); } -static inline void bmap_unlock(struct inode *inode, int create) +static inline void bmap_unlock(struct gfs2_inode *ip, int create) { - struct gfs2_inode *ip = GFS2_I(inode); if (create) up_write(&ip->i_rw_mutex); else up_read(&ip->i_rw_mutex); } +static inline __be64 *gfs2_indirect_init(struct metapath *mp, + struct gfs2_glock *gl, unsigned int i, + unsigned offset, u64 bn) +{ + __be64 *ptr = (__be64 *)(mp->mp_bh[i - 1]->b_data + + ((i > 1) ? sizeof(struct gfs2_meta_header) : + sizeof(struct gfs2_dinode))); + BUG_ON(i < 1); + BUG_ON(mp->mp_bh[i] != NULL); + mp->mp_bh[i] = gfs2_meta_new(gl, bn); + gfs2_trans_add_bh(gl, mp->mp_bh[i], 1); + gfs2_metatype_set(mp->mp_bh[i], GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_clear_tail(mp->mp_bh[i], sizeof(struct gfs2_meta_header)); + ptr += offset; + *ptr = cpu_to_be64(bn); + return ptr; +} + +enum alloc_state { + ALLOC_DATA = 0, + ALLOC_GROW_DEPTH = 1, + ALLOC_GROW_HEIGHT = 2, + /* ALLOC_UNSTUFF = 3, TBD and rather complicated */ +}; + +/** + * gfs2_bmap_alloc - Build a metadata tree of the requested height + * @inode: The GFS2 inode + * @lblock: The logical starting block of the extent + * @bh_map: This is used to return the mapping details + * @mp: The metapath + * @sheight: The starting height (i.e. whats already mapped) + * @height: The height to build to + * @maxlen: The max number of data blocks to alloc + * + * In this routine we may have to alloc: + * i) Indirect blocks to grow the metadata tree height + * ii) Indirect blocks to fill in lower part of the metadata tree + * iii) Data blocks + * + * The function is in two parts. The first part works out the total + * number of blocks which we need. The second part does the actual + * allocation asking for an extent at a time (if enough contiguous free + * blocks are available, there will only be one request per bmap call) + * and uses the state machine to initialise the blocks in order. + * + * Returns: errno on error + */ + +static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, + struct buffer_head *bh_map, struct metapath *mp, + const unsigned int sheight, + const unsigned int height, + const unsigned int maxlen) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct buffer_head *dibh = mp->mp_bh[0]; + u64 bn, dblock = 0; + unsigned n, i, blks, alloced = 0, iblks = 0, zmpl = 0; + unsigned dblks = 0; + unsigned ptrs_per_blk; + const unsigned end_of_metadata = height - 1; + int eob = 0; + enum alloc_state state; + __be64 *ptr; + __be64 zero_bn = 0; + + BUG_ON(sheight < 1); + BUG_ON(dibh == NULL); + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + + if (height == sheight) { + struct buffer_head *bh; + /* Bottom indirect block exists, find unalloced extent size */ + ptr = metapointer(end_of_metadata, mp); + bh = mp->mp_bh[end_of_metadata]; + dblks = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, + &eob); + BUG_ON(dblks < 1); + state = ALLOC_DATA; + } else { + /* Need to allocate indirect blocks */ + ptrs_per_blk = height > 1 ? sdp->sd_inptrs : sdp->sd_diptrs; + dblks = min(maxlen, ptrs_per_blk - mp->mp_list[end_of_metadata]); + if (height == ip->i_height) { + /* Writing into existing tree, extend tree down */ + iblks = height - sheight; + state = ALLOC_GROW_DEPTH; + } else { + /* Building up tree height */ + state = ALLOC_GROW_HEIGHT; + iblks = height - ip->i_height; + zmpl = zero_metapath_length(mp, height); + iblks -= zmpl; + iblks += height; + } + } + + /* start of the second part of the function (state machine) */ + + blks = dblks + iblks; + i = sheight; + do { + n = blks - alloced; + bn = gfs2_alloc_block(ip, &n); + alloced += n; + if (state != ALLOC_DATA || gfs2_is_jdata(ip)) + gfs2_trans_add_unrevoke(sdp, bn, n); + switch (state) { + /* Growing height of tree */ + case ALLOC_GROW_HEIGHT: + if (i == 1) { + ptr = (__be64 *)(dibh->b_data + + sizeof(struct gfs2_dinode)); + zero_bn = *ptr; + } + for (; i - 1 < height - ip->i_height && n > 0; i++, n--) + gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++); + if (i - 1 == height - ip->i_height) { + i--; + gfs2_buffer_copy_tail(mp->mp_bh[i], + sizeof(struct gfs2_meta_header), + dibh, sizeof(struct gfs2_dinode)); + gfs2_buffer_clear_tail(dibh, + sizeof(struct gfs2_dinode) + + sizeof(__be64)); + ptr = (__be64 *)(mp->mp_bh[i]->b_data + + sizeof(struct gfs2_meta_header)); + *ptr = zero_bn; + state = ALLOC_GROW_DEPTH; + for(i = zmpl; i < height; i++) { + if (mp->mp_bh[i] == NULL) + break; + brelse(mp->mp_bh[i]); + mp->mp_bh[i] = NULL; + } + i = zmpl; + } + if (n == 0) + break; + /* Branching from existing tree */ + case ALLOC_GROW_DEPTH: + if (i > 1 && i < height) + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i-1], 1); + for (; i < height && n > 0; i++, n--) + gfs2_indirect_init(mp, ip->i_gl, i, + mp->mp_list[i-1], bn++); + if (i == height) + state = ALLOC_DATA; + if (n == 0) + break; + /* Tree complete, adding data blocks */ + case ALLOC_DATA: + BUG_ON(n > dblks); + BUG_ON(mp->mp_bh[end_of_metadata] == NULL); + gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[end_of_metadata], 1); + dblks = n; + ptr = metapointer(end_of_metadata, mp); + dblock = bn; + while (n-- > 0) + *ptr++ = cpu_to_be64(bn++); + break; + } + } while (state != ALLOC_DATA); + + ip->i_height = height; + gfs2_add_inode_blocks(&ip->i_inode, alloced); + gfs2_dinode_out(ip, mp->mp_bh[0]->b_data); + map_bh(bh_map, inode->i_sb, dblock); + bh_map->b_size = dblks << inode->i_blkbits; + set_buffer_new(bh_map); + return 0; +} + /** * gfs2_block_map - Map a block from an inode to a disk block * @inode: The inode * @lblock: The logical block number * @bh_map: The bh to be mapped + * @create: True if its ok to alloc blocks to satify the request * - * Find the block number on the current device which corresponds to an - * inode's block. If the block had to be created, "new" will be set. + * Sets buffer_mapped() if successful, sets buffer_boundary() if a + * read of metadata will be required before the next block can be + * mapped. Sets buffer_new() if new blocks were allocated. * * Returns: errno */ @@ -481,21 +573,21 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); unsigned int bsize = sdp->sd_sb.sb_bsize; - int error = 0; - int new = 0; - u64 dblock = 0; - int boundary; - unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; - struct metapath mp; - u64 size; + const unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; const u64 *arr = sdp->sd_heightsize; - BUG_ON(maxlen == 0); + __be64 *ptr; + u64 size; + struct metapath mp; + int ret; + int eob; + unsigned int len; + struct buffer_head *bh; + u8 height; - if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) - return 0; + BUG_ON(maxlen == 0); memset(mp.mp_bh, 0, sizeof(mp.mp_bh)); - bmap_lock(inode, create); + bmap_lock(ip, create); clear_buffer_mapped(bh_map); clear_buffer_new(bh_map); clear_buffer_boundary(bh_map); @@ -503,56 +595,50 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, bsize = sdp->sd_jbsize; arr = sdp->sd_jheightsize; } - size = (lblock + 1) * bsize; - error = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]); - if (error) - goto out_fail; - - if (size > arr[ip->i_height]) { - u8 height = ip->i_height; - if (!create) - goto out_ok; - while (size > arr[height]) - height++; - error = build_height(inode, &mp, height); - if (error) - goto out_fail; - } + ret = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]); + if (ret) + goto out; - find_metapath(ip, lblock, &mp); - error = lookup_metapath(inode, &mp, create, &new, &dblock); - if (error < 0) - goto out_fail; - boundary = error; - - if (new) { - map_bh(bh_map, inode->i_sb, dblock); - if (boundary) - set_buffer_boundary(bh_map); - gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); - gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); - set_buffer_new(bh_map); - goto out_ok; - } + height = ip->i_height; + size = (lblock + 1) * bsize; + while (size > arr[height]) + height++; + find_metapath(sdp, lblock, &mp, height); + ret = 1; + if (height > ip->i_height || gfs2_is_stuffed(ip)) + goto do_alloc; + ret = lookup_metapath(ip, &mp); + if (ret < 0) + goto out; + if (ret != ip->i_height) + goto do_alloc; + ptr = metapointer(ip->i_height - 1, &mp); + if (*ptr == 0) + goto do_alloc; + map_bh(bh_map, inode->i_sb, be64_to_cpu(*ptr)); + bh = mp.mp_bh[ip->i_height - 1]; + len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, &eob); + bh_map->b_size = (len << inode->i_blkbits); + if (eob) + set_buffer_boundary(bh_map); + ret = 0; +out: + release_metapath(&mp); + bmap_unlock(ip, create); + return ret; - if (dblock) { - unsigned int len; - struct buffer_head *bh = mp.mp_bh[ip->i_height - 1]; - __be64 *ptr = metapointer(&boundary, ip->i_height - 1, &mp); - map_bh(bh_map, inode->i_sb, dblock); - len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, - &boundary); - bh_map->b_size = (len << inode->i_blkbits); - if (boundary) - set_buffer_boundary(bh_map); +do_alloc: + /* All allocations are done here, firstly check create flag */ + if (!create) { + BUG_ON(gfs2_is_stuffed(ip)); + ret = 0; + goto out; } -out_ok: - error = 0; -out_fail: - release_metapath(&mp); - bmap_unlock(inode, create); - return error; + + /* At this point ret is the tree depth of already allocated blocks */ + ret = gfs2_bmap_alloc(inode, lblock, bh_map, &mp, ret, height, maxlen); + goto out; } /* @@ -568,7 +654,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!dblock); BUG_ON(!new); - bh.b_size = 1 << (inode->i_blkbits + 5); + bh.b_size = 1 << (inode->i_blkbits + (create ? 0 : 5)); ret = gfs2_block_map(inode, lblock, &bh, create); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; @@ -835,38 +921,25 @@ static int do_grow(struct gfs2_inode *ip, u64 size) if (error) goto out_ipres; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { - const u64 *arr = sdp->sd_heightsize; if (gfs2_is_stuffed(ip)) { error = gfs2_unstuff_dinode(ip, NULL); if (error) - goto out_end_trans; - } - - down_write(&ip->i_rw_mutex); - if (size > arr[ip->i_height]) { - struct metapath mp; - u8 height = ip->i_height; - while(size > arr[height]) - height++; - error = build_height(&ip->i_inode, &mp, height); + goto out_brelse; } - up_write(&ip->i_rw_mutex); - if (error) - goto out_end_trans; } ip->i_di.di_size = size; ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto out_end_trans; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); +out_brelse: + brelse(dibh); out_end_trans: gfs2_trans_end(sdp); out_ipres: @@ -996,6 +1069,7 @@ out: static int trunc_dealloc(struct gfs2_inode *ip, u64 size) { + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); unsigned int height = ip->i_height; u64 lblock; struct metapath mp; @@ -1004,9 +1078,9 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size) if (!size) lblock = 0; else - lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift; + lblock = (size - 1) >> sdp->sd_sb.sb_bsize_shift; - find_metapath(ip, lblock, &mp); + find_metapath(sdp, lblock, &mp, ip->i_height); gfs2_alloc_get(ip); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 34dc8dfaba1..a3753c7989f 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -159,6 +159,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, unsigned int o; int copied = 0; int error = 0; + int new = 0; if (!size) return 0; @@ -183,7 +184,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, while (copied < size) { unsigned int amount; struct buffer_head *bh; - int new = 0; amount = size - copied; if (amount > sdp->sd_sb.sb_bsize - o) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 77eba0a3804..4291375cecc 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1357,16 +1357,18 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, bi->bi_len, blk, new_state); - while(*n < elen) { + goal = blk; + while (*n < elen) { goal++; - if (goal >= (bi->bi_len / GFS2_NBBY)) + if (goal >= (bi->bi_len * GFS2_NBBY)) break; if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) != GFS2_BLKST_FREE) break; - (*n)++; gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, - bi->bi_offset, bi->bi_len, blk, new_state); + bi->bi_offset, bi->bi_len, goal, + new_state); + (*n)++; } } -- cgit v1.2.3-70-g09d2 From 7dc2cf1c8ffbd471722f1aa479bc68d4df1c9edc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 25 Feb 2008 18:58:36 +0100 Subject: [GFS2] fix file_system_type leak on gfs2meta mount get_gfs2_sb does a get_fs_type without doing a put_filesystem and thus leaking a file_system_type reference everytime it's called. Just use gfs2_fs_type directly instead of doing the lookup and thus fix the problem. Signed-off-by: Christoph Hellwig Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c4b7a210c0c..63d5fd203d3 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -943,7 +943,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name) { struct kstat stat; struct nameidata nd; - struct file_system_type *fstype; struct super_block *sb = NULL, *s; int error; @@ -955,8 +954,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) } error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat); - fstype = get_fs_type("gfs2"); - list_for_each_entry(s, &fstype->fs_supers, s_instances) { + list_for_each_entry(s, &gfs2_fs_type.fs_supers, s_instances) { if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || (S_ISDIR(stat.mode) && s == nd.path.dentry->d_inode->i_sb)) { -- cgit v1.2.3-70-g09d2 From d83225d45d2b76175279abb2a3d7ee325a09aba8 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Tue, 26 Feb 2008 15:25:03 +0800 Subject: [GFS2] remove gfs2_dev_iops struct inode_operations gfs2_dev_iops is always the same as gfs2_file_iops, since Jan 2006, when GFS2 merged into mainstream kernel. So one of them could be removed. Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 2 +- fs/gfs2/ops_inode.c | 10 ---------- fs/gfs2/ops_inode.h | 1 - 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 810ff023fb1..7b9f31e5d6d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -149,7 +149,7 @@ void gfs2_set_iop(struct inode *inode) } else if (S_ISLNK(mode)) { inode->i_op = &gfs2_symlink_iops; } else { - inode->i_op = &gfs2_dev_iops; + inode->i_op = &gfs2_file_iops; } unlock_new_inode(inode); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index af7097a514c..6cbbb5b46ce 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1149,16 +1149,6 @@ const struct inode_operations gfs2_file_iops = { .removexattr = gfs2_removexattr, }; -const struct inode_operations gfs2_dev_iops = { - .permission = gfs2_permission, - .setattr = gfs2_setattr, - .getattr = gfs2_getattr, - .setxattr = gfs2_setxattr, - .getxattr = gfs2_getxattr, - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, -}; - const struct inode_operations gfs2_dir_iops = { .create = gfs2_create, .lookup = gfs2_lookup, diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index fd8cee231e1..14b4b797622 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -15,7 +15,6 @@ extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_dir_iops; extern const struct inode_operations gfs2_symlink_iops; -extern const struct inode_operations gfs2_dev_iops; extern const struct file_operations gfs2_file_fops; extern const struct file_operations gfs2_dir_fops; extern const struct file_operations gfs2_file_fops_nolock; -- cgit v1.2.3-70-g09d2 From 43a33c53cc9131a537522ab9736c6e4c03ddf57a Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Tue, 26 Feb 2008 15:25:04 +0800 Subject: [GFS2] re-support special inode a previous commit removed call to init_special_inode from inode lookuping, this cause problems as: # mknod /mnt/gfs2/dev/null c 1 3 # cat /mnt/gfs2/dev/null cat: /mnt/gfs2/dev/null: Invalid argument without special inode, GFS2 cannot support char device file, block device file, fifo pipe, and socket file, lose many important features as a common file system. this one line patch re add special inode support. Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7b9f31e5d6d..92ea9afacb1 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -150,6 +150,7 @@ void gfs2_set_iop(struct inode *inode) inode->i_op = &gfs2_symlink_iops; } else { inode->i_op = &gfs2_file_iops; + init_special_inode(inode, inode->i_mode, inode->i_rdev); } unlock_new_inode(inode); -- cgit v1.2.3-70-g09d2 From 105284970ba7d0d0ff4b97e57728eac7adf6a42a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 27 Feb 2008 17:56:27 +0000 Subject: [GFS2] Need to ensure that sector_t is 64bits for GFS2 We need to ensure that sector_t is 64bits for GFS2, so that we need to depend on LBD as well as LSF. Signed-off-by: Steven Whitehouse --- fs/gfs2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index d147b53ef52..7f7947e3dfb 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -1,6 +1,6 @@ config GFS2_FS tristate "GFS2 file system support" - depends on EXPERIMENTAL && (64BIT || LSF) + depends on EXPERIMENTAL && (64BIT || (LSF && LBD)) select FS_POSIX_ACL select CRC32 help -- cgit v1.2.3-70-g09d2 From 182fe5abd8ebbb3a00c1be91f44e4783e139918c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 3 Mar 2008 21:54:21 +0300 Subject: [GFS2] possible null pointer dereference fixup gfs2_alloc_get may fail so we have to check it to prevent NULL pointer dereference. Signed-off-by: Cyrill Gorcunov Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 5 ++++- fs/gfs2/dir.c | 10 +++++++--- fs/gfs2/eattr.c | 6 ++++++ fs/gfs2/inode.c | 7 ++++++- fs/gfs2/ops_address.c | 4 ++++ fs/gfs2/ops_inode.c | 11 ++++++++++- fs/gfs2/quota.c | 9 +++++++-- 7 files changed, 44 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index c1ee6355ced..f7093aa69aa 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -900,6 +900,8 @@ static int do_grow(struct gfs2_inode *ip, u64 size) int error; al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -1081,7 +1083,8 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size) lblock = (size - 1) >> sdp->sd_sb.sb_bsize_shift; find_metapath(sdp, lblock, &mp, ip->i_height); - gfs2_alloc_get(ip); + if (!gfs2_alloc_get(ip)) + return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index a3753c7989f..94070ad8826 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1868,11 +1868,14 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, if (!ht) return -ENOMEM; - gfs2_alloc_get(dip); + if (!gfs2_alloc_get(dip)) { + error = -ENOMEM; + goto out; + } error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) - goto out; + goto out_put; error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh); if (error) @@ -1946,8 +1949,9 @@ out_rlist: gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh); out_qs: gfs2_quota_unhold(dip); -out: +out_put: gfs2_alloc_put(dip); +out: kfree(ht); return error; } diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 76ead1acfcc..288d5e6ad93 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -318,6 +318,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, int error; al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -681,6 +683,8 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, int error; al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -1464,6 +1468,8 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) int error; al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 92ea9afacb1..dcae2aa83f1 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -351,6 +351,8 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) } al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -825,7 +827,8 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, int error; munge_mode_uid_gid(dip, &mode, &uid, &gid); - gfs2_alloc_get(dip); + if (!gfs2_alloc_get(dip)) + return -ENOMEM; error = gfs2_quota_lock(dip, uid, gid); if (error) @@ -860,6 +863,8 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, int error; al = gfs2_alloc_get(dip); + if (!al) + return -ENOMEM; error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index fbb4a6aa158..2483d874106 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -649,6 +649,10 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, if (alloc_required) { al = gfs2_alloc_get(ip); + if (!al) { + error = -ENOMEM; + goto out_unlock; + } error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 6cbbb5b46ce..34fe571e15e 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -200,6 +200,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(dip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -716,6 +720,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(ndip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -953,7 +961,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) ogid = ngid = NO_QUOTA_CHANGE; - gfs2_alloc_get(ip); + if (!gfs2_alloc_get(ip)) + return -ENOMEM; error = gfs2_quota_lock(ip, nuid, ngid); if (error) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a08dabd6ce9..636bccfd2bc 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -617,8 +617,9 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, int err = -EIO; if (gfs2_is_stuffed(ip)) { - struct gfs2_alloc *al = NULL; - al = gfs2_alloc_get(ip); + struct gfs2_alloc *al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; /* just request 1 blk */ al->al_requested = 1; gfs2_inplace_reserve(ip); @@ -729,6 +730,10 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) if (nalloc) { al = gfs2_alloc_get(ip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } al->al_requested = nalloc * (data_blocks + ind_blocks); -- cgit v1.2.3-70-g09d2 From 20b95bf2c4c5c28e093aa42699e67829b6cd7fd0 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Thu, 6 Mar 2008 17:43:52 -0600 Subject: [GFS2] gfs2_adjust_quota has broken unstuffing code This patch combines the 2 patches in bug 434736 to correct the lock ordering in the unstuffing of the quota inode in gfs2_adjust_quota and adjusting the number of revokes in gfs2_write_jdata_pagevec Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 3 +-- fs/gfs2/quota.c | 71 ++++++++++++++++++++++----------------------------- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 2483d874106..e72fd47d71e 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "gfs2.h" #include "incore.h" @@ -278,7 +277,7 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, int i; int ret; - ret = gfs2_trans_begin(sdp, nrblocks, 0); + ret = gfs2_trans_begin(sdp, nrblocks, nrblocks); if (ret < 0) return ret; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 636bccfd2bc..c71f781db5d 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -616,17 +616,9 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, s64 value; int err = -EIO; - if (gfs2_is_stuffed(ip)) { - struct gfs2_alloc *al = gfs2_alloc_get(ip); - if (!al) - return -ENOMEM; - /* just request 1 blk */ - al->al_requested = 1; - gfs2_inplace_reserve(ip); + if (gfs2_is_stuffed(ip)) gfs2_unstuff_dinode(ip, NULL); - gfs2_inplace_release(ip); - gfs2_alloc_put(ip); - } + page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; @@ -691,7 +683,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) unsigned int qx, x; struct gfs2_quota_data *qd; loff_t offset; - unsigned int nalloc = 0; + unsigned int nalloc = 0, blocks; struct gfs2_alloc *al = NULL; int error; @@ -728,34 +720,33 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) nalloc++; } - if (nalloc) { - al = gfs2_alloc_get(ip); - if (!al) { - error = -ENOMEM; - goto out_gunlock; - } + al = gfs2_alloc_get(ip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } + /* + * 1 blk for unstuffing inode if stuffed. We add this extra + * block to the reservation unconditionally. If the inode + * doesn't need unstuffing, the block will be released to the + * rgrp since it won't be allocated during the transaction + */ + al->al_requested = 1; + /* +1 in the end for block requested above for unstuffing */ + blocks = num_qd * data_blocks + RES_DINODE + num_qd + 1; - al->al_requested = nalloc * (data_blocks + ind_blocks); + if (nalloc) + al->al_requested += nalloc * (data_blocks + ind_blocks); + error = gfs2_inplace_reserve(ip); + if (error) + goto out_alloc; - error = gfs2_inplace_reserve(ip); - if (error) - goto out_alloc; - - error = gfs2_trans_begin(sdp, - al->al_rgd->rd_length + - num_qd * data_blocks + - nalloc * ind_blocks + - RES_DINODE + num_qd + - RES_STATFS, 0); - if (error) - goto out_ipres; - } else { - error = gfs2_trans_begin(sdp, - num_qd * data_blocks + - RES_DINODE + num_qd, 0); - if (error) - goto out_gunlock; - } + if (nalloc) + blocks += al->al_rgd->rd_length + nalloc * ind_blocks + RES_STATFS; + + error = gfs2_trans_begin(sdp, blocks, 0); + if (error) + goto out_ipres; for (x = 0; x < num_qd; x++) { qd = qda[x]; @@ -774,11 +765,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) out_end_trans: gfs2_trans_end(sdp); out_ipres: - if (nalloc) - gfs2_inplace_release(ip); + gfs2_inplace_release(ip); out_alloc: - if (nalloc) - gfs2_alloc_put(ip); + gfs2_alloc_put(ip); out_gunlock: gfs2_glock_dq_uninit(&i_gh); out: -- cgit v1.2.3-70-g09d2 From 860b25d4a913a00331d333f8e207a088c7a1b84a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 10 Mar 2008 10:13:31 +0000 Subject: [GFS2] Remove drop of module ref where not needed In an earlier patch "[GFS2] fix file_system_type leak on gfs2meta mount" we removed the code to grab a ref to the module which was not needed (since we know that the module cannot be unloaded at that time) so this patch removes the code to drop that reference. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 63d5fd203d3..5b518f73497 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -998,7 +998,6 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, error = PTR_ERR(new); goto error; } - module_put(fs_type->owner); new->s_flags = flags; strlcpy(new->s_id, sb->s_id, sizeof(new->s_id)); sb_set_blocksize(new, sb->s_blocksize); -- cgit v1.2.3-70-g09d2 From d82661d96993ac4efc1d54259ea85ffcd9b8bec6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 10 Mar 2008 15:34:50 +0000 Subject: [GFS2] Streamline quota lock/check for no-quota case This patch streamlines the quota checking in the "no quota" case by making the check inline in the calling function, thus reducing the number of function calls. Eventually we might be able to remove the checks from the gfs2_quota_lock() and gfs2_quota_check() functions, but currently we can't as there are a very few places in the code which need to call these functions directly still. Signed-off-by: Steven Whitehouse Cc: Abhijith Das --- fs/gfs2/bmap.c | 6 +----- fs/gfs2/eattr.c | 6 +----- fs/gfs2/ops_address.c | 6 +----- fs/gfs2/ops_file.c | 5 +---- fs/gfs2/ops_inode.c | 12 ++---------- fs/gfs2/quota.h | 17 +++++++++++++++++ 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index f7093aa69aa..c19184f2e70 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -903,14 +903,10 @@ static int do_grow(struct gfs2_inode *ip, u64 size) if (!al) return -ENOMEM; - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + error = gfs2_quota_lock_check(ip); if (error) goto out; - error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); - if (error) - goto out_gunlock_q; - al->al_requested = sdp->sd_max_height + RES_DATA; error = gfs2_inplace_reserve(ip); diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 288d5e6ad93..81755925a75 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -686,14 +686,10 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (!al) return -ENOMEM; - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + error = gfs2_quota_lock_check(ip); if (error) goto out; - error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); - if (error) - goto out_gunlock_q; - al->al_requested = blks; error = gfs2_inplace_reserve(ip); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index e72fd47d71e..90a04a6e378 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -653,14 +653,10 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, goto out_unlock; } - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + error = gfs2_quota_lock_check(ip); if (error) goto out_alloc_put; - error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); - if (error) - goto out_qunlock; - al->al_requested = data_blocks + ind_blocks; error = gfs2_inplace_reserve(ip); if (error) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 2b25a5f7a1c..e1b7d525a06 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -369,12 +369,9 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) if (al == NULL) goto out_unlock; - ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + ret = gfs2_quota_lock_check(ip); if (ret) goto out_alloc_put; - ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); - if (ret) - goto out_quota_unlock; al->al_requested = data_blocks + ind_blocks; ret = gfs2_inplace_reserve(ip); if (ret) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 34fe571e15e..2686ad4c002 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -205,14 +205,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, goto out_gunlock; } - error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + error = gfs2_quota_lock_check(dip); if (error) goto out_alloc; - error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); - if (error) - goto out_gunlock_q; - al->al_requested = sdp->sd_max_dirres; error = gfs2_inplace_reserve(dip); @@ -725,14 +721,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock; } - error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + error = gfs2_quota_lock_check(ndip); if (error) goto out_alloc; - error = gfs2_quota_check(ndip, ndip->i_inode.i_uid, ndip->i_inode.i_gid); - if (error) - goto out_gunlock_q; - al->al_requested = sdp->sd_max_dirres; error = gfs2_inplace_reserve(ndip); diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index a8be1417051..3b7f4b0e5df 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -32,4 +32,21 @@ int gfs2_quota_init(struct gfs2_sbd *sdp); void gfs2_quota_scan(struct gfs2_sbd *sdp); void gfs2_quota_cleanup(struct gfs2_sbd *sdp); +static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + int ret; + if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) + return 0; + ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (ret) + return ret; + if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) + return 0; + ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); + if (ret) + gfs2_quota_unlock(ip); + return ret; +} + #endif /* __QUOTA_DOT_H__ */ -- cgit v1.2.3-70-g09d2 From 1f466a47e8a3a3e3b527b3285c7b9c8a837fb7ec Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 10 Mar 2008 18:17:47 -0500 Subject: [GFS2] Faster gfs2_bitfit algorithm This version of the gfs2_bitfit algorithm includes the latest suggestions from Steve Whitehouse. It is typically eight to ten times faster than the version we're using today. If there is a lot of metadata mixed in (lots of small files) the algorithm is often 15 times faster, and given the right conditions, I've seen peaks of 20 times faster. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 93 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4291375cecc..7e8f0b1d6c6 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -33,6 +34,16 @@ #define BFITNOENT ((u32)~0) #define NO_BLOCK ((u64)~0) +#if BITS_PER_LONG == 32 +#define LBITMASK (0x55555555UL) +#define LBITSKIP55 (0x55555555UL) +#define LBITSKIP00 (0x00000000UL) +#else +#define LBITMASK (0x5555555555555555UL) +#define LBITSKIP55 (0x5555555555555555UL) +#define LBITSKIP00 (0x0000000000000000UL) +#endif + /* * These routines are used by the resource group routines (rgrp.c) * to keep track of block allocation. Each block is represented by two @@ -138,45 +149,63 @@ static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal, u8 old_state) { - const u8 *byte; - u32 blk = goal; - unsigned int bit, bitlong; - const unsigned long *plong; -#if BITS_PER_LONG == 32 - const unsigned long plong55 = 0x55555555; -#else - const unsigned long plong55 = 0x5555555555555555; -#endif - - byte = buffer + (goal / GFS2_NBBY); - plong = (const unsigned long *)(buffer + (goal / GFS2_NBBY)); - bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; - bitlong = bit; - - while (byte < buffer + buflen) { - - if (bitlong == 0 && old_state == 0 && *plong == plong55) { - plong++; - byte += sizeof(unsigned long); - blk += sizeof(unsigned long) * GFS2_NBBY; - continue; + const u8 *byte, *start, *end; + int bit, startbit; + u32 g1, g2, misaligned; + unsigned long *plong; + unsigned long lskipval; + + lskipval = (old_state & GFS2_BLKST_USED) ? LBITSKIP00 : LBITSKIP55; + g1 = (goal / GFS2_NBBY); + start = buffer + g1; + byte = start; + end = buffer + buflen; + g2 = ALIGN(g1, sizeof(unsigned long)); + plong = (unsigned long *)(buffer + g2); + startbit = bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; + misaligned = g2 - g1; + if (!misaligned) + goto ulong_aligned; +/* parse the bitmap a byte at a time */ +misaligned: + while (byte < end) { + if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) { + return goal + + (((byte - start) * GFS2_NBBY) + + ((bit - startbit) >> 1)); } - if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) - return blk; bit += GFS2_BIT_SIZE; - if (bit >= 8) { + if (bit >= GFS2_NBBY * GFS2_BIT_SIZE) { bit = 0; byte++; + misaligned--; + if (!misaligned) { + plong = (unsigned long *)byte; + goto ulong_aligned; + } } - bitlong += GFS2_BIT_SIZE; - if (bitlong >= sizeof(unsigned long) * 8) { - bitlong = 0; - plong++; - } - - blk++; } + return BFITNOENT; +/* parse the bitmap a unsigned long at a time */ +ulong_aligned: + /* Stop at "end - 1" or else prefetch can go past the end and segfault. + We could "if" it but we'd lose some of the performance gained. + This way will only slow down searching the very last 4/8 bytes + depending on architecture. I've experimented with several ways + of writing this section such as using an else before the goto + but this one seems to be the fastest. */ + while ((unsigned char *)plong < end - 1) { + prefetch(plong + 1); + if (((*plong) & LBITMASK) != lskipval) + break; + plong++; + } + if ((unsigned char *)plong < end) { + byte = (const u8 *)plong; + misaligned += sizeof(unsigned long) - 1; + goto misaligned; + } return BFITNOENT; } -- cgit v1.2.3-70-g09d2 From f5a8cd020173c455705fc0095b7d299da6f8f87b Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Wed, 12 Mar 2008 14:01:29 -0700 Subject: [GFS2] fs/gfs2/recovery.c: suppress warnings fs/gfs2/recovery.c: In function 'get_log_header': fs/gfs2/recovery.c:152: warning: 'lh.lh_sequence' may be used uninitialized in this function fs/gfs2/recovery.c:152: warning: 'lh.lh_flags' may be used uninitialized in this function fs/gfs2/recovery.c:152: warning: 'lh.lh_tail' may be used uninitialized in this function fs/gfs2/recovery.c:152: warning: 'lh.lh_blkno' may be used uninitialized in this function fs/gfs2/recovery.c:152: warning: 'lh.lh_hash' may be used uninitialized in this function Cc: David Teigland Cc: Bob Peterson Signed-off-by: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/gfs2/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index b17d3b8b232..06dcdc04627 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -149,7 +149,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, struct gfs2_log_header_host *head) { struct buffer_head *bh; - struct gfs2_log_header_host lh; + struct gfs2_log_header_host uninitialized_var(lh); const u32 nothing = 0; u32 hash; int error; -- cgit v1.2.3-70-g09d2 From 58e9fee13e579df44922172dbe3c9e3ba3edf7a3 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 14 Mar 2008 13:52:52 -0500 Subject: [GFS2] Invalidate cache at correct point GFS2 wasn't invalidating its cache before it called into the lock manager with a request that could potentially drop a lock. This was leaving a window where the lock could be actually be held by another node, but the file's page cache would still appear valid, causing coherency problems. This patch moves the cache invalidation to before the lock manager call when dropping a lock. It also adds the option to the lock_dlm lock manager to not use conversion mode deadlock avoidance, which, on a conversion from shared to exclusive, could internally drop the lock, and then reacquire in. GFS2 now asks lock_dlm to not do this. Instead, GFS2 manually drops the lock and reacquires it. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 35 +++++++++++++++++++++-------------- fs/gfs2/incore.h | 1 + fs/gfs2/locking/dlm/lock.c | 3 ++- fs/gfs2/locking/dlm/thread.c | 10 +++++++++- fs/gfs2/ops_fstype.c | 2 +- include/linux/lm_interface.h | 10 ++++++++++ 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 63981e2fb83..d636b3e80f5 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -764,7 +764,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) static void drop_bh(struct gfs2_glock *gl, unsigned int ret) { struct gfs2_sbd *sdp = gl->gl_sbd; - const struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_holder *gh = gl->gl_req_gh; gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -772,8 +772,14 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) state_change(gl, LM_ST_UNLOCKED); - if (glops->go_inval) - glops->go_inval(gl, DIO_METADATA); + if (test_and_clear_bit(GLF_CONV_DEADLK, &gl->gl_flags)) { + spin_lock(&gl->gl_spin); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + gfs2_glock_xmote_th(gl, gl->gl_req_gh); + gfs2_glock_put(gl); + return; + } spin_lock(&gl->gl_spin); gfs2_demote_wake(gl); @@ -794,7 +800,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_glock_operations *glops = gl->gl_ops; struct gfs2_holder *gh = gl->gl_req_gh; - int prev_state = gl->gl_state; int op_done = 1; if (!gh && (ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) { @@ -808,16 +813,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) state_change(gl, ret & LM_OUT_ST_MASK); - if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) { - if (glops->go_inval) - glops->go_inval(gl, DIO_METADATA); - } else if (gl->gl_state == LM_ST_DEFERRED) { - /* We might not want to do this here. - Look at moving to the inode glops. */ - if (glops->go_inval) - glops->go_inval(gl, 0); - } - /* Deal with each possible exit condition */ if (!gh) { @@ -837,6 +832,14 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) } } else { spin_lock(&gl->gl_spin); + if (ret & LM_OUT_CONV_DEADLK) { + gh->gh_error = 0; + set_bit(GLF_CONV_DEADLK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + gfs2_glock_drop_th(gl); + gfs2_glock_put(gl); + return; + } list_del_init(&gh->gh_list); gh->gh_error = -EIO; if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) @@ -910,6 +913,8 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) if (glops->go_xmote_th) glops->go_xmote_th(gl); + if (state == LM_ST_DEFERRED && glops->go_inval) + glops->go_inval(gl, DIO_METADATA); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -952,6 +957,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) if (glops->go_xmote_th) glops->go_xmote_th(gl); + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 4ba2ea63119..9c2c0b90b22 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -167,6 +167,7 @@ enum { GLF_DEMOTE_IN_PROGRESS = 6, GLF_LFLUSH = 7, GLF_WAITERS2 = 8, + GLF_CONV_DEADLK = 9, }; struct gfs2_glock { diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 542a797ac89..53a6ab3c091 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -137,7 +137,8 @@ static inline unsigned int make_flags(struct gdlm_lock *lp, /* Conversion deadlock avoidance by DLM */ - if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) && + if (!(lp->ls->fsflags & LM_MFLAG_CONV_NODROP) && + !test_bit(LFL_FORCE_PROMOTE, &lp->flags) && !(lkf & DLM_LKF_NOQUEUE) && cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req) lkf |= DLM_LKF_CONVDEADLK; diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 521694fc19d..e53db6fd28a 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -135,7 +135,15 @@ static void process_complete(struct gdlm_lock *lp) lp->lksb.sb_status, lp->lockname.ln_type, (unsigned long long)lp->lockname.ln_number, lp->flags); - return; + if (lp->lksb.sb_status == -EDEADLOCK && + lp->ls->fsflags & LM_MFLAG_CONV_NODROP) { + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CONV_DEADLK; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } else + return; } /* diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5b518f73497..ef9c6c4f80f 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -723,7 +723,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) { char *proto = sdp->sd_proto_name; char *table = sdp->sd_table_name; - int flags = 0; + int flags = LM_MFLAG_CONV_NODROP; int error; if (sdp->sd_args.ar_spectator) diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h index 1418fdc9ac0..f274997bc28 100644 --- a/include/linux/lm_interface.h +++ b/include/linux/lm_interface.h @@ -21,9 +21,15 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); * modify the filesystem. The lock module shouldn't assign a journal to the FS * mount. It shouldn't send recovery callbacks to the FS mount. If the node * dies or withdraws, all locks can be wiped immediately. + * + * LM_MFLAG_CONV_NODROP + * Do not allow the dlm to internally resolve conversion deadlocks by demoting + * the lock to unlocked and then reacquiring it in the requested mode. Instead, + * it should cancel the request and return LM_OUT_CONV_DEADLK. */ #define LM_MFLAG_SPECTATOR 0x00000001 +#define LM_MFLAG_CONV_NODROP 0x00000002 /* * lm_lockstruct flags @@ -110,6 +116,9 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); * * LM_OUT_ASYNC * The result of the request will be returned in an LM_CB_ASYNC callback. + * + * LM_OUT_CONV_DEADLK + * The lock request was canceled do to a conversion deadlock. */ #define LM_OUT_ST_MASK 0x00000003 @@ -117,6 +126,7 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); #define LM_OUT_CANCELED 0x00000008 #define LM_OUT_ASYNC 0x00000080 #define LM_OUT_ERROR 0x00000100 +#define LM_OUT_CONV_DEADLK 0x00000200 /* * lm_callback_t types -- cgit v1.2.3-70-g09d2 From 773adff8e983cba1f5844c3be3be224ca6645f26 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 24 Mar 2008 19:08:48 +0100 Subject: [GFS2] test for IS_ERR rather than 0 The function gfs2_inode_lookup always returns either a valid pointer or a value made with ERR_PTR, so its result should be tested with IS_ERR, not with a test for 0. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @a@ expression E, E1; statement S,S1; position p; @@ E = gfs2_inode_lookup(...) ... when != E = E1 if@p (E) S else S1 @n@ position a.p; expression E,E1; statement S,S1; @@ E = NULL ... when != E = E1 if@p (E) S else S1 @depends on !n@ expression E; statement S,S1; position a.p; @@ * if@p (E) S else S1 // Signed-off-by: Julia Lawall Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_export.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 334c7f85351..990d9f4bc46 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -204,8 +204,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0); - if (!inode) - goto fail; if (IS_ERR(inode)) { error = PTR_ERR(inode); goto fail; -- cgit v1.2.3-70-g09d2 From 16c5f06f15ad4e5a5d6e90b78ffb1ac14319e445 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 9 Apr 2008 09:33:41 -0400 Subject: [GFS2] fix GFP_KERNEL misuses There are several places where GFP_KERNEL allocations happen under a glock, which will result in hangs if we're under memory pressure and go to re-enter the fs in order to flush stuff out. This patch changes the culprits to GFS_NOFS to keep this problem from happening. Thank you, Signed-off-by: Josef Bacik Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 6 +++--- fs/gfs2/dir.c | 10 +++++----- fs/gfs2/eattr.c | 4 ++-- fs/gfs2/inode.c | 2 +- fs/gfs2/locking/dlm/lock.c | 4 ++-- fs/gfs2/locking/nolock/main.c | 2 +- fs/gfs2/quota.c | 8 ++++---- fs/gfs2/recovery.c | 2 +- fs/gfs2/super.c | 4 ++-- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 1047a8c7226..3e9bd46f27e 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -116,7 +116,7 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, goto out; er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); - er.er_data = kmalloc(er.er_data_len, GFP_KERNEL); + er.er_data = kmalloc(er.er_data_len, GFP_NOFS); error = -ENOMEM; if (!er.er_data) goto out; @@ -222,7 +222,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) return error; } - clone = posix_acl_clone(acl, GFP_KERNEL); + clone = posix_acl_clone(acl, GFP_NOFS); error = -ENOMEM; if (!clone) goto out; @@ -272,7 +272,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) if (!acl) return gfs2_setattr_simple(ip, attr); - clone = posix_acl_clone(acl, GFP_KERNEL); + clone = posix_acl_clone(acl, GFP_NOFS); error = -ENOMEM; if (!clone) goto out; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 94070ad8826..eed040d8ba3 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1089,7 +1089,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) /* Allocate both the "from" and "to" buffers in one big chunk */ - buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL); + buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS | __GFP_NOFAIL); for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { error = gfs2_dir_read_data(dip, (char *)buf, @@ -1378,7 +1378,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, hash = gfs2_dir_offset2hash(*offset); index = hash >> (32 - dip->i_depth); - lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); if (!lp) return -ENOMEM; @@ -1443,7 +1443,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, error = -ENOMEM; /* 96 is max number of dirents which can be stuffed into an inode */ - darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL); + darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS); if (darr) { g.pdent = darr; g.offset = 0; @@ -1789,7 +1789,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) return -EIO; } - lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); if (!lp) return -ENOMEM; @@ -1864,7 +1864,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); - ht = kzalloc(size, GFP_KERNEL); + ht = kzalloc(size, GFP_NOFS); if (!ht) return -ENOMEM; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 81755925a75..e3f76f451b0 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -448,7 +448,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, unsigned int x; int error = 0; - bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); + bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS); if (!bh) return -ENOMEM; @@ -1206,7 +1206,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, unsigned int x; int error; - bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); + bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS); if (!bh) return -ENOMEM; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index dcae2aa83f1..3a9ef526c30 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1231,7 +1231,7 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) x = ip->i_di.di_size + 1; if (x > *len) { - *buf = kmalloc(x, GFP_KERNEL); + *buf = kmalloc(x, GFP_NOFS); if (!*buf) { error = -ENOMEM; goto out_brelse; diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 53a6ab3c091..cf7ea8abec8 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -165,7 +165,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, { struct gdlm_lock *lp; - lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL); + lp = kzalloc(sizeof(struct gdlm_lock), GFP_NOFS); if (!lp) return -ENOMEM; @@ -383,7 +383,7 @@ static int gdlm_add_lvb(struct gdlm_lock *lp) { char *lvb; - lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL); + lvb = kzalloc(GDLM_LVB_SIZE, GFP_NOFS); if (!lvb) return -ENOMEM; diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index d3b8ce6fbbe..284a5ece8d9 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -140,7 +140,7 @@ static int nolock_hold_lvb(void *lock, char **lvbp) struct nolock_lockspace *nl = lock; int error = 0; - *lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL); + *lvbp = kzalloc(nl->nl_lvb_size, GFP_NOFS); if (!*lvbp) error = -ENOMEM; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c71f781db5d..56aaf915c59 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -94,7 +94,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, struct gfs2_quota_data *qd; int error; - qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL); + qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_NOFS); if (!qd) return -ENOMEM; @@ -690,7 +690,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), &data_blocks, &ind_blocks); - ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL); + ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_NOFS); if (!ghs) return -ENOMEM; @@ -1118,12 +1118,12 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) error = -ENOMEM; sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks, - sizeof(unsigned char *), GFP_KERNEL); + sizeof(unsigned char *), GFP_NOFS); if (!sdp->sd_quota_bitmap) return error; for (x = 0; x < sdp->sd_quota_chunks; x++) { - sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL); + sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_NOFS); if (!sdp->sd_quota_bitmap[x]) goto fail; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 06dcdc04627..2888e4b4b1c 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -68,7 +68,7 @@ int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) return 0; } - rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL); + rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_NOFS); if (!rr) return -ENOMEM; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 88497b0b733..7aeacbc65f3 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -210,7 +210,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) struct page *page; struct bio *bio; - page = alloc_page(GFP_KERNEL); + page = alloc_page(GFP_NOFS); if (unlikely(!page)) return -ENOBUFS; @@ -218,7 +218,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) ClearPageDirty(page); lock_page(page); - bio = bio_alloc(GFP_KERNEL, 1); + bio = bio_alloc(GFP_NOFS, 1); if (unlikely(!bio)) { __free_page(page); return -ENOBUFS; -- cgit v1.2.3-70-g09d2 From 62be1f71677c53d5e51223807a06ac9052f49b0f Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Thu, 17 Apr 2008 17:25:37 +0200 Subject: [GFS2] fix assertion in log_refund() since unsigned, unused >= 0 is always true. Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b335304fc5d..548264b1836 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -769,8 +769,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); reserved = calc_reserved(sdp); + gfs2_assert_withdraw(sdp, sdp->sd_log_blks_reserved + tr->tr_reserved >= reserved); unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved; - gfs2_assert_withdraw(sdp, unused >= 0); atomic_add(unused, &sdp->sd_log_blks_free); gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); -- cgit v1.2.3-70-g09d2