diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-21 17:05:23 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-21 17:05:23 -0400 |
commit | 7276b3b0c77101f8b3f4e45e89a29cf9045e831a (patch) | |
tree | 3dd0a981218e490ddf47f925ba20c254e491ce98 /fs/gfs2 | |
parent | 91fa47964165a42401fbc1f41caa63ab78564305 (diff) |
[GFS2] Tidy up meta_io code
Fix a bug in the directory reading code, where we might have dereferenced
a NULL pointer in case of OOM. Updated the directory code to use the new
& improved version of gfs2_meta_ra() which now returns the first block
that was being read. Previously it was releasing it requiring following
code to grab the block again at each point it was called.
Also turned off readahead on directory lookups since we are reading a
hash table, and therefore reading the entries in order is very
unlikely. Readahead is still used for all other calls to the
directory reading function (e.g. when growing the hash table).
Removed the DIO_START constant. Everywhere this was used, it was
used to unconditionally start i/o aside from a couple of places, so
I've removed it and made the couple of exceptions to this rule into
separate functions.
Also hunted through the other DIO flags and removed them as arguments
from functions which were always called with the same combination of
arguments.
Updated gfs2_meta_indirect_buffer to be a bit more efficient and
hopefully also be a bit easier to read.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/bmap.c | 4 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 56 | ||||
-rw-r--r-- | fs/gfs2/eattr.c | 23 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 55 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 1 | ||||
-rw-r--r-- | fs/gfs2/lops.c | 9 | ||||
-rw-r--r-- | fs/gfs2/meta_io.c | 173 | ||||
-rw-r--r-- | fs/gfs2/meta_io.h | 6 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 2 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 16 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 3 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 5 |
12 files changed, 163 insertions, 190 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 19b9bfc10349..3fb9a26b6f58 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -448,6 +448,8 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, u64 dblock = 0; int boundary; + BUG_ON(maxlen == 0); + if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) return 0; @@ -561,7 +563,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!new); bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, *extlen); + ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, 32); bmap_unlock(inode, create); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 739028688270..40e94ac0b93d 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -106,7 +106,7 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head *bh; int error; - error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); if (error) return error; if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { @@ -246,7 +246,7 @@ fail: } static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size) + u64 offset, unsigned int size) { struct buffer_head *dibh; int error; @@ -271,8 +271,8 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, * * Returns: The amount of data actually copied or the error */ -static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, - u64 offset, unsigned int size) +static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, + unsigned int size, unsigned ra) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); u64 lblock, dblock; @@ -291,8 +291,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, return 0; if (gfs2_is_stuffed(ip)) - return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, - size); + return gfs2_dir_read_stuffed(ip, buf, offset, size); if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; @@ -313,34 +312,31 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, new = 0; error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); - if (error) + if (error || !dblock) goto fail; + BUG_ON(extlen < 1); + if (!ra) + extlen = 1; + bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); } - - if (extlen > 1) - gfs2_meta_ra(ip->i_gl, dblock, extlen); - - if (dblock) { - if (new) - error = gfs2_dir_get_new_buffer(ip, dblock, &bh); - else - error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); + if (!bh) { + error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); if (error) goto fail; - dblock++; - extlen--; - } else - bh = NULL; - + } + error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD); + if (error) { + brelse(bh); + goto fail; + } + dblock++; + extlen--; memcpy(buf, bh->b_data + o, amount); brelse(bh); - if (error) - goto fail; - + bh = NULL; buf += amount; copied += amount; lblock++; - o = sizeof(struct gfs2_meta_header); } @@ -701,7 +697,7 @@ static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, { int error; - error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); + error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { /* printk(KERN_INFO "block num=%llu\n", leaf_no); */ error = -EIO; @@ -727,7 +723,7 @@ static int get_leaf_nr(struct gfs2_inode *dip, u32 index, error = gfs2_dir_read_data(dip, (char *)&leaf_no, index * sizeof(u64), - sizeof(u64)); + sizeof(u64), 0); if (error != sizeof(u64)) return (error < 0) ? error : -EIO; @@ -1095,7 +1091,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { error = gfs2_dir_read_data(dip, (char *)buf, block * sdp->sd_hash_bsize, - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1375,7 +1371,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(u64), - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1745,7 +1741,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(u64), - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 698942ec7c99..bd5ca602f9f0 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -115,7 +115,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) u64 *eablk, *end; int error; - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh); if (error) return error; @@ -139,7 +139,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) break; bn = be64_to_cpu(*eablk); - error = gfs2_meta_read(ip->i_gl, bn, DIO_START | DIO_WAIT, &eabh); + error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh); if (error) break; error = ea_foreach_i(ip, eabh, ea_call, data); @@ -453,8 +453,8 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, return -ENOMEM; for (x = 0; x < nptrs; x++) { - error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), - DIO_START, bh + x); + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, + bh + x); if (error) { while (x--) brelse(bh[x]); @@ -464,7 +464,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, } for (x = 0; x < nptrs; x++) { - error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + error = gfs2_meta_wait(sdp, bh[x]); if (error) { for (; x < nptrs; x++) brelse(bh[x]); @@ -938,8 +938,8 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { u64 *end; - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, - DIO_START | DIO_WAIT, &indbh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, + &indbh); if (error) return error; @@ -1215,8 +1215,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, goto out; for (x = 0; x < nptrs; x++) { - error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), - DIO_START, bh + x); + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, + bh + x); if (error) { while (x--) brelse(bh[x]); @@ -1226,7 +1226,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, } for (x = 0; x < nptrs; x++) { - error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + error = gfs2_meta_wait(sdp, bh[x]); if (error) { for (; x < nptrs; x++) brelse(bh[x]); @@ -1310,8 +1310,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, - DIO_START | DIO_WAIT, &indbh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh); if (error) return error; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 9c046dbf4729..ef1492e2d445 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -77,32 +77,24 @@ static void gfs2_page_inval(struct gfs2_glock *gl) } /** - * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock + * gfs2_page_wait - Wait for writeback of data * @gl: the glock - * @flags: DIO_START | DIO_WAIT * * Syncs data (not metadata) for a regular file. * No-op for all other types. */ -static void gfs2_page_sync(struct gfs2_glock *gl, int flags) +static void gfs2_page_wait(struct gfs2_glock *gl) { - struct gfs2_inode *ip; - struct inode *inode; - struct address_space *mapping; - int error = 0; + struct gfs2_inode *ip = gl->gl_object; + struct inode *inode = &ip->i_inode; + struct address_space *mapping = inode->i_mapping; + int error; - ip = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) + if (!S_ISREG(ip->i_di.di_mode)) return; - mapping = inode->i_mapping; - - if (flags & DIO_START) - filemap_fdatawrite(mapping); - if (!error && (flags & DIO_WAIT)) - error = filemap_fdatawait(mapping); + error = filemap_fdatawait(mapping); /* Put back any errors cleared by filemap_fdatawait() so they can be caught by someone who can pass them @@ -115,6 +107,18 @@ static void gfs2_page_sync(struct gfs2_glock *gl, int flags) } +static void gfs2_page_writeback(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip = gl->gl_object; + struct inode *inode = &ip->i_inode; + struct address_space *mapping = inode->i_mapping; + + if (!S_ISREG(ip->i_di.di_mode)) + return; + + filemap_fdatawrite(mapping); +} + /** * meta_go_sync - sync out the metadata for this glock * @gl: the glock @@ -132,7 +136,7 @@ static void meta_go_sync(struct gfs2_glock *gl, int flags) if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); + gfs2_meta_sync(gl); if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); } @@ -185,8 +189,7 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl) if (gl->gl_state != LM_ST_UNLOCKED && (!gh || !(gh->gh_flags & GL_SKIP))) { - error = gfs2_meta_read(gl, gl->gl_name.ln_number, DIO_START, - &bh); + error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh); if (!error) brelse(bh); } @@ -221,16 +224,18 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) if (test_bit(GLF_DIRTY, &gl->gl_flags)) { if (meta && data) { - gfs2_page_sync(gl, flags | DIO_START); + gfs2_page_writeback(gl); gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); - gfs2_page_sync(gl, flags | DIO_WAIT); + gfs2_meta_sync(gl); + gfs2_page_wait(gl); clear_bit(GLF_DIRTY, &gl->gl_flags); } else if (meta) { gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); - } else if (data) - gfs2_page_sync(gl, flags | DIO_START | DIO_WAIT); + gfs2_meta_sync(gl); + } else if (data) { + gfs2_page_writeback(gl); + gfs2_page_wait(gl); + } if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 7183dcf03563..118dc693d111 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -12,7 +12,6 @@ #include <linux/fs.h> -#define DIO_START 0x00000008 #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 #define DIO_DATA 0x00000040 diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index e44d245d51d4..2a98cbe3290f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -248,13 +248,13 @@ static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); return; } if (pass != 1) return; - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); @@ -726,15 +726,14 @@ static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_meta_sync(ip->i_gl, - DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); return; } if (pass != 1) return; /* data sync? */ - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 6b52aacb0736..d3708af0a4d1 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -273,19 +273,16 @@ void gfs2_meta_inval(struct gfs2_glock *gl) /** * gfs2_meta_sync - Sync all buffers associated with a glock * @gl: The glock - * @flags: DIO_START | DIO_WAIT * */ -void gfs2_meta_sync(struct gfs2_glock *gl, int flags) +void gfs2_meta_sync(struct gfs2_glock *gl) { struct address_space *mapping = gl->gl_aspace->i_mapping; - int error = 0; + int error; - if (flags & DIO_START) - filemap_fdatawrite(mapping); - if (!error && (flags & DIO_WAIT)) - error = filemap_fdatawait(mapping); + filemap_fdatawrite(mapping); + error = filemap_fdatawait(mapping); if (error) gfs2_io_error(gl->gl_sbd); @@ -377,7 +374,7 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) * gfs2_meta_read - Read a block from disk * @gl: The glock covering the block * @blkno: The block number - * @flags: flags to gfs2_dreread() + * @flags: flags * @bhp: the place where the buffer is returned (NULL on failure) * * Returns: errno @@ -386,45 +383,43 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp) { - int error; - *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); - error = gfs2_meta_reread(gl->gl_sbd, *bhp, flags); - if (error) - brelse(*bhp); + if (!buffer_uptodate(*bhp)) + ll_rw_block(READ, 1, bhp); + if (flags & DIO_WAIT) { + int error = gfs2_meta_wait(gl->gl_sbd, *bhp); + if (error) { + brelse(*bhp); + return error; + } + } - return error; + return 0; } /** - * gfs2_meta_reread - Reread a block from disk + * gfs2_meta_wait - Reread a block from disk * @sdp: the filesystem - * @bh: The block to read - * @flags: Flags that control the read + * @bh: The block to wait for * * Returns: errno */ -int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) +int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) { if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) return -EIO; - if ((flags & DIO_START) && !buffer_uptodate(bh)) - ll_rw_block(READ, 1, &bh); - - if (flags & DIO_WAIT) { - wait_on_buffer(bh); + wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - struct gfs2_trans *tr = current->journal_info; - if (tr && tr->tr_touched) - gfs2_io_error_bh(sdp, bh); - return -EIO; - } - if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - return -EIO; + if (!buffer_uptodate(bh)) { + struct gfs2_trans *tr = current->journal_info; + if (tr && tr->tr_touched) + gfs2_io_error_bh(sdp, bh); + return -EIO; } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; return 0; } @@ -635,67 +630,57 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, int new, struct buffer_head **bhp) { - struct buffer_head *bh, **bh_slot = ip->i_cache + height; - int error; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct gfs2_glock *gl = ip->i_gl; + struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height; + int in_cache = 0; spin_lock(&ip->i_spin); - bh = *bh_slot; - if (bh) { - if (bh->b_blocknr == num) - get_bh(bh); - else - bh = NULL; + if (*bh_slot && (*bh_slot)->b_blocknr == num) { + bh = *bh_slot; + get_bh(bh); + in_cache = 1; } spin_unlock(&ip->i_spin); - if (bh) { - if (new) - meta_prep_new(bh); - else { - error = gfs2_meta_reread(GFS2_SB(&ip->i_inode), bh, - DIO_START | DIO_WAIT); - if (error) { - brelse(bh); - return error; - } - } - } else { - if (new) - bh = gfs2_meta_new(ip->i_gl, num); - else { - error = gfs2_meta_read(ip->i_gl, num, - DIO_START | DIO_WAIT, &bh); - if (error) - return error; - } + if (!bh) + bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE); - spin_lock(&ip->i_spin); - if (*bh_slot != bh) { - brelse(*bh_slot); - *bh_slot = bh; - get_bh(bh); - } - spin_unlock(&ip->i_spin); - } + if (!bh) + return -ENOBUFS; if (new) { - if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), height)) { - brelse(bh); - return -EIO; - } + if (gfs2_assert_warn(sdp, height)) + goto err; + meta_prep_new(bh); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + } else { + u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; + if (!buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + if (gfs2_meta_wait(sdp, bh)) + goto err; + } + if (gfs2_metatype_check(sdp, bh, mtype)) + goto err; + } - } else if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, - (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { - brelse(bh); - return -EIO; + if (!in_cache) { + spin_lock(&ip->i_spin); + if (*bh_slot) + brelse(*bh_slot); + *bh_slot = bh; + get_bh(bh); + spin_unlock(&ip->i_spin); } *bhp = bh; - return 0; +err: + brelse(bh); + return -EIO; } /** @@ -704,19 +689,21 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, * @dblock: the starting disk block * @extlen: the number of blocks in the extent * + * returns: the first buffer in the extent */ -void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) +struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) { struct gfs2_sbd *sdp = gl->gl_sbd; struct inode *aspace = gl->gl_aspace; struct buffer_head *first_bh, *bh; u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; - int error; - if (!extlen || !max_ra) - return; + BUG_ON(!extlen); + + if (max_ra < 1) + max_ra = 1; if (extlen > max_ra) extlen = max_ra; @@ -724,11 +711,8 @@ void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) if (buffer_uptodate(first_bh)) goto out; - if (!buffer_locked(first_bh)) { - error = gfs2_meta_reread(sdp, first_bh, DIO_START); - if (error) - goto out; - } + if (!buffer_locked(first_bh)) + ll_rw_block(READ, 1, &first_bh); dblock++; extlen--; @@ -736,23 +720,18 @@ void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) while (extlen) { bh = getbuf(sdp, aspace, dblock, CREATE); - if (!buffer_uptodate(bh) && !buffer_locked(bh)) { - error = gfs2_meta_reread(sdp, bh, DIO_START); - brelse(bh); - if (error) - goto out; - } else - brelse(bh); - + if (!buffer_uptodate(bh) && !buffer_locked(bh)) + ll_rw_block(READA, 1, &bh); + brelse(bh); dblock++; extlen--; - - if (buffer_uptodate(first_bh)) - break; + if (!buffer_locked(first_bh) && buffer_uptodate(first_bh)) + goto out; } + wait_on_buffer(first_bh); out: - brelse(first_bh); + return first_bh; } /** diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 086a472df3f1..3323e6d0ed8f 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -46,12 +46,12 @@ void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai); void gfs2_ail_empty_gl(struct gfs2_glock *gl); void gfs2_meta_inval(struct gfs2_glock *gl); -void gfs2_meta_sync(struct gfs2_glock *gl, int flags); +void gfs2_meta_sync(struct gfs2_glock *gl); struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp); -int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags); +int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); @@ -71,7 +71,7 @@ static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp); } -void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); +struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); #endif /* __DIO_DOT_H__ */ diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 3f9da7ce5dd9..8b18e974fa4d 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -65,7 +65,7 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, create, bh_result, 4); + return gfs2_block_map(inode, lblock, create, bh_result, 32); } /** diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c5eb6c646177..da46e14388f4 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -265,7 +265,7 @@ static int bh_get(struct gfs2_quota_data *qd) error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1); if (error) goto fail; - error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); if (error) goto fail; error = -EIO; @@ -1059,8 +1059,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) u32 extlen = 0; int error; - if (!ip->i_di.di_size || - ip->i_di.di_size > (64 << 20) || + if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) || ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) { gfs2_consist_inode(ip); return -EIO; @@ -1091,19 +1090,16 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) if (error) goto fail; } - gfs2_meta_ra(ip->i_gl, dblock, extlen); - error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, - &bh); - if (error) - goto fail; error = -EIO; + bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); + if (!bh) + goto fail; if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) { brelse(bh); goto fail; } - for (y = 0; - y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots; + for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots; y++, slot++) { struct gfs2_quota_change qc; struct gfs2_quota_data *qd; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 518f9128137e..4d4ea7e66edc 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -47,8 +47,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, return -EIO; } - gfs2_meta_ra(gl, dblock, extlen); - error = gfs2_meta_read(gl, dblock, DIO_START | DIO_WAIT, bh); + *bh = gfs2_meta_ra(gl, dblock, extlen); return error; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 113b4ace6893..5f8e225c5497 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -575,15 +575,14 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) for (x = 0; x < length; x++) { bi = rgd->rd_bits + x; - error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, DIO_START, - &bi->bi_bh); + error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &bi->bi_bh); if (error) goto fail; } for (y = length; y--;) { bi = rgd->rd_bits + y; - error = gfs2_meta_reread(sdp, bi->bi_bh, DIO_WAIT); + error = gfs2_meta_wait(sdp, bi->bi_bh); if (error) goto fail; if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB : |