#include <linux/mm.h>
#include <linux/suspend.h>
#include <linux/pagemap.h>
-#include <asm/uaccess.h>
+#include <linux/kthread.h>
#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
EXPORT_SYMBOL(journal_start);
EXPORT_SYMBOL(journal_restart);
EXPORT_SYMBOL(journal_extend);
#endif
EXPORT_SYMBOL(journal_flush);
EXPORT_SYMBOL(journal_revoke);
-EXPORT_SYMBOL(journal_callback_set);
EXPORT_SYMBOL(journal_init_dev);
EXPORT_SYMBOL(journal_init_inode);
EXPORT_SYMBOL(journal_create);
EXPORT_SYMBOL(journal_load);
EXPORT_SYMBOL(journal_destroy);
-EXPORT_SYMBOL(journal_recover);
EXPORT_SYMBOL(journal_update_superblock);
EXPORT_SYMBOL(journal_abort);
EXPORT_SYMBOL(journal_errno);
EXPORT_SYMBOL(journal_blocks_per_page);
EXPORT_SYMBOL(journal_invalidatepage);
EXPORT_SYMBOL(journal_try_to_free_buffers);
-EXPORT_SYMBOL(journal_bmap);
EXPORT_SYMBOL(journal_force_commit);
static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+static void __journal_abort_soft (journal_t *journal, int errno);
/*
* Helper function used to manage commit timeouts
wake_up_process(p);
}
-/* Static check for data structure consistency. There's no code
- * invoked --- we'll just get a linker failure if things aren't right.
- */
-void __journal_internal_check(void)
-{
- extern void journal_bad_superblock_size(void);
- if (sizeof(struct journal_superblock_s) != 1024)
- journal_bad_superblock_size();
-}
-
/*
* kjournald: The main thread function used to manage a logging device
* journal.
* known as checkpointing, and this thread is responsible for that job.
*/
-journal_t *current_journal; // AKPM: debug
-
-int kjournald(void *arg)
+static int kjournald(void *arg)
{
- journal_t *journal = (journal_t *) arg;
+ journal_t *journal = arg;
transaction_t *transaction;
- struct timer_list timer;
-
- current_journal = journal;
-
- daemonize("kjournald");
- /* Set up an interval timer which can be used to trigger a
- commit wakeup after the commit interval expires */
- init_timer(&timer);
- timer.data = (unsigned long) current;
- timer.function = commit_timeout;
- journal->j_commit_timer = &timer;
+ /*
+ * Set up an interval timer which can be used to trigger a commit wakeup
+ * after the commit interval expires
+ */
+ setup_timer(&journal->j_commit_timer, commit_timeout,
+ (unsigned long)current);
/* Record that the journal thread is running */
journal->j_task = current;
spin_lock(&journal->j_state_lock);
loop:
+ if (journal->j_flags & JFS_UNMOUNT)
+ goto end_loop;
+
jbd_debug(1, "commit_sequence=%d, commit_request=%d\n",
journal->j_commit_sequence, journal->j_commit_request);
if (journal->j_commit_sequence != journal->j_commit_request) {
jbd_debug(1, "OK, requests differ\n");
spin_unlock(&journal->j_state_lock);
- del_timer_sync(journal->j_commit_timer);
+ del_timer_sync(&journal->j_commit_timer);
journal_commit_transaction(journal);
spin_lock(&journal->j_state_lock);
- goto end_loop;
+ goto loop;
}
wake_up(&journal->j_wait_done_commit);
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
/*
* The simpler the better. Flushing journal isn't a
* good idea, because that depends on threads that may
*/
jbd_debug(1, "Now suspending kjournald\n");
spin_unlock(&journal->j_state_lock);
- refrigerator(PF_FREEZE);
+ refrigerator();
spin_lock(&journal->j_state_lock);
} else {
/*
if (transaction && time_after_eq(jiffies,
transaction->t_expires))
should_sleep = 0;
+ if (journal->j_flags & JFS_UNMOUNT)
+ should_sleep = 0;
if (should_sleep) {
spin_unlock(&journal->j_state_lock);
schedule();
journal->j_commit_request = transaction->t_tid;
jbd_debug(1, "woke because of timeout\n");
}
-end_loop:
- if (!(journal->j_flags & JFS_UNMOUNT))
- goto loop;
+ goto loop;
+end_loop:
spin_unlock(&journal->j_state_lock);
- del_timer_sync(journal->j_commit_timer);
+ del_timer_sync(&journal->j_commit_timer);
journal->j_task = NULL;
wake_up(&journal->j_wait_done_commit);
jbd_debug(1, "Journal thread exiting.\n");
static void journal_start_thread(journal_t *journal)
{
- kernel_thread(kjournald, journal, CLONE_VM|CLONE_FS|CLONE_FILES);
+ kthread_run(kjournald, journal, "kjournald");
wait_event(journal->j_wait_done_commit, journal->j_task != 0);
}
/*
* Check for escaping
*/
- if (*((unsigned int *)(mapped_data + new_offset)) ==
- htonl(JFS_MAGIC_NUMBER)) {
+ if (*((__be32 *)(mapped_data + new_offset)) ==
+ cpu_to_be32(JFS_MAGIC_NUMBER)) {
need_copy_out = 1;
do_escape = 1;
}
* We play buffer_head aliasing tricks to write data/metadata blocks to
* the journal without copying their contents, but for journal
* descriptor blocks we do need to generate bona fide buffers.
+ *
+ * After the caller of journal_get_descriptor_buffer() has finished modifying
+ * the buffer's contents they really should run flush_dcache_page(bh->b_page).
+ * But we don't bother doing that, so there will be coherency problems with
+ * mmaps of blockdevs which hold live JBD-controlled filesystems.
*/
-
-struct journal_head * journal_get_descriptor_buffer(journal_t *journal)
+struct journal_head *journal_get_descriptor_buffer(journal_t *journal)
{
struct buffer_head *bh;
unsigned long blocknr;
return NULL;
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ lock_buffer(bh);
memset(bh->b_data, 0, journal->j_blocksize);
- bh->b_state |= (1 << BH_Dirty);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
BUFFER_TRACE(bh, "return this buffer");
return journal_add_journal_head(bh);
}
init_waitqueue_head(&journal->j_wait_checkpoint);
init_waitqueue_head(&journal->j_wait_commit);
init_waitqueue_head(&journal->j_wait_updates);
- init_MUTEX(&journal->j_barrier);
- init_MUTEX(&journal->j_checkpoint_sem);
+ mutex_init(&journal->j_barrier);
+ mutex_init(&journal->j_checkpoint_mutex);
spin_lock_init(&journal->j_revoke_lock);
spin_lock_init(&journal->j_list_lock);
spin_lock_init(&journal->j_state_lock);
{
journal_t *journal = journal_init_common();
struct buffer_head *bh;
+ int n;
if (!journal)
return NULL;
journal->j_sb_buffer = bh;
journal->j_superblock = (journal_superblock_t *)bh->b_data;
+ /* journal descriptor can store up to n blocks -bzzz */
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+ if (!journal->j_wbuf) {
+ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+ __FUNCTION__);
+ kfree(journal);
+ journal = NULL;
+ }
+
return journal;
}
struct buffer_head *bh;
journal_t *journal = journal_init_common();
int err;
+ int n;
unsigned long blocknr;
if (!journal)
journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
journal->j_blocksize = inode->i_sb->s_blocksize;
+ /* journal descriptor can store up to n blocks -bzzz */
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+ if (!journal->j_wbuf) {
+ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+ __FUNCTION__);
+ kfree(journal);
+ return NULL;
+ }
+
err = journal_bmap(journal, 0, &blocknr);
/* If that failed, give up */
if (err) {
journal_superblock_t *sb = journal->j_superblock;
unsigned int first, last;
- first = ntohl(sb->s_first);
- last = ntohl(sb->s_maxlen);
+ first = be32_to_cpu(sb->s_first);
+ last = be32_to_cpu(sb->s_maxlen);
journal->j_first = first;
journal->j_last = last;
/* OK, fill in the initial static fields in the new superblock */
sb = journal->j_superblock;
- sb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
- sb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+ sb->s_header.h_magic = cpu_to_be32(JFS_MAGIC_NUMBER);
+ sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2);
- sb->s_blocksize = htonl(journal->j_blocksize);
- sb->s_maxlen = htonl(journal->j_maxlen);
- sb->s_first = htonl(1);
+ sb->s_blocksize = cpu_to_be32(journal->j_blocksize);
+ sb->s_maxlen = cpu_to_be32(journal->j_maxlen);
+ sb->s_first = cpu_to_be32(1);
journal->j_transaction_sequence = 1;
jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
journal->j_tail, journal->j_tail_sequence, journal->j_errno);
- sb->s_sequence = htonl(journal->j_tail_sequence);
- sb->s_start = htonl(journal->j_tail);
- sb->s_errno = htonl(journal->j_errno);
+ sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
+ sb->s_start = cpu_to_be32(journal->j_tail);
+ sb->s_errno = cpu_to_be32(journal->j_errno);
spin_unlock(&journal->j_state_lock);
BUFFER_TRACE(bh, "marking dirty");
if (wait)
sync_dirty_buffer(bh);
else
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(SWRITE, 1, &bh);
out:
/* If we have just flushed the log (by marking s_start==0), then
err = -EINVAL;
- if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
- sb->s_blocksize != htonl(journal->j_blocksize)) {
+ if (sb->s_header.h_magic != cpu_to_be32(JFS_MAGIC_NUMBER) ||
+ sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) {
printk(KERN_WARNING "JBD: no valid journal superblock found\n");
goto out;
}
- switch(ntohl(sb->s_header.h_blocktype)) {
+ switch(be32_to_cpu(sb->s_header.h_blocktype)) {
case JFS_SUPERBLOCK_V1:
journal->j_format_version = 1;
break;
goto out;
}
- if (ntohl(sb->s_maxlen) < journal->j_maxlen)
- journal->j_maxlen = ntohl(sb->s_maxlen);
- else if (ntohl(sb->s_maxlen) > journal->j_maxlen) {
+ if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen)
+ journal->j_maxlen = be32_to_cpu(sb->s_maxlen);
+ else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) {
printk (KERN_WARNING "JBD: journal file too short\n");
goto out;
}
sb = journal->j_superblock;
- journal->j_tail_sequence = ntohl(sb->s_sequence);
- journal->j_tail = ntohl(sb->s_start);
- journal->j_first = ntohl(sb->s_first);
- journal->j_last = ntohl(sb->s_maxlen);
- journal->j_errno = ntohl(sb->s_errno);
+ journal->j_tail_sequence = be32_to_cpu(sb->s_sequence);
+ journal->j_tail = be32_to_cpu(sb->s_start);
+ journal->j_first = be32_to_cpu(sb->s_first);
+ journal->j_last = be32_to_cpu(sb->s_maxlen);
+ journal->j_errno = be32_to_cpu(sb->s_errno);
return 0;
}
iput(journal->j_inode);
if (journal->j_revoke)
journal_destroy_revoke(journal);
+ kfree(journal->j_wbuf);
kfree(journal);
}
/**
*int journal_check_used_features () - Check if features specified are used.
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
*
* Check whether the journal uses all of a given set of
* features. Return true (non-zero) if it does.
/**
* int journal_check_available_features() - Check feature set in journalling layer
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
*
* Check whether the journaling code supports the use of
* all of a given set of features on this journal. Return true
/**
* int journal_set_features () - Mark a given journal feature in the superblock
+ * @journal: Journal to act on.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
*
* Mark a given journal feature as present on the
* superblock. Returns true if the requested features could be set.
/**
* int journal_update_format () - Update on-disk journal structure.
+ * @journal: Journal to act on.
*
* Given an initialised but unloaded journal struct, poke about in the
* on-disk structure to update it to the most recent supported version.
sb = journal->j_superblock;
- switch (ntohl(sb->s_header.h_blocktype)) {
+ switch (be32_to_cpu(sb->s_header.h_blocktype)) {
case JFS_SUPERBLOCK_V2:
return 0;
case JFS_SUPERBLOCK_V1:
/* Pre-initialise new fields to zero */
offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);
- blocksize = ntohl(sb->s_blocksize);
+ blocksize = be32_to_cpu(sb->s_blocksize);
memset(&sb->s_feature_compat, 0, blocksize-offset);
sb->s_nr_users = cpu_to_be32(1);
* device this journal is present.
*/
-const char *journal_dev_name(journal_t *journal, char *buffer)
+static const char *journal_dev_name(journal_t *journal, char *buffer)
{
struct block_device *bdev;
/* Soft abort: record the abort error status in the journal superblock,
* but don't do any other IO. */
-void __journal_abort_soft (journal_t *journal, int errno)
+static void __journal_abort_soft (journal_t *journal, int errno)
{
if (journal->j_flags & JFS_ABORT)
return;
/**
* int journal_clear_err () - clears the journal's error state
+ * @journal: journal to act on.
*
* An error must be cleared or Acked to take a FS out of readonly
* mode.
/**
* void journal_ack_err() - Ack journal err.
+ * @journal: journal to act on.
*
* An error must be cleared or Acked to take a FS out of readonly
* mode.
}
/*
- * Simple support for retying memory allocations. Introduced to help to
+ * Simple support for retrying memory allocations. Introduced to help to
* debug different VM deadlock avoidance strategies.
*/
-/*
- * Simple support for retying memory allocations. Introduced to help to
- * debug different VM deadlock avoidance strategies.
- */
-void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry)
+void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
{
return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
}
{
J_ASSERT(journal_head_cache != NULL);
kmem_cache_destroy(journal_head_cache);
- journal_head_cache = 0;
+ journal_head_cache = NULL;
}
/*
if (jh->b_transaction == NULL &&
jh->b_next_transaction == NULL &&
jh->b_cp_transaction == NULL) {
+ J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
J_ASSERT_BH(bh, buffer_jbd(bh));
J_ASSERT_BH(bh, jh2bh(jh) == bh);
BUFFER_TRACE(bh, "remove journal_head");
static struct proc_dir_entry *proc_jbd_debug;
-int read_jbd_debug(char *page, char **start, off_t off,
+static int read_jbd_debug(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int ret;
return ret;
}
-int write_jbd_debug(struct file *file, const char __user *buffer,
+static int write_jbd_debug(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char buf[32];
{
int ret;
+/* Static check for data structure consistency. There's no code
+ * invoked --- we'll just get a linker failure if things aren't right.
+ */
+ extern void journal_bad_superblock_size(void);
+ if (sizeof(struct journal_superblock_s) != 1024)
+ journal_bad_superblock_size();
+
+
ret = journal_init_caches();
if (ret != 0)
journal_destroy_caches();