Whamcloud - gitweb
- fix against credits leak in journal_release_buffer()
authoralex <alex>
Tue, 8 Mar 2005 09:01:51 +0000 (09:01 +0000)
committeralex <alex>
Tue, 8 Mar 2005 09:01:51 +0000 (09:01 +0000)
  accepted in mainline (2.6.11-pre)

lustre/kernel_patches/patches/jbd-buffer-release-2.6.7.patch [new file with mode: 0644]
lustre/kernel_patches/series/2.6-vanilla.series

diff --git a/lustre/kernel_patches/patches/jbd-buffer-release-2.6.7.patch b/lustre/kernel_patches/patches/jbd-buffer-release-2.6.7.patch
new file mode 100644 (file)
index 0000000..b4708d8
--- /dev/null
@@ -0,0 +1,390 @@
+fix against credits leak in journal_release_buffer()
+
+The idea is to charge a buffer at a time of modification (journal_dirty_metadata()),
+not at a time of access (journal_get_*_access()). Each buffer has flag first call
+journal_dirty_metadata() sets on the buffer.
+
+Signed-off-by: Alex Tomas <alex@clusterfs.com>
+
+Index: linux-2.6.7/include/linux/journal-head.h
+===================================================================
+--- linux-2.6.7.orig/include/linux/journal-head.h      2003-06-24 18:05:26.000000000 +0400
++++ linux-2.6.7/include/linux/journal-head.h   2005-03-08 11:55:04.000000000 +0300
+@@ -32,6 +32,13 @@
+       unsigned b_jlist;
+       /*
++       * This flag signals the buffer has been modified by
++       * the currently running transaction
++       * [jbd_lock_bh_state()]
++       */
++      unsigned b_modified;
++
++      /*
+        * Copy of the buffer data frozen for writing to the log.
+        * [jbd_lock_bh_state()]
+        */
+Index: linux-2.6.7/include/linux/ext3_jbd.h
+===================================================================
+--- linux-2.6.7.orig/include/linux/ext3_jbd.h  2004-08-26 17:12:16.000000000 +0400
++++ linux-2.6.7/include/linux/ext3_jbd.h       2005-03-08 11:55:04.000000000 +0300
+@@ -113,9 +113,9 @@
+ static inline int
+ __ext3_journal_get_undo_access(const char *where, handle_t *handle,
+-                              struct buffer_head *bh, int *credits)
++                              struct buffer_head *bh)
+ {
+-      int err = journal_get_undo_access(handle, bh, credits);
++      int err = journal_get_undo_access(handle, bh);
+       if (err)
+               ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+       return err;
+@@ -123,19 +123,18 @@
+ static inline int
+ __ext3_journal_get_write_access(const char *where, handle_t *handle,
+-                              struct buffer_head *bh, int *credits)
++                              struct buffer_head *bh)
+ {
+-      int err = journal_get_write_access(handle, bh, credits);
++      int err = journal_get_write_access(handle, bh);
+       if (err)
+               ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+       return err;
+ }
+ static inline void
+-ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh,
+-                              int credits)
++ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
+ {
+-      journal_release_buffer(handle, bh, credits);
++      journal_release_buffer(handle, bh);
+ }
+ static inline void
+@@ -175,12 +174,10 @@
+ }
+-#define ext3_journal_get_undo_access(handle, bh, credits) \
+-      __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits))
++#define ext3_journal_get_undo_access(handle, bh) \
++      __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
+ #define ext3_journal_get_write_access(handle, bh) \
+-      __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL)
+-#define ext3_journal_get_write_access_credits(handle, bh, credits) \
+-      __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits))
++      __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
+ #define ext3_journal_revoke(handle, blocknr, bh) \
+       __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
+ #define ext3_journal_get_create_access(handle, bh) \
+Index: linux-2.6.7/include/linux/jbd.h
+===================================================================
+--- linux-2.6.7.orig/include/linux/jbd.h       2004-08-26 17:12:16.000000000 +0400
++++ linux-2.6.7/include/linux/jbd.h    2005-03-08 11:55:04.000000000 +0300
+@@ -903,15 +903,12 @@
+ extern handle_t *journal_start(journal_t *, int nblocks);
+ extern int     journal_restart (handle_t *, int nblocks);
+ extern int     journal_extend (handle_t *, int nblocks);
+-extern int     journal_get_write_access(handle_t *, struct buffer_head *,
+-                                              int *credits);
++extern int     journal_get_write_access(handle_t *, struct buffer_head *);
+ extern int     journal_get_create_access (handle_t *, struct buffer_head *);
+-extern int     journal_get_undo_access(handle_t *, struct buffer_head *,
+-                                              int *credits);
++extern int     journal_get_undo_access(handle_t *, struct buffer_head *);
+ extern int     journal_dirty_data (handle_t *, struct buffer_head *);
+ extern int     journal_dirty_metadata (handle_t *, struct buffer_head *);
+-extern void    journal_release_buffer (handle_t *, struct buffer_head *,
+-                                              int credits);
++extern void    journal_release_buffer (handle_t *, struct buffer_head *);
+ extern void    journal_forget (handle_t *, struct buffer_head *);
+ extern void    journal_sync_buffer (struct buffer_head *);
+ extern int     journal_invalidatepage(journal_t *,
+Index: linux-2.6.7/fs/jbd/transaction.c
+===================================================================
+--- linux-2.6.7.orig/fs/jbd/transaction.c      2004-08-26 17:12:40.000000000 +0400
++++ linux-2.6.7/fs/jbd/transaction.c   2005-03-08 11:55:04.000000000 +0300
+@@ -524,7 +524,7 @@
+  */
+ static int
+ do_get_write_access(handle_t *handle, struct journal_head *jh,
+-                      int force_copy, int *credits) 
++                      int force_copy) 
+ {
+       struct buffer_head *bh;
+       transaction_t *transaction;
+@@ -606,11 +606,6 @@
+               JBUFFER_TRACE(jh, "has frozen data");
+               J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+               jh->b_next_transaction = transaction;
+-
+-              J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
+-              handle->h_buffer_credits--;
+-              if (credits)
+-                      (*credits)++;
+               goto done;
+       }
+@@ -689,10 +684,6 @@
+               jh->b_next_transaction = transaction;
+       }
+-      J_ASSERT(handle->h_buffer_credits > 0);
+-      handle->h_buffer_credits--;
+-      if (credits)
+-              (*credits)++;
+       /*
+        * Finally, if the buffer is not journaled right now, we need to make
+@@ -750,8 +741,7 @@
+  * because we're write()ing a buffer which is also part of a shared mapping.
+  */
+-int journal_get_write_access(handle_t *handle,
+-                      struct buffer_head *bh, int *credits)
++int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
+ {
+       struct journal_head *jh = journal_add_journal_head(bh);
+       int rc;
+@@ -759,7 +749,7 @@
+       /* We do not want to get caught playing with fields which the
+        * log thread also manipulates.  Make sure that the buffer
+        * completes any outstanding IO before proceeding. */
+-      rc = do_get_write_access(handle, jh, 0, credits);
++      rc = do_get_write_access(handle, jh, 0);
+       journal_put_journal_head(jh);
+       return rc;
+ }
+@@ -815,9 +805,6 @@
+       J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+       J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
+-      J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
+-      handle->h_buffer_credits--;
+-
+       if (jh->b_transaction == NULL) {
+               jh->b_transaction = transaction;
+               JBUFFER_TRACE(jh, "file as BJ_Reserved");
+@@ -870,8 +857,7 @@
+  *
+  * Returns error number or 0 on success.
+  */
+-int journal_get_undo_access(handle_t *handle, struct buffer_head *bh,
+-                              int *credits)
++int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
+ {
+       int err;
+       struct journal_head *jh = journal_add_journal_head(bh);
+@@ -884,7 +870,7 @@
+        * make sure that obtaining the committed_data is done
+        * atomically wrt. completion of any outstanding commits.
+        */
+-      err = do_get_write_access(handle, jh, 1, credits);
++      err = do_get_write_access(handle, jh, 1);
+       if (err)
+               goto out;
+@@ -1112,6 +1098,17 @@
+       jbd_lock_bh_state(bh);
++      if (jh->b_modified == 0) {
++              /*
++               * This buffer's got modified and becoming part
++               * of the transaction. This needs to be done
++               * once a transaction -bzzz
++               */
++              jh->b_modified = 1;
++              J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
++              handle->h_buffer_credits--;
++      }
++
+       /*
+        * fastpath, to avoid expensive locking.  If this buffer is already
+        * on the running transaction's metadata list there is nothing to do.
+@@ -1162,24 +1159,11 @@
+  * journal_release_buffer: undo a get_write_access without any buffer
+  * updates, if the update decided in the end that it didn't need access.
+  *
+- * The caller passes in the number of credits which should be put back for
+- * this buffer (zero or one).
+- *
+- * We leave the buffer attached to t_reserved_list because even though this
+- * handle doesn't want it, some other concurrent handle may want to journal
+- * this buffer.  If that handle is curently in between get_write_access() and
+- * journal_dirty_metadata() then it expects the buffer to be reserved.  If
+- * we were to rip it off t_reserved_list here, the other handle will explode
+- * when journal_dirty_metadata is presented with a non-reserved buffer.
+- *
+- * If nobody really wants to journal this buffer then it will be thrown
+- * away at the start of commit.
+  */
+ void
+-journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
++journal_release_buffer(handle_t *handle, struct buffer_head *bh)
+ {
+       BUFFER_TRACE(bh, "entry");
+-      handle->h_buffer_credits += credits;
+ }
+ /** 
+@@ -1214,6 +1198,12 @@
+               goto not_jbd;
+       jh = bh2jh(bh);
++      /*
++       * The buffer's going from the transaction, we must drop
++       * all references -bzzz
++       */
++      jh->b_modified = 0;
++
+       if (jh->b_transaction == handle->h_transaction) {
+               J_ASSERT_JH(jh, !jh->b_frozen_data);
+Index: linux-2.6.7/fs/jbd/commit.c
+===================================================================
+--- linux-2.6.7.orig/fs/jbd/commit.c   2004-08-26 17:12:40.000000000 +0400
++++ linux-2.6.7/fs/jbd/commit.c        2005-03-08 11:55:04.000000000 +0300
+@@ -229,6 +229,22 @@
+       jbd_debug (3, "JBD: commit phase 2\n");
+       /*
++       * First, drop modified flag: all accesses to the buffers
++       * will be tracked for a new trasaction only -bzzz
++       */
++      spin_lock(&journal->j_list_lock);
++      if (commit_transaction->t_buffers) {
++              new_jh = jh = commit_transaction->t_buffers->b_tnext;
++              do {
++                      J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
++                                      new_jh->b_modified == 0);
++                      new_jh->b_modified = 0;
++                      new_jh = new_jh->b_tnext;
++              } while (new_jh != jh);
++      }
++      spin_unlock(&journal->j_list_lock);
++
++      /*
+        * Now start flushing things to disk, in the order they appear
+        * on the transaction lists.  Data blocks go first.
+        */
+Index: linux-2.6.7/fs/ext3/balloc.c
+===================================================================
+--- linux-2.6.7.orig/fs/ext3/balloc.c  2004-08-26 17:11:16.000000000 +0400
++++ linux-2.6.7/fs/ext3/balloc.c       2005-03-08 11:55:04.000000000 +0300
+@@ -171,7 +171,7 @@
+        */
+       /* @@@ check errors */
+       BUFFER_TRACE(bitmap_bh, "getting undo access");
+-      err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
++      err = ext3_journal_get_undo_access(handle, bitmap_bh);
+       if (err)
+               goto error_return;
+@@ -411,7 +411,6 @@
+ {
+       int i;
+       int fatal;
+-      int credits = 0;
+       *errp = 0;
+@@ -421,7 +420,7 @@
+        * if the buffer is in BJ_Forget state in the committing transaction.
+        */
+       BUFFER_TRACE(bitmap_bh, "get undo access for new block");
+-      fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
++      fatal = ext3_journal_get_undo_access(handle, bitmap_bh);
+       if (fatal) {
+               *errp = fatal;
+               goto fail;
+@@ -460,7 +459,7 @@
+ fail_access:
+       BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
+-      ext3_journal_release_buffer(handle, bitmap_bh, credits);
++      ext3_journal_release_buffer(handle, bitmap_bh);
+ fail:
+       return -1;
+ }
+Index: linux-2.6.7/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.6.7.orig/fs/ext3/ialloc.c  2004-08-26 17:11:31.000000000 +0400
++++ linux-2.6.7/fs/ext3/ialloc.c       2005-03-08 11:55:04.000000000 +0300
+@@ -475,11 +475,9 @@
+               ino = ext3_find_next_zero_bit((unsigned long *)
+                               bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino);
+               if (ino < EXT3_INODES_PER_GROUP(sb)) {
+-                      int credits = 0;
+                       BUFFER_TRACE(bitmap_bh, "get_write_access");
+-                      err = ext3_journal_get_write_access_credits(handle,
+-                                                      bitmap_bh, &credits);
++                      err = ext3_journal_get_write_access(handle, bitmap_bh);
+                       if (err)
+                               goto fail;
+@@ -495,7 +493,7 @@
+                               goto got;
+                       }
+                       /* we lost it */
+-                      journal_release_buffer(handle, bitmap_bh, credits);
++                      journal_release_buffer(handle, bitmap_bh);
+                       if (++ino < EXT3_INODES_PER_GROUP(sb))
+                               goto repeat_in_this_group;
+Index: linux-2.6.7/fs/ext3/xattr.c
+===================================================================
+--- linux-2.6.7.orig/fs/ext3/xattr.c   2004-08-26 17:10:37.000000000 +0400
++++ linux-2.6.7/fs/ext3/xattr.c        2005-03-08 11:55:04.000000000 +0300
+@@ -607,8 +607,7 @@
+                       goto skip_get_write_access;
+               /* ext3_journal_get_write_access() requires an unlocked bh,
+                  which complicates things here. */
+-              error = ext3_journal_get_write_access_credits(handle, bh,
+-                                                            &credits);
++              error = ext3_journal_get_write_access(handle, bh);
+               if (error)
+                       goto cleanup;
+               lock_buffer(bh);
+@@ -620,7 +619,7 @@
+                       int offset;
+                       unlock_buffer(bh);
+-                      journal_release_buffer(handle, bh, credits);
++                      journal_release_buffer(handle, bh);
+               skip_get_write_access:
+                       ea_bdebug(bh, "cloning");
+                       header = kmalloc(bh->b_size, GFP_KERNEL);
+@@ -764,8 +763,7 @@
+                               error = -EDQUOT;
+                               if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+                                       unlock_buffer(new_bh);
+-                                      journal_release_buffer(handle, new_bh,
+-                                                             credits);
++                                      journal_release_buffer(handle, new_bh);
+                                       goto cleanup;
+                               }
+                               HDR(new_bh)->h_refcount = cpu_to_le32(1 +
+@@ -1057,8 +1055,7 @@
+                       ext3_error(inode->i_sb, "ext3_xattr_cache_find",
+                               "inode %ld: block %ld read error",
+                               inode->i_ino, (unsigned long) ce->e_block);
+-              } else if (ext3_journal_get_write_access_credits(
+-                              handle, bh, credits) == 0) {
++              } else if (ext3_journal_get_write_access(handle, bh) == 0) {
+                       /* ext3_journal_get_write_access() requires an unlocked
+                        * bh, which complicates things here. */
+                       lock_buffer(bh);
+@@ -1074,7 +1071,7 @@
+                               return bh;
+                       }
+                       unlock_buffer(bh);
+-                      journal_release_buffer(handle, bh, *credits);
++                      journal_release_buffer(handle, bh);
+                       *credits = 0;
+                       brelse(bh);
+               }
index 61b9bdb..8e88ec9 100644 (file)
@@ -17,4 +17,4 @@ dcache-mds-num-2.6.7.patch
 dynamic-locks-2.6.7.patch
 vfs-pdirops-2.6.7.patch
 dcache-fid-2.6.7.patch
-jbd-static-wbuf-2.6.7
+jbd-buffer-release-2.6.7.patch