this patch changes declaration of ->journal_info in the struct
    task_struct and updates the only user (ext3) correspondingly.
    ->journal_info is supposed to hold some file system data per-thread
    per-file-system-invocation. Problem is that it is possible (through
    VM call backs or page faults, for example) for invocations of file
    system drivers to nest. This patch changes ->journal_info from void*
    to a pointer to the struct fs_activation. struct fs_activation
    contains only one field ->owner: it can be used by file system to
    tell whether it can continue within given "parent" context:
    generally journalling file system cannot be called from within
    different journalling file system, because of deadlocks.
    struct fs_activation will be usually embedded into some file system
    specific object (like transaction handle for ext3, or
    reiser4_context for, well, reiser4) and it is file system
    responsibility to save original value of ->journal_info on entry and
    restore it on exit.
    Also, ->journal_info is renamed to less specific ->fs_context.
    Thanks to Stephen Tweedie for useful comments.
Please apply.
Nikita.
diff -rup -X dontdiff linus-bk-2.5/fs/jbd/transaction.c linux-2.5-reiser4/fs/jbd/transaction.c
--- linus-bk-2.5/fs/jbd/transaction.c	Tue Oct 15 20:56:59 2002
+++ linux-2.5-reiser4/fs/jbd/transaction.c	Mon Oct 21 13:43:51 2002
@@ -101,6 +101,7 @@ static int start_this_handle(journal_t *
 
 	jbd_debug(3, "New handle %p going live.\n", handle);
 
+	handle->h_journal = journal;
 repeat:
 
 	lock_journal(journal);
@@ -223,6 +224,23 @@ static handle_t *new_handle(int nblocks)
 }
 
 /*
+ * push @handle into ->fs_context stack
+ */
+static void push_handle(handle_t *handle)
+{
+	handle->h_parent = current->fs_context;
+	current->fs_context = (struct fs_activation *) handle;
+}
+
+/*
+ * pop top of ->fs_context stack
+ */
+static void pop_handle(handle_t *handle)
+{
+	current->fs_context = (struct fs_activation *) handle->h_parent;
+}
+
+/*
  * Obtain a new handle.  
  *
  * We make sure that the transaction can guarantee at least nblocks of
@@ -243,7 +261,7 @@ handle_t *journal_start(journal_t *journ
 	if (!journal)
 		return ERR_PTR(-EROFS);
 
-	if (handle) {
+	if (handle && handle->h_journal == journal) {
 		J_ASSERT(handle->h_transaction->t_journal == journal);
 		handle->h_ref++;
 		return handle;
@@ -253,12 +271,12 @@ handle_t *journal_start(journal_t *journ
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
 
-	current->journal_info = handle;
+	push_handle(handle);
 
 	err = start_this_handle(journal, handle);
 	if (err < 0) {
+		pop_handle(handle);
 		kfree(handle);
-		current->journal_info = NULL;
 		return ERR_PTR(err);
 	}
 
@@ -336,7 +354,7 @@ handle_t *journal_try_start(journal_t *j
 	if (!journal)
 		return ERR_PTR(-EROFS);
 
-	if (handle) {
+	if (handle && handle->h_journal == journal) {
 		jbd_debug(4, "h_ref %d -> %d\n",
 				handle->h_ref,
 				handle->h_ref + 1);
@@ -356,12 +374,12 @@ handle_t *journal_try_start(journal_t *j
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
 
-	current->journal_info = handle;
+	push_handle(handle);
 
 	err = try_start_this_handle(journal, handle);
 	if (err < 0) {
+		pop_handle(handle);
 		kfree(handle);
-		current->journal_info = NULL;
 		return ERR_PTR(err);
 	}
 
@@ -1441,7 +1459,7 @@ int journal_stop(handle_t *handle)
 		} while (old_handle_count != transaction->t_handle_count);
 	}
 
-	current->journal_info = NULL;
+	pop_handle(handle);
 	transaction->t_outstanding_credits -= handle->h_buffer_credits;
 	transaction->t_updates--;
 	if (!transaction->t_updates) {
diff -rup -X dontdiff linus-bk-2.5/include/linux/init_task.h linux-2.5-reiser4/include/linux/init_task.h
--- linus-bk-2.5/include/linux/init_task.h	Tue Oct 15 20:57:02 2002
+++ linux-2.5-reiser4/include/linux/init_task.h	Mon Oct 21 13:43:57 2002
@@ -95,7 +95,7 @@
 	.blocked	= {{0}},					\
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
-	.journal_info	= NULL,						\
+	.fs_context	= NULL,				\
 }
 
 
diff -rup -X dontdiff linus-bk-2.5/include/linux/jbd.h linux-2.5-reiser4/include/linux/jbd.h
--- linus-bk-2.5/include/linux/jbd.h	Tue Oct 15 20:57:02 2002
+++ linux-2.5-reiser4/include/linux/jbd.h	Mon Oct 21 13:43:58 2002
@@ -274,6 +274,14 @@ struct jbd_revoke_table_s;
 
 struct handle_s 
 {
+	/* Which journal this handle belongs to.  This has to be first
+	 * field, because current->fs_context points here. */
+	journal_t             * h_journal;
+
+	/* Previous file system context. NULL if we are top-most
+	 * call. */
+	struct fs_activation  * h_parent;
+
 	/* Which compound transaction is this update a part of? */
 	transaction_t	      * h_transaction;
 
@@ -637,7 +645,7 @@ static inline void unlock_journal(journa
 
 static inline handle_t *journal_current_handle(void)
 {
-	return current->journal_info;
+	return (handle_t*) current->fs_context;
 }
 
 /* The journaling code user interface:
diff -rup -X dontdiff linus-bk-2.5/include/linux/sched.h linux-2.5-reiser4/include/linux/sched.h
--- linus-bk-2.5/include/linux/sched.h	Sat Oct 19 03:01:12 2002
+++ linux-2.5-reiser4/include/linux/sched.h	Mon Oct 21 13:43:58 2002
@@ -268,6 +268,24 @@ extern struct user_struct root_user;
 typedef struct prio_array prio_array_t;
 struct backing_dev_info;
 
+/*
+ * Some file systems need context associated with current thread during
+ * one system call (transaction handle, for example). This context in
+ * attached to current->fs_context.
+ *
+ * As it is possible for file system calls to nest (through quota of VM
+ * call backs), every file system using current->fs_context should store
+ * original ->fs_context value of entrance and restore in on exit.
+ */
+struct fs_activation {
+	/*
+	 * cookie allowing to distinguish file system instances
+	 * (mounts). Usually this is pointer to the super block, but not
+	 * necessary. This is used to tell reentrance.
+	 */
+	void *owner;
+};
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -387,8 +405,8 @@ struct task_struct {
 /* context-switch lock */
 	spinlock_t switch_lock;
 
-/* journalling filesystem info */
-	void *journal_info;
+/* info about current file system activation */
+	struct fs_activation *fs_context;
 	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
 };
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/