]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - fs/logfs/journal.c
[LogFS] Prevent memory corruption on large deletes
[linux-2.6.git] / fs / logfs / journal.c
index c0e7d63221d4cdf8931f2f97b6d19b0e90e37b08..2c22a4ad5329e4531045c9b42a75de13d839382f 100644 (file)
@@ -419,12 +419,13 @@ static size_t __logfs_write_header(struct logfs_super *super,
 {
        jh->h_len       = cpu_to_be16(len);
        jh->h_type      = cpu_to_be16(type);
-       jh->h_version   = cpu_to_be16(++super->s_last_version);
        jh->h_datalen   = cpu_to_be16(datalen);
        jh->h_compr     = compr;
        jh->h_pad[0]    = 'H';
-       jh->h_pad[1]    = 'A';
-       jh->h_pad[2]    = 'T';
+       jh->h_pad[1]    = 'E';
+       jh->h_pad[2]    = 'A';
+       jh->h_pad[3]    = 'D';
+       jh->h_pad[4]    = 'R';
        jh->h_crc       = logfs_crc32(jh, len + sizeof(*jh), 4);
        return ALIGN(len, 16) + sizeof(*jh);
 }
@@ -492,6 +493,8 @@ static void account_shadows(struct super_block *sb)
 
        btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow);
        btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow);
+       btree_grim_visitor32(&tree->segment_map, 0, NULL);
+       tree->no_shadowed_segments = 0;
 
        if (li->li_block) {
                /*
@@ -659,6 +662,7 @@ static int logfs_write_je_buf(struct super_block *sb, void *buf, u16 type,
        if (ofs < 0)
                return ofs;
        logfs_buf_write(area, ofs, super->s_compressed_je, len);
+       BUG_ON(super->s_no_je >= MAX_JOURNAL_ENTRIES);
        super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs);
        return 0;
 }
@@ -724,14 +728,17 @@ static int logfs_write_obj_aliases(struct super_block *sb)
  * bit wasteful, but robustness is more important.  With this we can *always*
  * erase all journal segments except the one containing the most recent commit.
  */
-void logfs_write_anchor(struct inode *inode)
+void logfs_write_anchor(struct super_block *sb)
 {
-       struct super_block *sb = inode->i_sb;
        struct logfs_super *super = logfs_super(sb);
        struct logfs_area *area = super->s_journal_area;
        int i, err;
 
-       BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
+       if (!(super->s_flags & LOGFS_SB_FLAG_DIRTY))
+               return;
+       super->s_flags &= ~LOGFS_SB_FLAG_DIRTY;
+
+       BUG_ON(super->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
        mutex_lock(&super->s_journal_mutex);
 
        /* Do this first or suffer corruption */
@@ -796,6 +803,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb)
 {
        struct logfs_super *super = logfs_super(sb);
        struct logfs_area *area = super->s_journal_area;
+       struct btree_head32 *head = &super->s_reserved_segments;
        u32 segno, ec;
        int i, err;
 
@@ -803,6 +811,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb)
        /* Drop old segments */
        journal_for_each(i)
                if (super->s_journal_seg[i]) {
+                       btree_remove32(head, super->s_journal_seg[i]);
                        logfs_set_segment_unreserved(sb,
                                        super->s_journal_seg[i],
                                        super->s_journal_ec[i]);
@@ -815,13 +824,18 @@ void do_logfs_journal_wl_pass(struct super_block *sb)
                super->s_journal_seg[i] = segno;
                super->s_journal_ec[i] = ec;
                logfs_set_segment_reserved(sb, segno);
+               err = btree_insert32(head, segno, (void *)1, GFP_KERNEL);
+               BUG_ON(err); /* mempool should prevent this */
+               err = logfs_erase_segment(sb, segno, 1);
+               BUG_ON(err); /* FIXME: remount-ro would be nicer */
        }
        /* Manually move journal_area */
+       freeseg(sb, area->a_segno);
        area->a_segno = super->s_journal_seg[0];
        area->a_is_open = 0;
        area->a_used_bytes = 0;
        /* Write journal */
-       logfs_write_anchor(super->s_master_inode);
+       logfs_write_anchor(sb);
        /* Write superblocks */
        err = logfs_write_sb(sb);
        BUG_ON(err);