Commit 255f41c59558a346d65a2012420a7573e36dc584

Authored by Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/joern/logfs

* git://git.kernel.org/pub/scm/linux/kernel/git/joern/logfs:
  [LogFS] Split large truncated into smaller chunks
  [LogFS] Set s_bdi
  [LogFS] Prevent mempool_destroy NULL pointer dereference
  [LogFS] Move assertion
  [LogFS] Plug 8 byte information leak
  [LogFS] Prevent memory corruption on large deletes
  [LogFS] Remove unused method

Fix trivial conflict with added header includes in fs/logfs/super.c

Showing 6 changed files Side-by-side Diff

... ... @@ -459,6 +459,14 @@
459 459 struct logfs_block *block;
460 460 int round, progress, last_progress = 0;
461 461  
  462 + /*
  463 + * Doing too many changes to the segfile at once would result
  464 + * in a large number of aliases. Write the journal before
  465 + * things get out of hand.
  466 + */
  467 + if (super->s_shadow_tree.no_shadowed_segments >= MAX_OBJ_ALIASES)
  468 + logfs_write_anchor(sb);
  469 +
462 470 if (no_free_segments(sb) >= target &&
463 471 super->s_no_object_aliases < MAX_OBJ_ALIASES)
464 472 return;
... ... @@ -389,7 +389,10 @@
389 389 static int journal_erase_segment(struct logfs_area *area)
390 390 {
391 391 struct super_block *sb = area->a_sb;
392   - struct logfs_segment_header sh;
  392 + union {
  393 + struct logfs_segment_header sh;
  394 + unsigned char c[ALIGN(sizeof(struct logfs_segment_header), 16)];
  395 + } u;
393 396 u64 ofs;
394 397 int err;
395 398  
396 399  
... ... @@ -397,20 +400,21 @@
397 400 if (err)
398 401 return err;
399 402  
400   - sh.pad = 0;
401   - sh.type = SEG_JOURNAL;
402   - sh.level = 0;
403   - sh.segno = cpu_to_be32(area->a_segno);
404   - sh.ec = cpu_to_be32(area->a_erase_count);
405   - sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
406   - sh.crc = logfs_crc32(&sh, sizeof(sh), 4);
  403 + memset(&u, 0, sizeof(u));
  404 + u.sh.pad = 0;
  405 + u.sh.type = SEG_JOURNAL;
  406 + u.sh.level = 0;
  407 + u.sh.segno = cpu_to_be32(area->a_segno);
  408 + u.sh.ec = cpu_to_be32(area->a_erase_count);
  409 + u.sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
  410 + u.sh.crc = logfs_crc32(&u.sh, sizeof(u.sh), 4);
407 411  
408 412 /* This causes a bug in segment.c. Not yet. */
409 413 //logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0);
410 414  
411 415 ofs = dev_ofs(sb, area->a_segno, 0);
412   - area->a_used_bytes = ALIGN(sizeof(sh), 16);
413   - logfs_buf_write(area, ofs, &sh, sizeof(sh));
  416 + area->a_used_bytes = sizeof(u);
  417 + logfs_buf_write(area, ofs, &u, sizeof(u));
414 418 return 0;
415 419 }
416 420  
... ... @@ -494,6 +498,8 @@
494 498  
495 499 btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow);
496 500 btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow);
  501 + btree_grim_visitor32(&tree->segment_map, 0, NULL);
  502 + tree->no_shadowed_segments = 0;
