2002-10-31 16:00:34

by Nikita Danilov

[permalink] [raw]
Subject: [PATCH]: 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.
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;
};