aboutsummaryrefslogtreecommitdiffstats
path: root/fs/logfs
diff options
context:
space:
mode:
authorJoern Engel <joern@logfs.org>2010-04-13 11:46:37 -0400
committerJoern Engel <joern@logfs.org>2010-04-13 11:46:37 -0400
commit032d8f7268444a0f5d4ee02d9513d682d5b8edfc (patch)
tree57cd841514abb9ffe7df7d2569513663f551f960 /fs/logfs
parente05c378f4973674a16d5b9636f2310cf88aca5f2 (diff)
[LogFS] Prevent memory corruption on large deletes
Removing sufficiently large files would create aliases for a large number of segments. This in turn results in a large number of journal entries and an overflow of s_je_array. Cheap fix is to add a BUG_ON, turning memory corruption into something annoying, but less dangerous. Real fix is to count the number of affected segments and prevent the problem completely. Signed-off-by: Joern Engel <joern@logfs.org>
Diffstat (limited to 'fs/logfs')
-rw-r--r--fs/logfs/gc.c8
-rw-r--r--fs/logfs/journal.c3
-rw-r--r--fs/logfs/logfs.h8
-rw-r--r--fs/logfs/readwrite.c14
-rw-r--r--fs/logfs/super.c2
5 files changed, 34 insertions, 1 deletions
diff --git a/fs/logfs/gc.c b/fs/logfs/gc.c
index 92949f95a901..e8253e7fb6b2 100644
--- a/fs/logfs/gc.c
+++ b/fs/logfs/gc.c
@@ -458,6 +458,14 @@ static void __logfs_gc_pass(struct super_block *sb, int target)
458 struct logfs_block *block; 458 struct logfs_block *block;
459 int round, progress, last_progress = 0; 459 int round, progress, last_progress = 0;
460 460
461 /*
462 * Doing too many changes to the segfile at once would result
463 * in a large number of aliases. Write the journal before
464 * things get out of hand.
465 */
466 if (super->s_shadow_tree.no_shadowed_segments >= MAX_OBJ_ALIASES)
467 logfs_write_anchor(sb);
468
461 if (no_free_segments(sb) >= target && 469 if (no_free_segments(sb) >= target &&
462 super->s_no_object_aliases < MAX_OBJ_ALIASES) 470 super->s_no_object_aliases < MAX_OBJ_ALIASES)
463 return; 471 return;
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c
index d57c7b07b60b..2c22a4ad5329 100644
--- a/fs/logfs/journal.c
+++ b/fs/logfs/journal.c
@@ -493,6 +493,8 @@ static void account_shadows(struct super_block *sb)
493 493
494 btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); 494 btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow);
495 btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); 495 btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow);
496 btree_grim_visitor32(&tree->segment_map, 0, NULL);
497 tree->no_shadowed_segments = 0;
496 498
497 if (li->li_block) { 499 if (li->li_block) {
498 /* 500 /*
@@ -660,6 +662,7 @@ static int logfs_write_je_buf(struct super_block *sb, void *buf, u16 type,
660 if (ofs < 0) 662 if (ofs < 0)
661 return ofs; 663 return ofs;
662 logfs_buf_write(area, ofs, super->s_compressed_je, len); 664 logfs_buf_write(area, ofs, super->s_compressed_je, len);
665 BUG_ON(super->s_no_je >= MAX_JOURNAL_ENTRIES);
663 super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs); 666 super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs);
664 return 0; 667 return 0;
665} 668}
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h
index 97195b9e93a5..c9929eed80b1 100644
--- a/fs/logfs/logfs.h
+++ b/fs/logfs/logfs.h
@@ -257,10 +257,14 @@ struct logfs_shadow {
257 * struct shadow_tree 257 * struct shadow_tree
258 * @new: shadows where old_ofs==0, indexed by new_ofs 258 * @new: shadows where old_ofs==0, indexed by new_ofs
259 * @old: shadows where old_ofs!=0, indexed by old_ofs 259 * @old: shadows where old_ofs!=0, indexed by old_ofs
260 * @segment_map: bitfield of segments containing shadows
261 * @no_shadowed_segment: number of segments containing shadows
260 */ 262 */
261struct shadow_tree { 263struct shadow_tree {
262 struct btree_head64 new; 264 struct btree_head64 new;
263 struct btree_head64 old; 265 struct btree_head64 old;
266 struct btree_head32 segment_map;
267 int no_shadowed_segments;
264}; 268};
265 269
266struct object_alias_item { 270struct object_alias_item {
@@ -311,6 +315,8 @@ struct logfs_block_ops {
311 write_alias_t *write_one_alias); 315 write_alias_t *write_one_alias);
312}; 316};
313 317
318#define MAX_JOURNAL_ENTRIES 256
319
314struct logfs_super { 320struct logfs_super {
315 struct mtd_info *s_mtd; /* underlying device */ 321 struct mtd_info *s_mtd; /* underlying device */
316 struct block_device *s_bdev; /* underlying device */ 322 struct block_device *s_bdev; /* underlying device */
@@ -377,7 +383,7 @@ struct logfs_super {
377 u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */ 383 u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */
378 u64 s_last_version; 384 u64 s_last_version;
379 struct logfs_area *s_journal_area; /* open journal segment */ 385 struct logfs_area *s_journal_area; /* open journal segment */
380 __be64 s_je_array[64]; 386 __be64 s_je_array[MAX_JOURNAL_ENTRIES];
381 int s_no_je; 387 int s_no_je;
382 388
383 int s_sum_index; /* for the 12 summaries */ 389 int s_sum_index; /* for the 12 summaries */
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index 3659c37fbd72..7e0c39c49719 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -1219,6 +1219,18 @@ static void free_shadow(struct inode *inode, struct logfs_shadow *shadow)
1219 mempool_free(shadow, super->s_shadow_pool); 1219 mempool_free(shadow, super->s_shadow_pool);
1220} 1220}
1221 1221
1222static void mark_segment(struct shadow_tree *tree, u32 segno)
1223{
1224 int err;
1225
1226 if (!btree_lookup32(&tree->segment_map, segno)) {
1227 err = btree_insert32(&tree->segment_map, segno, (void *)1,
1228 GFP_NOFS);
1229 BUG_ON(err);
1230 tree->no_shadowed_segments++;
1231 }
1232}
1233
1222/** 1234/**
1223 * fill_shadow_tree - Propagate shadow tree changes due to a write 1235 * fill_shadow_tree - Propagate shadow tree changes due to a write
1224 * @inode: Inode owning the page 1236 * @inode: Inode owning the page
@@ -1266,6 +1278,8 @@ static void fill_shadow_tree(struct inode *inode, struct page *page,
1266 1278
1267 super->s_dirty_used_bytes += shadow->new_len; 1279 super->s_dirty_used_bytes += shadow->new_len;
1268 super->s_dirty_free_bytes += shadow->old_len; 1280 super->s_dirty_free_bytes += shadow->old_len;
1281 mark_segment(tree, shadow->old_ofs >> super->s_segshift);
1282 mark_segment(tree, shadow->new_ofs >> super->s_segshift);
1269 } 1283 }
1270} 1284}
1271 1285
diff --git a/fs/logfs/super.c b/fs/logfs/super.c
index 9d856c49afc5..d6e1f4fc3115 100644
--- a/fs/logfs/super.c
+++ b/fs/logfs/super.c
@@ -451,6 +451,8 @@ static int logfs_read_sb(struct super_block *sb, int read_only)
451 451
452 btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool); 452 btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool);
453 btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool); 453 btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool);
454 btree_init_mempool32(&super->s_shadow_tree.segment_map,
455 super->s_btree_pool);
454 456
455 ret = logfs_init_mapping(sb); 457 ret = logfs_init_mapping(sb);
456 if (ret) 458 if (ret)