GIT c8f3a3330f830d7818a3537c8b8d14e8e6678183 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git commit Author: Bob Peterson Date: Thu Jan 31 10:31:39 2008 -0600 [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 commit dd9c340d9275ee163cc6d970936a638e579fbb90 Author: Steven Whitehouse Date: Wed Jan 30 15:34:04 2008 +0000 [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 commit ac09dedb6c310d5ac221611b07a03f89dba294f4 Author: Bob Peterson Date: Tue Jan 29 13:56:15 2008 -0600 [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 commit 4da612bf79bd2a69ba36f924414f66435a462bd1 Author: Steven Whitehouse Date: Tue Jan 29 13:30:20 2008 +0000 [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 commit 298ffcba5c9b85d1863e91f196b9a7d6fca6a0ec Author: Steven Whitehouse Date: Tue Jan 29 09:12:55 2008 +0000 [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 commit bc038bf2dd3f7fbdbe42cd84b47b164d5ba786f7 Author: Steven Whitehouse Date: Mon Jan 28 15:10:29 2008 +0000 [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 commit 83149bd56c7e44799204130ffc30a841739f7829 Author: Bob Peterson Date: Mon Jan 28 22:31:39 2008 -0600 [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 commit d7aee72c8cb78a90af5118903a5169b5f4e80665 Author: Bob Peterson Date: Mon Jan 28 18:38:07 2008 -0600 [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 commit 848d52154963afd4948602fee623f28fc204901f Author: Bob Peterson Date: Mon Jan 28 17:20:26 2008 -0600 [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 commit 0ac14a7da2a308c5eaa35503bab6602b8e11698c Author: Bob Peterson Date: Mon Jan 28 16:35:13 2008 -0600 [GFS2] Plug an unlikely leak Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse commit e139fc1a71b47c7b1d04d8b80048628e27c39b0b Author: Adrian Bunk Date: Tue Jan 29 00:11:34 2008 +0200 [GFS2] make gfs2_glock_hold() static gfs2_glock_hold() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse commit 13ad5ab1cbae21528db1258d51249430251b5a93 Author: Bob Peterson Date: Mon Jan 28 14:54:16 2008 -0600 [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 commit b5987dff3461679962346e43d15a588c82454baa Author: Bob Peterson Date: Mon Jan 28 11:24:35 2008 -0600 [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 commit ad9ff8dc0b7960bb2245d41e10981c8d26b2bc33 Author: Bob Peterson Date: Mon Jan 28 11:20:10 2008 -0600 [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 commit d794faa497c46d2869af045204766a92ad380b09 Author: Bob Peterson Date: Mon Jan 28 11:15:57 2008 -0600 [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 commit 209f3c0654573075c9229a414726c199567268f3 Author: Bob Peterson Date: Mon Jan 28 11:13:02 2008 -0600 [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 commit 69245672086159aae424702521578edac29dff1c Author: Steven Whitehouse Date: Mon Jan 28 10:37:35 2008 +0000 [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 commit 0004e0d3aebbbeb32b1515294804a2b959582add Author: Steven Whitehouse Date: Mon Jan 28 08:47:38 2008 +0000 [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/Makefile | 2 +- fs/gfs2/bmap.c | 267 +++++++++++++++++++++++-------------------------- fs/gfs2/dir.c | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/glock.c | 172 +++++++++++++++++++------------ fs/gfs2/glock.h | 1 - fs/gfs2/glops.c | 10 ++- fs/gfs2/incore.h | 25 ++--- fs/gfs2/inode.c | 23 +++-- fs/gfs2/inode.h | 2 +- fs/gfs2/lm.c | 210 -------------------------------------- fs/gfs2/lm.h | 42 -------- fs/gfs2/log.c | 17 +++- fs/gfs2/lops.c | 21 +---- fs/gfs2/lops.h | 11 +-- fs/gfs2/main.c | 10 ++ fs/gfs2/ops_address.c | 4 +- fs/gfs2/ops_file.c | 31 ++++++- fs/gfs2/ops_fstype.c | 75 +++++++++++++- fs/gfs2/ops_super.c | 1 - fs/gfs2/recovery.c | 11 ++- fs/gfs2/rgrp.c | 105 +++++++++++--------- fs/gfs2/rgrp.h | 5 +- fs/gfs2/super.c | 2 + fs/gfs2/super.h | 1 + fs/gfs2/sys.c | 1 - fs/gfs2/util.c | 24 ++++- fs/gfs2/util.h | 2 + 28 files changed, 497 insertions(+), 582 deletions(-) diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 8fff110..e2350df 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/bmap.c b/fs/gfs2/bmap.c index e4effc4..9365221 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]; }; @@ -166,7 +167,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: @@ -177,43 +178,6 @@ out: } /** - * 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 * @height: The height to build to @@ -222,19 +186,18 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) * 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_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; int error; __be64 *bp; 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); @@ -243,37 +206,37 @@ 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)); *(__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; @@ -342,17 +305,15 @@ 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_di.di_height; i--;) - mp->mp_list[i] = do_div(b, sdp->sd_inptrs); + for (i = ip->i_height; i--;) + mp->mp_list[i] = do_div(block, sdp->sd_inptrs); } /** * metapointer - Return pointer to start of metadata in a buffer - * @bh: The buffer * @height: The metadata height (0 = dinode) * @mp: The metapath * @@ -361,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; @@ -377,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 @@ -390,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); @@ -407,12 +368,12 @@ 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); - 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++; @@ -422,6 +383,41 @@ 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 *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; + + mp->mp_bh[0] = bh; + + for (x = 0; x < end_of_metadata; x++) { + lookup_block(ip, x, mp, create, new, dblock); + if (!dblock) + return 0; + + ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &mp->mp_bh[x+1]); + if (ret) + return ret; + } + + 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) { struct gfs2_inode *ip = GFS2_I(inode); @@ -457,11 +453,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 end_of_metadata; - unsigned int x; + unsigned int bsize = sdp->sd_sb.sb_bsize; int error = 0; int new = 0; u64 dblock = 0; @@ -469,67 +461,54 @@ 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); clear_buffer_boundary(bh_map); - bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; - 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 (gfs2_is_dir(ip)) { + bsize = sdp->sd_jbsize; + arr = sdp->sd_jheightsize; } + size = (lblock + 1) * bsize; - find_metapath(ip, lblock, &mp); - end_of_metadata = ip->i_di.di_height - 1; - error = gfs2_meta_inode_buffer(ip, &bh); - if (error) - 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) + if (size > arr[ip->i_height]) { + u8 height = ip->i_height; + if (!create) goto out_ok; - - error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); + while (size > arr[height]) + height++; + error = build_height(inode, &mp, height); if (error) goto out_fail; } - boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock); + find_metapath(ip, lblock, &mp); + error = lookup_metapath(inode, &mp, create, &new, &dblock); + if (error < 0) + goto out_fail; + boundary = error; + if (dblock) { map_bh(bh_map, inode->i_sb, dblock); 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)) { 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); @@ -537,17 +516,17 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, set_buffer_boundary(bh_map); } } -out_brelse: - brelse(bh); out_ok: error = 0; out_fail: - if (dibh) - brelse(dibh); + release_metapath(&mp); bmap_unlock(inode, create); 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 }; @@ -621,7 +600,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; @@ -679,7 +658,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; @@ -713,7 +692,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; @@ -804,7 +783,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); @@ -830,20 +808,24 @@ 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]) { + struct metapath mp; + u8 height = ip->i_height; + while(size > arr[height]) + height++; + error = build_height(&ip->i_inode, &mp, height); } + up_write(&ip->i_rw_mutex); + if (error) + goto out_end_trans; } ip->i_di.di_size = size; @@ -986,7 +968,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; @@ -1037,7 +1019,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; @@ -1197,10 +1179,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 +1195,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 +1204,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; } diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 57e2ed9..165f295 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 bee9970..04febbc 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/glock.c b/fs/gfs2/glock.c index 80e09c5..d9b2b04 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 @@ -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); @@ -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); } @@ -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 @@ -338,8 +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_req_bh = NULL; - gl->gl_vn = 0; gl->gl_stamp = jiffies; gl->gl_tchange = jiffies; gl->gl_object = NULL; @@ -594,11 +602,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); @@ -704,7 +713,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; } @@ -737,6 +746,50 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) } /** + * 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 * @ret: the int returned from the lock module @@ -751,6 +804,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)); @@ -776,7 +834,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); @@ -818,7 +875,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); } @@ -829,6 +885,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 @@ -857,7 +924,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); @@ -870,49 +936,13 @@ 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) +static unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock, + unsigned int cur_state) { - 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); + 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; } /** @@ -935,7 +965,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); @@ -958,16 +987,17 @@ 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); 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); + 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 { @@ -1035,7 +1065,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); @@ -1420,6 +1449,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 @@ -1455,12 +1492,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); } @@ -1526,8 +1566,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); @@ -1586,10 +1625,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); } /** @@ -1888,7 +1927,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/glock.h b/fs/gfs2/glock.h index b16f604..0724076 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -77,7 +77,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); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index c663b7a..d31bada 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 513aaf0..4c921ec 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 @@ -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, @@ -70,7 +69,6 @@ struct gfs2_bitmap { }; struct gfs2_rgrp_host { - u32 rg_flags; u32 rg_free; u32 rg_dinodes; u64 rg_igeneration; @@ -87,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; @@ -96,8 +93,10 @@ 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 */ +#define GFS2_RDF_UPTODATE 0x04 /* rg is up to date */ }; enum gfs2_state_bits { @@ -168,6 +167,7 @@ enum { GLF_DIRTY = 5, GLF_DEMOTE_IN_PROGRESS = 6, GLF_LFLUSH = 7, + GLF_WAITERS2 = 8, }; struct gfs2_glock { @@ -187,18 +187,15 @@ 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; struct gfs2_holder *gl_req_gh; - gfs2_glop_bh_t gl_req_bh; void *gl_lock; char *gl_lvb; atomic_t gl_lvb_count; - u64 gl_vn; unsigned long gl_stamp; unsigned long gl_tchange; void *gl_object; @@ -213,6 +210,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 */ @@ -246,7 +245,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 +266,7 @@ struct gfs2_inode { u64 i_last_rg_alloc; struct rw_semaphore i_rw_mutex; + u8 i_height; }; /* @@ -490,9 +489,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 */ @@ -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/inode.c b/fs/gfs2/inode.c index 728d316..11c5ce4 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 @@ -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,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 " di_height = %u\n", di->di_height); + 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", diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index d446506..db73868 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/lm.c b/fs/gfs2/lm.c deleted file mode 100644 index cfcc39b..0000000 --- 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 21cdc30..0000000 --- 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/log.c b/fs/gfs2/log.c index 161ab6f..b335304 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 fae59d6..4390f6f 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; @@ -419,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++; @@ -737,7 +724,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 +749,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 41a00df..3c0b273 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; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 9c7765c..053e2eb 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/ops_address.c b/fs/gfs2/ops_address.c index 38dbe99..e601016 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) */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index f4842f2..f97a8b8 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 43d511b..0f765c4 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 @@ -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; @@ -542,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"); @@ -705,6 +711,69 @@ fail: } /** + * 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 * @data: Mount options diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 5e52421..2278c68 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 b249e29..7165d03 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/rgrp.c b/fs/gfs2/rgrp.c index 3552110..3f10b1f 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 @@ -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++) { @@ -353,7 +354,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) } kfree(rgd->rd_bits); - kfree(rgd); + kmem_cache_free(gfs2_rgrpd_cachep, rgd); } } @@ -516,7 +517,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; @@ -539,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; } @@ -575,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; } @@ -609,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; } @@ -642,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); @@ -655,21 +656,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); @@ -726,9 +737,9 @@ 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); - 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_flags |= GFS2_RDF_UPTODATE; } spin_lock(&sdp->sd_rindex_spin); @@ -840,7 +851,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); @@ -1317,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; @@ -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); @@ -1699,8 +1709,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 +1717,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 149bb16..5683605 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); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index ef0562c..88497b0 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; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 60a870e..44361ec 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 eaa3b7b..cc35ec8 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 424a077..d31e355 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -19,12 +19,12 @@ #include "gfs2.h" #include "incore.h" #include "glock.h" -#include "lm.h" #include "util.h" 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) { @@ -32,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 28938a4..509c5d6 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) @@ -163,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__ */