X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fgfs2%2Fmeta_io.c;h=0bb12c80937a85801bb45f96bce6ce53f994d382;hb=436c109adb54433fff689abd71c23a6505e46bb0;hp=b6bd2ebfc2cc808153df0998f7904076cf541e78;hpb=a98ab2204f8ed414c5e95fbca28a9f001c53bc7b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index b6bd2eb..0bb12c8 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -1,10 +1,10 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 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 - * of the GNU General Public License v.2. + * of the GNU General Public License version 2. */ #include @@ -17,9 +17,11 @@ #include #include #include -#include +#include +#include #include "gfs2.h" +#include "incore.h" #include "glock.h" #include "glops.h" #include "inode.h" @@ -28,386 +30,106 @@ #include "meta_io.h" #include "rgrp.h" #include "trans.h" +#include "util.h" -#define buffer_busy(bh) \ -((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) -#define buffer_in_io(bh) \ -((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock))) - -static int aspace_get_block(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create) -{ - gfs2_assert_warn(get_v2sdp(inode->i_sb), 0); - return -EOPNOTSUPP; -} - -static int gfs2_aspace_writepage(struct page *page, - struct writeback_control *wbc) -{ - return block_write_full_page(page, aspace_get_block, wbc); -} - -/** - * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. - * @bh: the buffer we're stuck on - * - */ - -static void stuck_releasepage(struct buffer_head *bh) -{ - struct gfs2_sbd *sdp = get_v2sdp(bh->b_page->mapping->host->i_sb); - struct gfs2_bufdata *bd = get_v2bd(bh); - struct gfs2_glock *gl; - - fs_warn(sdp, "stuck in gfs2_releasepage()\n"); - fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", - (uint64_t)bh->b_blocknr, atomic_read(&bh->b_count)); - fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); - fs_warn(sdp, "get_v2bd(bh) = %s\n", (bd) ? "!NULL" : "NULL"); - - if (!bd) - return; - - gl = bd->bd_gl; - - fs_warn(sdp, "gl = (%u, %llu)\n", - gl->gl_name.ln_type, gl->gl_name.ln_number); - - fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", - (list_empty(&bd->bd_list_tr)) ? "no" : "yes", - (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); - - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = get_gl2ip(gl); - unsigned int x; - - if (!ip) - return; - - fs_warn(sdp, "ip = %llu %llu\n", - ip->i_num.no_formal_ino, ip->i_num.no_addr); - fs_warn(sdp, "ip->i_count = %d, ip->i_vnode = %s\n", - atomic_read(&ip->i_count), - (ip->i_vnode) ? "!NULL" : "NULL"); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) - fs_warn(sdp, "ip->i_cache[%u] = %s\n", - x, (ip->i_cache[x]) ? "!NULL" : "NULL"); - } -} - -/** - * gfs2_aspace_releasepage - free the metadata associated with a page - * @page: the page that's being released - * @gfp_mask: passed from Linux VFS, ignored by us - * - * Call try_to_free_buffers() if the buffers in this page can be - * released. - * - * Returns: 0 - */ - -static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) +static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wbc) { - struct inode *aspace = page->mapping->host; - struct gfs2_sbd *sdp = get_v2sdp(aspace->i_sb); + int err; struct buffer_head *bh, *head; - struct gfs2_bufdata *bd; - unsigned long t; + int nr_underway = 0; + int write_op = (1 << BIO_RW_META) | ((wbc->sync_mode == WB_SYNC_ALL ? + WRITE_SYNC_PLUG : WRITE)); - if (!page_has_buffers(page)) - goto out; + BUG_ON(!PageLocked(page)); + BUG_ON(!page_has_buffers(page)); - head = bh = page_buffers(page); - do { - t = jiffies; + head = page_buffers(page); + bh = head; - while (atomic_read(&bh->b_count)) { - if (atomic_read(&aspace->i_writecount)) { - if (time_after_eq(jiffies, t + - gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { - stuck_releasepage(bh); - t = jiffies; - } - - yield(); - continue; - } - - return 0; + do { + if (!buffer_mapped(bh)) + continue; + /* + * If it's a fully non-blocking write attempt and we cannot + * lock the buffer then redirty the page. Note that this can + * potentially cause a busy-wait loop from pdflush and kswapd + * activity, but those code paths have their own higher-level + * throttling. + */ + if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { + lock_buffer(bh); + } else if (!trylock_buffer(bh)) { + redirty_page_for_writepage(wbc, page); + continue; } - - gfs2_assert_warn(sdp, !buffer_pinned(bh)); - - bd = get_v2bd(bh); - if (bd) { - gfs2_assert_warn(sdp, bd->bd_bh == bh); - gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); - gfs2_assert_warn(sdp, !bd->bd_ail); - kmem_cache_free(gfs2_bufdata_cachep, bd); - atomic_dec(&sdp->sd_bufdata_count); - set_v2bd(bh, NULL); + if (test_clear_buffer_dirty(bh)) { + mark_buffer_async_write(bh); + } else { + unlock_buffer(bh); } + } while ((bh = bh->b_this_page) != head); - bh = bh->b_this_page; - } - while (bh != head); - - out: - return try_to_free_buffers(page); -} - -static struct address_space_operations aspace_aops = { - .writepage = gfs2_aspace_writepage, - .releasepage = gfs2_aspace_releasepage, -}; - -/** - * gfs2_aspace_get - Create and initialize a struct inode structure - * @sdp: the filesystem the aspace is in - * - * Right now a struct inode is just a struct inode. Maybe Linux - * will supply a more lightweight address space construct (that works) - * in the future. - * - * Make sure pages/buffers in this aspace aren't in high memory. - * - * Returns: the aspace - */ - -struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) -{ - struct inode *aspace; - - aspace = new_inode(sdp->sd_vfs); - if (aspace) { - mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); - aspace->i_mapping->a_ops = &aspace_aops; - aspace->i_size = ~0ULL; - set_v2ip(aspace, NULL); - insert_inode_hash(aspace); - } - - return aspace; -} - -void gfs2_aspace_put(struct inode *aspace) -{ - remove_inode_hash(aspace); - iput(aspace); -} - -/** - * gfs2_ail1_start_one - Start I/O on a part of the AIL - * @sdp: the filesystem - * @tr: the part of the AIL - * - */ - -void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) -{ - struct gfs2_bufdata *bd, *s; - struct buffer_head *bh; - int retry; + /* + * The page and its buffers are protected by PageWriteback(), so we can + * drop the bh refcounts early. + */ + BUG_ON(PageWriteback(page)); + set_page_writeback(page); do { - retry = 0; - - list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, - bd_ail_st_list) { - bh = bd->bd_bh; - - gfs2_assert(sdp, bd->bd_ail == ai); - - if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - list_move(&bd->bd_ail_st_list, - &ai->ai_ail2_list); - continue; - } - - if (!buffer_dirty(bh)) - continue; - - list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); - - gfs2_log_unlock(sdp); - wait_on_buffer(bh); - ll_rw_block(WRITE, 1, &bh); - gfs2_log_lock(sdp); - - retry = 1; - break; - } - } while (retry); -} - -/** - * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced - * @sdp: the filesystem - * @ai: the AIL entry - * - */ - -int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) -{ - struct gfs2_bufdata *bd, *s; - struct buffer_head *bh; - - list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, - bd_ail_st_list) { - bh = bd->bd_bh; - - gfs2_assert(sdp, bd->bd_ail == ai); - - if (buffer_busy(bh)) { - if (flags & DIO_ALL) - continue; - else - break; + struct buffer_head *next = bh->b_this_page; + if (buffer_async_write(bh)) { + submit_bh(write_op, bh); + nr_underway++; } + bh = next; + } while (bh != head); + unlock_page(page); - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - } - - return list_empty(&ai->ai_ail1_list); -} - -/** - * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced - * @sdp: the filesystem - * @ai: the AIL entry - * - */ - -void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) -{ - struct list_head *head = &ai->ai_ail2_list; - struct gfs2_bufdata *bd; - - while (!list_empty(head)) { - bd = list_entry(head->prev, struct gfs2_bufdata, - bd_ail_st_list); - gfs2_assert(sdp, bd->bd_ail == ai); - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - brelse(bd->bd_bh); - } -} - -/** - * ail_empty_gl - remove all buffers for a given lock from the AIL - * @gl: the glock - * - * None of the buffers should be dirty, locked, or pinned. - */ - -void gfs2_ail_empty_gl(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - unsigned int blocks; - struct list_head *head = &gl->gl_ail_list; - struct gfs2_bufdata *bd; - struct buffer_head *bh; - uint64_t blkno; - int error; - - blocks = atomic_read(&gl->gl_ail_count); - if (!blocks) - return; - - error = gfs2_trans_begin(sdp, 0, blocks); - if (gfs2_assert_withdraw(sdp, !error)) - return; - - gfs2_log_lock(sdp); - while (!list_empty(head)) { - bd = list_entry(head->next, struct gfs2_bufdata, - bd_ail_gl_list); - bh = bd->bd_bh; - blkno = bh->b_blocknr; - gfs2_assert_withdraw(sdp, !buffer_busy(bh)); - - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&gl->gl_ail_count); - brelse(bh); - gfs2_log_unlock(sdp); - - gfs2_trans_add_revoke(sdp, blkno); - - gfs2_log_lock(sdp); - } - gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); - gfs2_log_unlock(sdp); + err = 0; + if (nr_underway == 0) + end_page_writeback(page); - gfs2_trans_end(sdp); - gfs2_log_flush(sdp); + return err; } -/** - * gfs2_meta_inval - Invalidate all buffers associated with a glock - * @gl: the glock - * - */ - -void gfs2_meta_inval(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - struct inode *aspace = gl->gl_aspace; - struct address_space *mapping = gl->gl_aspace->i_mapping; - - gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); - - atomic_inc(&aspace->i_writecount); - truncate_inode_pages(mapping, 0); - atomic_dec(&aspace->i_writecount); - - gfs2_assert_withdraw(sdp, !mapping->nrpages); -} +const struct address_space_operations gfs2_meta_aops = { + .writepage = gfs2_aspace_writepage, + .releasepage = gfs2_releasepage, + .sync_page = block_sync_page, +}; /** * 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; + struct address_space *mapping = gfs2_glock2aspace(gl); + 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); } /** - * getbuf - Get a buffer with a given address space - * @sdp: the filesystem - * @aspace: the address space + * gfs2_getbuf - Get a buffer with a given address space + * @gl: the glock * @blkno: the block number (filesystem scope) * @create: 1 if the buffer should be created * * Returns: the buffer */ -static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace, - uint64_t blkno, int create) +struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create) { + struct address_space *mapping = gfs2_glock2aspace(gl); + struct gfs2_sbd *sdp = gl->gl_sbd; struct page *page; struct buffer_head *bh; unsigned int shift; @@ -420,13 +142,13 @@ static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace, if (create) { for (;;) { - page = grab_cache_page(aspace->i_mapping, index); + page = grab_cache_page(mapping, index); if (page) break; yield(); } } else { - page = find_lock_page(aspace->i_mapping, index); + page = find_lock_page(mapping, index); if (!page) return NULL; } @@ -469,10 +191,10 @@ static void meta_prep_new(struct buffer_head *bh) * Returns: The buffer */ -struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno) +struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) { struct buffer_head *bh; - bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); + bh = gfs2_getbuf(gl, blkno, CREATE); meta_prep_new(bh); return bh; } @@ -481,57 +203,69 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t 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 */ -int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, int flags, +int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp) { - int error; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct buffer_head *bh; - *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); - error = gfs2_meta_reread(gl->gl_sbd, *bhp, flags); - if (error) - brelse(*bhp); + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; - return error; + *bhp = bh = gfs2_getbuf(gl, blkno, CREATE); + + lock_buffer(bh); + if (buffer_uptodate(bh)) { + unlock_buffer(bh); + return 0; + } + bh->b_end_io = end_buffer_read_sync; + get_bh(bh); + submit_bh(READ_SYNC | (1 << BIO_RW_META), bh); + if (!(flags & DIO_WAIT)) + return 0; + + wait_on_buffer(bh); + if (unlikely(!buffer_uptodate(bh))) { + struct gfs2_trans *tr = current->journal_info; + if (tr && tr->tr_touched) + gfs2_io_error_bh(sdp, bh); + brelse(bh); + return -EIO; + } + + 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_FORCE) - clear_buffer_uptodate(bh); - - 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 = get_transaction; - 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; } @@ -543,22 +277,21 @@ int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) * @meta: Flag to indicate whether its metadata or not */ -void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta) +void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, + int meta) { struct gfs2_bufdata *bd; - lock_page(bh->b_page); + if (meta) + lock_page(bh->b_page); - if (get_v2bd(bh)) { - unlock_page(bh->b_page); + if (bh->b_private) { + if (meta) + unlock_page(bh->b_page); return; } - bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_KERNEL | __GFP_NOFAIL), - atomic_inc(&gl->gl_sbd->sd_bufdata_count); - - memset(bd, 0, sizeof(struct gfs2_bufdata)); - + bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL); bd->bd_bh = bh; bd->bd_gl = gl; @@ -567,80 +300,43 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta lops_init_le(&bd->bd_le, &gfs2_buf_lops); else lops_init_le(&bd->bd_le, &gfs2_databuf_lops); + bh->b_private = bd; - set_v2bd(bh, bd); - - unlock_page(bh->b_page); -} - -/** - * gfs2_pin - Pin a buffer in memory - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to be pinned - * - */ - -void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) -{ - struct gfs2_bufdata *bd = get_v2bd(bh); - - gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); - - if (test_set_buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - wait_on_buffer(bh); - - /* If this buffer is in the AIL and it has already been written - to in-place disk block, remove it from the AIL. */ - - gfs2_log_lock(sdp); - if (bd->bd_ail && !buffer_in_io(bh)) - list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); - gfs2_log_unlock(sdp); - - clear_buffer_dirty(bh); - wait_on_buffer(bh); - - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - - get_bh(bh); + if (meta) + unlock_page(bh->b_page); } -/** - * gfs2_unpin - Unpin a buffer - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to unpin - * @ai: - * - */ - -void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, - struct gfs2_ail *ai) +void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta) { - struct gfs2_bufdata *bd = get_v2bd(bh); - - gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); - - if (!buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - mark_buffer_dirty(bh); - clear_buffer_pinned(bh); - - gfs2_log_lock(sdp); - if (bd->bd_ail) { - list_del(&bd->bd_ail_st_list); + struct address_space *mapping = bh->b_page->mapping; + struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping); + struct gfs2_bufdata *bd = bh->b_private; + + if (test_clear_buffer_pinned(bh)) { + list_del_init(&bd->bd_le.le_list); + if (meta) { + gfs2_assert_warn(sdp, sdp->sd_log_num_buf); + sdp->sd_log_num_buf--; + tr->tr_num_buf_rm++; + } else { + gfs2_assert_warn(sdp, sdp->sd_log_num_databuf); + sdp->sd_log_num_databuf--; + tr->tr_num_databuf_rm++; + } + tr->tr_touched = 1; brelse(bh); - } else { - struct gfs2_glock *gl = bd->bd_gl; - list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); - atomic_inc(&gl->gl_ail_count); } - bd->bd_ail = ai; - list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); - gfs2_log_unlock(sdp); + if (bd) { + if (bd->bd_ail) { + gfs2_remove_from_ail(bd); + bh->b_private = NULL; + bd->bd_bh = NULL; + bd->bd_blkno = bh->b_blocknr; + gfs2_trans_add_revoke(sdp, bd); + } + } + clear_buffer_dirty(bh); + clear_buffer_uptodate(bh); } /** @@ -651,46 +347,19 @@ void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, * */ -void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) +void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) { - struct gfs2_sbd *sdp = ip->i_sbd; - struct inode *aspace = ip->i_gl->gl_aspace; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *bh; while (blen) { - bh = getbuf(sdp, aspace, bstart, NO_CREATE); + bh = gfs2_getbuf(ip->i_gl, bstart, NO_CREATE); if (bh) { - struct gfs2_bufdata *bd = get_v2bd(bh); - - if (test_clear_buffer_pinned(bh)) { - gfs2_log_lock(sdp); - list_del_init(&bd->bd_le.le_list); - gfs2_assert_warn(sdp, sdp->sd_log_num_buf); - sdp->sd_log_num_buf--; - gfs2_log_unlock(sdp); - get_transaction->tr_num_buf_rm++; - brelse(bh); - } - if (bd) { - gfs2_log_lock(sdp); - if (bd->bd_ail) { - uint64_t blkno = bh->b_blocknr; - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - brelse(bh); - gfs2_log_unlock(sdp); - gfs2_trans_add_revoke(sdp, blkno); - } else - gfs2_log_unlock(sdp); - } - lock_buffer(bh); - clear_buffer_dirty(bh); - clear_buffer_uptodate(bh); + gfs2_log_lock(sdp); + gfs2_remove_from_journal(bh, current->journal_info, 1); + gfs2_log_unlock(sdp); unlock_buffer(bh); - brelse(bh); } @@ -700,32 +369,6 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) } /** - * gfs2_meta_cache_flush - get rid of any references on buffers for this inode - * @ip: The GFS2 inode - * - * This releases buffers that are in the most-recently-used array of - * blocks used for indirect block addressing for this inode. - */ - -void gfs2_meta_cache_flush(struct gfs2_inode *ip) -{ - struct buffer_head **bh_slot; - unsigned int x; - - spin_lock(&ip->i_spin); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { - bh_slot = &ip->i_cache[x]; - if (!*bh_slot) - break; - brelse(*bh_slot); - *bh_slot = NULL; - } - - spin_unlock(&ip->i_spin); -} - -/** * gfs2_meta_indirect_buffer - Get a metadata buffer * @ip: The GFS2 inode * @height: The level of this buf in the metadata (indir addr) tree (if any) @@ -733,75 +376,33 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) * @new: Non-zero if we may create a new buffer * @bhp: the buffer is returned here * - * Try to use the gfs2_inode's MRU metadata tree cache. - * * Returns: errno */ -int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, +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; - - spin_lock(&ip->i_spin); - bh = *bh_slot; - if (bh) { - if (bh->b_blocknr == num) - get_bh(bh); - else - bh = NULL; - } - spin_unlock(&ip->i_spin); - - if (bh) { - if (new) - meta_prep_new(bh); - else { - error = gfs2_meta_reread(ip->i_sbd, 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; - } - - spin_lock(&ip->i_spin); - if (*bh_slot != bh) { - brelse(*bh_slot); - *bh_slot = bh; - get_bh(bh); - } - spin_unlock(&ip->i_spin); - } + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct gfs2_glock *gl = ip->i_gl; + struct buffer_head *bh; + int ret = 0; if (new) { - if (gfs2_assert_warn(ip->i_sbd, height)) { - brelse(bh); - return -EIO; - } + BUG_ON(height == 0); + bh = gfs2_meta_new(gl, num); 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 if (gfs2_metatype_check(ip->i_sbd, bh, - (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { - brelse(bh); - return -EIO; + } else { + u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; + ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh); + if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) { + brelse(bh); + ret = -EIO; + } } - *bhp = bh; - - return 0; + return ret; } /** @@ -810,70 +411,47 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t 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, uint64_t dblock, uint32_t 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; - uint32_t max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; - int error; + u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> + sdp->sd_sb.sb_bsize_shift; - if (!extlen || !max_ra) - return; + BUG_ON(!extlen); + + if (max_ra < 1) + max_ra = 1; if (extlen > max_ra) extlen = max_ra; - first_bh = getbuf(sdp, aspace, dblock, CREATE); + first_bh = gfs2_getbuf(gl, dblock, CREATE); 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_SYNC | (1 << BIO_RW_META), 1, &first_bh); dblock++; 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); + bh = gfs2_getbuf(gl, dblock, CREATE); + 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; } - out: - brelse(first_bh); -} - -/** - * gfs2_meta_syncfs - sync all the buffers in a filesystem - * @sdp: the filesystem - * - */ - -void gfs2_meta_syncfs(struct gfs2_sbd *sdp) -{ - gfs2_log_flush(sdp); - for (;;) { - gfs2_ail1_start(sdp, DIO_ALL); - if (gfs2_ail1_empty(sdp, DIO_ALL)) - break; - msleep(100); - } + wait_on_buffer(first_bh); +out: + return first_bh; }