497 503  
498 504 if (li->li_block) {
499 505 /*
500 506  
... ... @@ -607,9 +613,9 @@
607 613 if (len == 0)
608 614 return logfs_write_header(super, header, 0, type);
609 615  
  616 + BUG_ON(len > sb->s_blocksize);
610 617 compr_len = logfs_compress(buf, data, len, sb->s_blocksize);
611 618 if (compr_len < 0 || type == JE_ANCHOR) {
612   - BUG_ON(len > sb->s_blocksize);
613 619 memcpy(data, buf, len);
614 620 compr_len = len;
615 621 compr = COMPR_NONE;
... ... @@ -661,6 +667,7 @@
661 667 if (ofs < 0)
662 668 return ofs;
663 669 logfs_buf_write(area, ofs, super->s_compressed_je, len);
  670 + BUG_ON(super->s_no_je >= MAX_JOURNAL_ENTRIES);
664 671 super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs);
665 672 return 0;
666 673 }
... ... @@ -257,10 +257,14 @@
257 257 * struct shadow_tree
258 258 * @new: shadows where old_ofs==0, indexed by new_ofs
259 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 */
261 263 struct shadow_tree {
262 264 struct btree_head64 new;
263 265 struct btree_head64 old;
  266 + struct btree_head32 segment_map;
  267 + int no_shadowed_segments;
264 268 };
265 269  
266 270 struct object_alias_item {
267 271  
... ... @@ -305,13 +309,14 @@
305 309 level_t level, int child_no, __be64 val);
306 310 struct logfs_block_ops {
307 311 void (*write_block)(struct logfs_block *block);
308   - gc_level_t (*block_level)(struct logfs_block *block);
309 312 void (*free_block)(struct super_block *sb, struct logfs_block*block);
310 313 int (*write_alias)(struct super_block *sb,
311 314 struct logfs_block *block,
312 315 write_alias_t *write_one_alias);
313 316 };
314 317  
  318 +#define MAX_JOURNAL_ENTRIES 256
  319 +
315 320 struct logfs_super {
316 321 struct mtd_info *s_mtd; /* underlying device */
317 322 struct block_device *s_bdev; /* underlying device */
... ... @@ -378,7 +383,7 @@
378 383 u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */
379 384 u64 s_last_version;
380 385 struct logfs_area *s_journal_area; /* open journal segment */
381   - __be64 s_je_array[64];
  386 + __be64 s_je_array[MAX_JOURNAL_ENTRIES];
382 387 int s_no_je;
383 388  
384 389 int s_sum_index; /* for the 12 summaries */
... ... @@ -720,6 +725,12 @@
720 725 gc_level_t gc_level)
721 726 {
722 727 return logfs_super(sb)->s_area[(__force u8)gc_level];
  728 +}
  729 +
  730 +static inline void logfs_mempool_destroy(mempool_t *pool)
  731 +{
  732 + if (pool)
  733 + mempool_destroy(pool);
723 734 }
724 735  
725 736 #endif
fs/logfs/readwrite.c
... ... @@ -430,25 +430,6 @@
430 430 }
431 431 }
432 432  
433   -static gc_level_t inode_block_level(struct logfs_block *block)
434   -{
435   - BUG_ON(block->inode->i_ino == LOGFS_INO_MASTER);
436   - return GC_LEVEL(LOGFS_MAX_LEVELS);
437   -}
438   -
439   -static gc_level_t indirect_block_level(struct logfs_block *block)
440   -{
441   - struct page *page;
442   - struct inode *inode;
443   - u64 bix;
444   - level_t level;
445   -
446   - page = block->page;
447   - inode = page->mapping->host;
448   - logfs_unpack_index(page->index, &bix, &level);
449   - return expand_level(inode->i_ino, level);
450   -}
451   -
452 433 /*
453 434 * This silences a false, yet annoying gcc warning. I hate it when my editor
454 435 * jumps into bitops.h each time I recompile this file.
455 436  
... ... @@ -587,14 +568,12 @@
587 568  
588 569 static struct logfs_block_ops inode_block_ops = {
589 570 .write_block = inode_write_block,
590   - .block_level = inode_block_level,
591 571 .free_block = inode_free_block,
592 572 .write_alias = inode_write_alias,
593 573 };
594 574  
595 575 struct logfs_block_ops indirect_block_ops = {
596 576 .write_block = indirect_write_block,
597   - .block_level = indirect_block_level,
598 577 .free_block = indirect_free_block,
599 578 .write_alias = indirect_write_alias,
600 579 };
... ... @@ -1241,6 +1220,18 @@
1241 1220 mempool_free(shadow, super->s_shadow_pool);
1242 1221 }
1243 1222  
  1223 +static void mark_segment(struct shadow_tree *tree, u32 segno)
  1224 +{
  1225 + int err;
  1226 +
  1227 + if (!btree_lookup32(&tree->segment_map, segno)) {
  1228 + err = btree_insert32(&tree->segment_map, segno, (void *)1,
  1229 + GFP_NOFS);
  1230 + BUG_ON(err);
  1231 + tree->no_shadowed_segments++;
  1232 + }
  1233 +}
  1234 +
1244 1235 /**
1245 1236 * fill_shadow_tree - Propagate shadow tree changes due to a write
1246 1237 * @inode: Inode owning the page
... ... @@ -1288,6 +1279,8 @@
1288 1279  
1289 1280 super->s_dirty_used_bytes += shadow->new_len;
1290 1281 super->s_dirty_free_bytes += shadow->old_len;
  1282 + mark_segment(tree, shadow->old_ofs >> super->s_segshift);
  1283 + mark_segment(tree, shadow->new_ofs >> super->s_segshift);
1291 1284 }
1292 1285 }
1293 1286  
1294 1287  
1295 1288  
1296 1289  
1297 1290  
... ... @@ -1845,19 +1838,37 @@
1845 1838 return logfs_truncate_direct(inode, size);
1846 1839 }
1847 1840  
1848   -int logfs_truncate(struct inode *inode, u64 size)
  1841 +/*
  1842 + * Truncate, by changing the segment file, can consume a fair amount
  1843 + * of resources. So back off from time to time and do some GC.
  1844 + * 8 or 2048 blocks should be well within safety limits even if
  1845 + * every single block resided in a different segment.
  1846 + */
  1847 +#define TRUNCATE_STEP (8 * 1024 * 1024)
  1848 +int logfs_truncate(struct inode *inode, u64 target)
