Skip to contentSkip to conversation

: reiser4 [6/8] share ->journal_info

PATCH New Nikita Danilov 1 participant 1 message Oct 31, 2002 Scheduler

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 : reiser4 [6/8] share ->journal_info

Hello, Linus,

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.

fs/jbd/transaction.c +25 -7
diff -rup -X dontdiff linus-bk-2.5/fs/jbd/transaction.c linux-2.5-reiser4/fs/jbd/transaction.c
@@ -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) {
include/linux/init_task.h +1 -1
diff -rup -X dontdiff linus-bk-2.5/include/linux/init_task.h linux-2.5-reiser4/include/linux/init_task.h
@@ -95,7 +95,7 @@
 	.blocked	= {{0}},					\
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
-	.journal_info	= NULL,						\
+	.fs_context	= NULL,				\
 }
 
 
include/linux/jbd.h +9 -1
diff -rup -X dontdiff linus-bk-2.5/include/linux/jbd.h linux-2.5-reiser4/include/linux/jbd.h
@@ -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:
include/linux/sched.h +20 -2
diff -rup -X dontdiff linus-bk-2.5/include/linux/sched.h linux-2.5-reiser4/include/linux/sched.h
@@ -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;
 };