Merge branch 'for-linus' of git://neil.brown.name/md
[pandora-kernel.git] / fs / gfs2 / glops.c
index da21eca..78418b4 100644 (file)
 #include "trans.h"
 #include "dir.h"
 
+static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
+{
+       fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
+              bh, (unsigned long long)bh->b_blocknr, bh->b_state,
+              bh->b_page->mapping, bh->b_page->flags);
+       fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
+              gl->gl_name.ln_type, gl->gl_name.ln_number,
+              gfs2_glock2aspace(gl));
+       gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
+}
+
 /**
  * __gfs2_ail_flush - remove all buffers for a given lock from the AIL
  * @gl: the glock
+ * @fsync: set when called from fsync (not all buffers will be clean)
  *
  * None of the buffers should be dirty, locked, or pinned.
  */
 
-static void __gfs2_ail_flush(struct gfs2_glock *gl)
+static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct list_head *head = &gl->gl_ail_list;
-       struct gfs2_bufdata *bd;
+       struct gfs2_bufdata *bd, *tmp;
        struct buffer_head *bh;
+       const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock);
+       sector_t blocknr;
 
+       gfs2_log_lock(sdp);
        spin_lock(&sdp->sd_ail_lock);
-       while (!list_empty(head)) {
-               bd = list_entry(head->next, struct gfs2_bufdata,
-                               bd_ail_gl_list);
+       list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
                bh = bd->bd_bh;
-               gfs2_remove_from_ail(bd);
-               bd->bd_bh = NULL;
+               if (bh->b_state & b_state) {
+                       if (fsync)
+                               continue;
+                       gfs2_ail_error(gl, bh);
+               }
+               blocknr = bh->b_blocknr;
                bh->b_private = NULL;
-               spin_unlock(&sdp->sd_ail_lock);
+               gfs2_remove_from_ail(bd); /* drops ref on bh */
 
-               bd->bd_blkno = bh->b_blocknr;
-               gfs2_log_lock(sdp);
-               gfs2_assert_withdraw(sdp, !buffer_busy(bh));
-               gfs2_trans_add_revoke(sdp, bd);
-               gfs2_log_unlock(sdp);
+               bd->bd_bh = NULL;
+               bd->bd_blkno = blocknr;
 
-               spin_lock(&sdp->sd_ail_lock);
+               gfs2_trans_add_revoke(sdp, bd);
        }
-       gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+       BUG_ON(!fsync && atomic_read(&gl->gl_ail_count));
        spin_unlock(&sdp->sd_ail_lock);
+       gfs2_log_unlock(sdp);
 }
 
 
@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
        BUG_ON(current->journal_info);
        current->journal_info = &tr;
 
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, 0);
 
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
 }
 
-void gfs2_ail_flush(struct gfs2_glock *gl)
+void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        unsigned int revokes = atomic_read(&gl->gl_ail_count);
@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
        ret = gfs2_trans_begin(sdp, 0, revokes);
        if (ret)
                return;
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, fsync);
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
 }
@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
 static void rgrp_go_sync(struct gfs2_glock *gl)
 {
        struct address_space *metamapping = gfs2_glock2aspace(gl);
+       struct gfs2_rgrpd *rgd;
        int error;
 
        if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
        error = filemap_fdatawait(metamapping);
         mapping_set_error(metamapping, error);
        gfs2_ail_empty_gl(gl);
+
+       spin_lock(&gl->gl_spin);
+       rgd = gl->gl_object;
+       if (rgd)
+               gfs2_free_clones(rgd);
+       spin_unlock(&gl->gl_spin);
 }
 
 /**
@@ -429,33 +451,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
        return 0;
 }
 
-/**
- * rgrp_go_lock - operation done after an rgrp lock is locked by
- *    a first holder on this node.
- * @gl: the glock
- * @flags:
- *
- * Returns: errno
- */
-
-static int rgrp_go_lock(struct gfs2_holder *gh)
-{
-       return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
-}
-
-/**
- * rgrp_go_unlock - operation done before an rgrp lock is unlocked by
- *    a last holder on this node.
- * @gl: the glock
- * @flags:
- *
- */
-
-static void rgrp_go_unlock(struct gfs2_holder *gh)
-{
-       gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
-}
-
 /**
  * trans_go_sync - promote/demote the transaction glock
  * @gl: the glock
@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
        .go_xmote_th = rgrp_go_sync,
        .go_inval = rgrp_go_inval,
-       .go_lock = rgrp_go_lock,
-       .go_unlock = rgrp_go_unlock,
+       .go_lock = gfs2_rgrp_go_lock,
+       .go_unlock = gfs2_rgrp_go_unlock,
        .go_dump = gfs2_rgrp_dump,
        .go_type = LM_TYPE_RGRP,
        .go_flags = GLOF_ASPACE,