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

From: Nikita Danilov (Nikita@Namesys.COM)
Date: Thu Oct 31 2002 - 11:02:57 EST


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.
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/



This archive was generated by hypermail 2b29 : Thu Oct 31 2002 - 22:00:54 EST