Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.4.13-ac8 /fs/jbd-kernel.c

Filename:/fs/jbd-kernel.c
Lines Added:329
Lines Deleted:0
Also changed in: (Previous) 2.4.13-ac7  2.4.13-ac6  2.4.13-ac5  2.4.13-ac4  2.4.13-ac3  2.4.13-ac1 
(Following)

Location
[  2.4.13-ac8
  [  fs
     o  jbd-kernel.c

Patch

diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/jbd-kernel.c linux.ac/fs/jbd-kernel.c
--- linux.vanilla/fs/jbd-kernel.c   Thu Jan  1 01:00:00 1970
+++ linux.ac/fs/jbd-kernel.c   Mon Oct 15 09:12:15 2001
@@ -0,0 +1,329 @@
+/*
+ * fs/jbd-kernel.c
+ *
+ * Support code for the Journalling Block Device layer.
+ * This file contains things which have to be in-kernel when
+ * JBD is a module.
+ *
+ * 15 May 2001   Andrew Morton <andrewm@uow.edu.au>
+ *   Created
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/jbd.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)
+
+/*
+ * jh_splice_lock needs explantion.
+ *
+ * In a number of places we want to do things like:
+ *
+ *   if (buffer_jbd(bh) && bh2jh(bh)->foo)
+ *
+ * This is racy on SMP, because another CPU could remove the journal_head
+ * in the middle of this expression.  We need locking.
+ *
+ * But we can greatly optimise the locking cost by testing BH_JBD
+ * outside the lock.  So, effectively:
+ *
+ *   ret = 0;
+ *   if (buffer_jbd(bh)) {
+ *      spin_lock(&jh_splice_lock);
+ *      if (buffer_jbd(bh)) {    (* Still there? *)
+ *         ret = bh2jh(bh)->foo;
+ *      }
+ *      spin_unlock(&jh_splice_lock);
+ *   }
+ *   return ret;
+ *
+ * Now, that protects us from races where another CPU can remove the
+ * journal_head.  But it doesn't defend us from the situation where another
+ * CPU can *add* a journal_head.  This is a correctness issue.  But it's not
+ * a problem because a) the calling code was *already* racy and b) it often
+ * can't happen at the call site and c) the places where we add journal_heads
+ * tend to be under external locking.
+ */
+spinlock_t jh_splice_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(jh_splice_lock);
+
+#ifdef CONFIG_JBD_DEBUG
+/*
+ * Some sanity testing which is called from mark_buffer_clean(),
+ * and must be present in the main kernel.
+ */
+
+void jbd_preclean_buffer_check(struct buffer_head *bh)
+{
+   if (buffer_jbd(bh)) {
+      struct journal_head *jh = bh2jh(bh);
+
+      transaction_t *transaction = jh->b_transaction;
+      journal_t *journal;
+
+      if (jh->b_jlist == 0 && transaction == NULL)
+         return;
+
+      J_ASSERT_JH(jh, (jh->b_jlist == 0 ||
+             jh->b_jlist == BJ_LogCtl ||
+             jh->b_jlist == BJ_IO ||
+             jh->b_jlist == BJ_Forget ||
+             buffer_jbd_data(bh)));
+      J_ASSERT_JH(jh, transaction != NULL);
+      /* The kernel may be unmapping old data.  We expect it
+       * to be dirty in that case, unless the buffer has
+       * already been forgotten by a transaction. */
+      if (jh->b_jlist != BJ_Forget) {
+         J_ASSERT_JH(jh, buffer_dirty(bh));
+         if (!buffer_jbd_data(bh)) {
+            J_ASSERT_JH(jh,
+                   test_bit(BH_JWrite, 
+                       &jh2bh(jh)->b_state));
+         }
+      }
+      
+      journal = transaction->t_journal;
+      J_ASSERT_JH(jh,
+             transaction == journal->j_running_transaction ||
+             transaction == journal->j_committing_transaction);
+   }
+}
+EXPORT_SYMBOL(jbd_preclean_buffer_check);
+#endif      /* CONFIG_JBD_DEBUG */
+
+/*
+ * Entries in /proc/sys/fs
+ */
+
+int journal_oom_retry = 1;
+EXPORT_SYMBOL(journal_oom_retry);
+#if defined(CONFIG_JBD_DEBUG)
+int journal_enable_debug;
+int journal_no_write[2];
+EXPORT_SYMBOL(journal_enable_debug);
+EXPORT_SYMBOL(journal_no_write);
+#endif
+
+#endif   /* defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) */
+
+/*
+ * Support functions for BUFFER_TRACE()
+ */
+#ifdef CONFIG_BUFFER_DEBUG
+
+static spinlock_t trace_lock = SPIN_LOCK_UNLOCKED;
+
+void buffer_trace(struct buffer_head *dest,
+      struct buffer_head *src, char *info)
+{
+   struct buffer_history_item *bhist_i;
+   unsigned long flags;
+
+   if (dest == 0 || src == 0)
+      return;
+
+   spin_lock_irqsave(&trace_lock, flags);
+
+   /*
+    * Sometimes we don't initialise the ring pointers. (locally declared
+    * temp buffer_heads). Feebly attempt to detect and correct that here.
+    */
+   if ((dest->b_history.b_history_head - dest->b_history.b_history_tail >
+            BUFFER_HISTORY_SIZE)) {
+      dest->b_history.b_history_head = 0;
+      dest->b_history.b_history_tail = 0;
+   }
+   bhist_i = dest->b_history.b +
+      (dest->b_history.b_history_head & (BUFFER_HISTORY_SIZE - 1));
+   bhist_i->info = info;
+   bhist_i->b_state = src->b_state;
+   bhist_i->b_list = src->b_list;
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)
+   bhist_i->b_trans_is_running = 0;
+   bhist_i->b_trans_is_committing = 0;
+   bhist_i->b_blocknr = src->b_blocknr;
+   if (buffer_jbd(src)) {
+      struct journal_head *jh;
+      journal_t *journal;
+      transaction_t *transaction;
+
+      /* Footwork to avoid racing with journal_remove_journal_head */
+      jh = src->b_private;
+      if (jh == 0)
+         goto raced;
+      transaction = jh->b_transaction;
+      if (src->b_private == 0)
+         goto raced;
+      bhist_i->b_jcount = jh->b_jcount;
+      bhist_i->b_jbd = 1;
+      bhist_i->b_jlist = jh->b_jlist;
+      bhist_i->b_frozen_data = jh->b_frozen_data;
+      bhist_i->b_committed_data = jh->b_committed_data;
+      bhist_i->b_transaction = !!jh->b_transaction;
+      bhist_i->b_next_transaction = !!jh->b_next_transaction;
+      bhist_i->b_cp_transaction = !!jh->b_cp_transaction;
+
+      if (transaction) {
+         journal = transaction->t_journal;
+         bhist_i->b_trans_is_running = transaction ==
+               journal->j_running_transaction;
+         bhist_i->b_trans_is_committing = transaction ==
+               journal->j_committing_transaction;
+      }
+   } else {
+raced:
+      bhist_i->b_jcount = 0;
+      bhist_i->b_jbd = 0;
+      bhist_i->b_jlist = 0;
+      bhist_i->b_frozen_data = 0;
+      bhist_i->b_committed_data = 0;
+      bhist_i->b_transaction = 0;
+      bhist_i->b_next_transaction = 0;
+      bhist_i->b_cp_transaction = 0;
+   }
+#endif   /* defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) */
+
+   bhist_i->on_lru = (src->b_prev_free != 0 && src->b_next_free != 0);
+   bhist_i->on_hash = (src->b_pprev != 0);
+   bhist_i->cpu = smp_processor_id();
+   bhist_i->b_count = atomic_read(&src->b_count);
+
+   dest->b_history.b_history_head++;
+   if (dest->b_history.b_history_head - dest->b_history.b_history_tail >
+            BUFFER_HISTORY_SIZE)
+      dest->b_history.b_history_tail =
+         dest->b_history.b_history_head - BUFFER_HISTORY_SIZE;
+
+   spin_unlock_irqrestore(&trace_lock, flags);
+}
+
+static const char *b_list_to_string(unsigned int b_list)
+{
+   switch (b_list) {
+   case BUF_CLEAN:      return "BUF_CLEAN";
+   case BUF_LOCKED:   return "BUF_LOCKED";
+   case BUF_DIRTY:      return "BUF_DIRTY";
+   default:      return "Bad b_list";
+   }
+}
+
+static const char *b_jlist_to_string(unsigned int b_list)
+{
+   switch (b_list) {
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)
+   case BJ_None:      return "BJ_None";
+   case BJ_SyncData:   return "BJ_SyncData";
+   case BJ_AsyncData:   return "BJ_AsyncData";
+   case BJ_Metadata:   return "BJ_Metadata";
+   case BJ_Forget:      return "BJ_Forget";
+   case BJ_IO:      return "BJ_IO";
+   case BJ_Shadow:      return "BJ_Shadow";
+   case BJ_LogCtl:      return "BJ_LogCtl";
+   case BJ_Reserved:   return "BJ_Reserved";
+#endif
+   default:      return "Bad b_jlist";
+   }
+}
+
+static void print_one_hist(struct buffer_history_item *bhist_i)
+{
+   printk(" %s\n", bhist_i->info);
+   printk("     b_state:0x%lx b_list:%s b_jlist:%s on_lru:%d\n",
+         bhist_i->b_state,
+         b_list_to_string(bhist_i->b_list),
+         b_jlist_to_string(bhist_i->b_jlist),
+         bhist_i->on_lru);
+   printk("     cpu:%d on_hash:%d b_count:%d b_blocknr:%lu\n",
+         bhist_i->cpu,
+         bhist_i->on_hash,
+         bhist_i->b_count,
+         bhist_i->b_blocknr);
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)
+   printk("     b_jbd:%u b_frozen_data:%p b_committed_data:%p\n",
+         bhist_i->b_jbd,
+         bhist_i->b_frozen_data,
+         bhist_i->b_committed_data);
+   printk("     b_transaction:%u b_next_transaction:%u "
+         "b_cp_transaction:%u b_trans_is_running:%u\n",
+         bhist_i->b_transaction,
+         bhist_i->b_next_transaction,
+         bhist_i->b_cp_transaction,
+         bhist_i->b_trans_is_running);
+   printk("     b_trans_is_comitting:%u b_jcount:%u ",
+         bhist_i->b_trans_is_committing,
+         bhist_i->b_jcount);
+#endif
+   printk("\n");
+}
+
+void print_buffer_fields(struct buffer_head *bh)
+{
+   printk("b_next:%p, b_blocknr:%lu b_count:%d b_flushtime:%lu\n",
+      bh->b_next, bh->b_blocknr, atomic_read(&bh->b_count),
+         bh->b_flushtime);
+   printk("b_next_free:%p b_prev_free:%p b_this_page:%p b_reqnext:%p\n",
+      bh->b_next_free, bh->b_prev_free, bh->b_this_page,
+         bh->b_reqnext);
+   printk("b_pprev:%p b_data:%p b_page:%p b_inode:%p b_list:%d\n",
+      bh->b_pprev, bh->b_data, bh->b_page, bh->b_inode, bh->b_list);
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)
+   if (buffer_jbd(bh)) {
+      struct journal_head *jh = bh2jh(bh);
+
+      printk("b_jlist:%u b_frozen_data:%p b_committed_data:%p\n",
+         jh->b_jlist, jh->b_frozen_data, jh->b_committed_data);
+      printk(" b_transaction:%p b_next_transaction:%p "
+            "b_cp_transaction:%p\n",
+         jh->b_transaction, jh->b_next_transaction,
+         jh->b_cp_transaction);
+      printk("b_cpnext:%p b_cpprev:%p\n",
+         jh->b_cpnext, jh->b_cpprev);
+   }
+#endif
+}
+
+void print_buffer_trace(struct buffer_head *bh)
+{
+#ifdef CONFIG_X86
+   extern void show_stack(unsigned long * esp);
+#endif
+
+   unsigned long idx, count;
+   unsigned long flags;
+
+   printk("buffer trace for buffer at 0x%p (I am CPU %d)\n",
+         bh, smp_processor_id());
+   BUFFER_TRACE(bh, "");      /* Record state now */
+
+   spin_lock_irqsave(&trace_lock, flags);
+   for (   idx = bh->b_history.b_history_tail, count = 0;
+      idx < bh->b_history.b_history_head &&
+         count < BUFFER_HISTORY_SIZE;
+      idx++, count++)
+      print_one_hist(bh->b_history.b +
+         (idx & (BUFFER_HISTORY_SIZE - 1)));
+
+   print_buffer_fields(bh);
+   spin_unlock_irqrestore(&trace_lock, flags);
+#ifdef CONFIG_X86
+   show_stack(NULL);
+#endif
+   printk("\n");
+}
+
+static struct buffer_head *failed_buffer_head;   /* For access with debuggers */
+
+void buffer_assertion_failure(struct buffer_head *bh)
+{
+   failed_buffer_head = bh;
+   print_buffer_trace(bh);
+}
+EXPORT_SYMBOL(buffer_trace);
+EXPORT_SYMBOL(print_buffer_trace);
+EXPORT_SYMBOL(buffer_assertion_failure);
+EXPORT_SYMBOL(print_buffer_fields);
+#endif   /* CONFIG_BUFFER_DEBUG */
+


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.