1849 1849 {
1850 1850 struct super_block *sb = inode->i_sb;
1851   - int err;
  1851 + u64 size = i_size_read(inode);
  1852 + int err = 0;
1852 1853  
1853   - logfs_get_wblocks(sb, NULL, 1);
1854   - err = __logfs_truncate(inode, size);
1855   - if (!err)
1856   - err = __logfs_write_inode(inode, 0);
1857   - logfs_put_wblocks(sb, NULL, 1);
  1854 + size = ALIGN(size, TRUNCATE_STEP);
  1855 + while (size > target) {
  1856 + if (size > TRUNCATE_STEP)
  1857 + size -= TRUNCATE_STEP;
  1858 + else
  1859 + size = 0;
  1860 + if (size < target)
  1861 + size = target;
1858 1862  
  1863 + logfs_get_wblocks(sb, NULL, 1);
  1864 + err = __logfs_truncate(inode, target);
  1865 + if (!err)
  1866 + err = __logfs_write_inode(inode, 0);
  1867 + logfs_put_wblocks(sb, NULL, 1);
  1868 + }
  1869 +
1859 1870 if (!err)
1860   - err = vmtruncate(inode, size);
  1871 + err = vmtruncate(inode, target);
1861 1872  
1862 1873 /* I don't trust error recovery yet. */
1863 1874 WARN_ON(err);
... ... @@ -2251,9 +2262,7 @@
2251 2262 struct logfs_super *super = logfs_super(sb);
2252 2263  
2253 2264 destroy_meta_inode(super->s_segfile_inode);
2254   - if (super->s_block_pool)
2255   - mempool_destroy(super->s_block_pool);
2256   - if (super->s_shadow_pool)
2257   - mempool_destroy(super->s_shadow_pool);
  2265 + logfs_mempool_destroy(super->s_block_pool);
  2266 + logfs_mempool_destroy(super->s_shadow_pool);
2258 2267 }
... ... @@ -183,14 +183,8 @@
183 183 return 0;
184 184 }
185 185  
186   -static gc_level_t btree_block_level(struct logfs_block *block)
187   -{
188   - return expand_level(block->ino, block->level);
189   -}
190   -
191 186 static struct logfs_block_ops btree_block_ops = {
192 187 .write_block = btree_write_block,
193   - .block_level = btree_block_level,
194 188 .free_block = __free_block,
195 189 .write_alias = btree_write_alias,
196 190 };
... ... @@ -919,7 +913,7 @@
919 913 for (i--; i >= 0; i--)
920 914 free_area(super->s_area[i]);
921 915 free_area(super->s_journal_area);
922   - mempool_destroy(super->s_alias_pool);
  916 + logfs_mempool_destroy(super->s_alias_pool);
923 917 return -ENOMEM;
924 918 }
925 919  
... ... @@ -12,6 +12,7 @@
12 12 #include "logfs.h"
13 13 #include <linux/bio.h>
14 14 #include <linux/slab.h>
  15 +#include <linux/blkdev.h>
15 16 #include <linux/mtd/mtd.h>
16 17 #include <linux/statfs.h>
17 18 #include <linux/buffer_head.h>
... ... @@ -137,6 +138,10 @@
137 138 sb->s_fs_info = super;
138 139 sb->s_mtd = super->s_mtd;
139 140 sb->s_bdev = super->s_bdev;
  141 + if (sb->s_bdev)
  142 + sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
  143 + if (sb->s_mtd)
  144 + sb->s_bdi = sb->s_mtd->backing_dev_info;
140 145 return 0;
141 146 }
142 147  
... ... @@ -452,6 +457,8 @@
452 457  
453 458 btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool);
454 459 btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool);
  460 + btree_init_mempool32(&super->s_shadow_tree.segment_map,
  461 + super->s_btree_pool);
455 462  
456 463 ret = logfs_init_mapping(sb);
457 464 if (ret)
... ... @@ -516,8 +523,8 @@
516 523 if (super->s_erase_page)
517 524 __free_page(super->s_erase_page);
518 525 super->s_devops->put_device(sb);
519   - mempool_destroy(super->s_btree_pool);
520   - mempool_destroy(super->s_alias_pool);
  526 + logfs_mempool_destroy(super->s_btree_pool);
  527 + logfs_mempool_destroy(super->s_alias_pool);
521 528 kfree(super);
522 529 log_super("LogFS: Finished unmounting\n");
523 530 }