Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 255f41c5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 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
parents 9befb55e b6349ac8
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -459,6 +459,14 @@ static void __logfs_gc_pass(struct super_block *sb, int target)
	struct logfs_block *block;
	int round, progress, last_progress = 0;

	/*
	 * Doing too many changes to the segfile at once would result
	 * in a large number of aliases.  Write the journal before
	 * things get out of hand.
	 */
	if (super->s_shadow_tree.no_shadowed_segments >= MAX_OBJ_ALIASES)
		logfs_write_anchor(sb);

	if (no_free_segments(sb) >= target &&
			super->s_no_object_aliases < MAX_OBJ_ALIASES)
		return;
+18 −11
Original line number Diff line number Diff line
@@ -389,7 +389,10 @@ static void journal_get_erase_count(struct logfs_area *area)
static int journal_erase_segment(struct logfs_area *area)
{
	struct super_block *sb = area->a_sb;
	union {
		struct logfs_segment_header sh;
		unsigned char c[ALIGN(sizeof(struct logfs_segment_header), 16)];
	} u;
	u64 ofs;
	int err;

@@ -397,20 +400,21 @@ static int journal_erase_segment(struct logfs_area *area)
	if (err)
		return err;

	sh.pad = 0;
	sh.type = SEG_JOURNAL;
	sh.level = 0;
	sh.segno = cpu_to_be32(area->a_segno);
	sh.ec = cpu_to_be32(area->a_erase_count);
	sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
	sh.crc = logfs_crc32(&sh, sizeof(sh), 4);
	memset(&u, 0, sizeof(u));
	u.sh.pad = 0;
	u.sh.type = SEG_JOURNAL;
	u.sh.level = 0;
	u.sh.segno = cpu_to_be32(area->a_segno);
	u.sh.ec = cpu_to_be32(area->a_erase_count);
	u.sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
	u.sh.crc = logfs_crc32(&u.sh, sizeof(u.sh), 4);

	/* This causes a bug in segment.c.  Not yet. */
	//logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0);

	ofs = dev_ofs(sb, area->a_segno, 0);
	area->a_used_bytes = ALIGN(sizeof(sh), 16);
	logfs_buf_write(area, ofs, &sh, sizeof(sh));
	area->a_used_bytes = sizeof(u);
	logfs_buf_write(area, ofs, &u, sizeof(u));
	return 0;
}

@@ -494,6 +498,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) {
		/*
@@ -607,9 +613,9 @@ static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type,
	if (len == 0)
		return logfs_write_header(super, header, 0, type);

	BUG_ON(len > sb->s_blocksize);
	compr_len = logfs_compress(buf, data, len, sb->s_blocksize);
	if (compr_len < 0 || type == JE_ANCHOR) {
		BUG_ON(len > sb->s_blocksize);
		memcpy(data, buf, len);
		compr_len = len;
		compr = COMPR_NONE;
@@ -661,6 +667,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;
}
+13 −2
Original line number Diff line number Diff line
@@ -257,10 +257,14 @@ struct logfs_shadow {
 * struct shadow_tree
 * @new:			shadows where old_ofs==0, indexed by new_ofs
 * @old:			shadows where old_ofs!=0, indexed by old_ofs
 * @segment_map:		bitfield of segments containing shadows
 * @no_shadowed_segment:	number of segments containing shadows
 */
struct shadow_tree {
	struct btree_head64 new;
	struct btree_head64 old;
	struct btree_head32 segment_map;
	int no_shadowed_segments;
};

struct object_alias_item {
@@ -305,13 +309,14 @@ typedef int write_alias_t(struct super_block *sb, u64 ino, u64 bix,
		level_t level, int child_no, __be64 val);
struct logfs_block_ops {
	void	(*write_block)(struct logfs_block *block);
	gc_level_t	(*block_level)(struct logfs_block *block);
	void	(*free_block)(struct super_block *sb, struct logfs_block*block);
	int	(*write_alias)(struct super_block *sb,
			struct logfs_block *block,
			write_alias_t *write_one_alias);
};

#define MAX_JOURNAL_ENTRIES 256

struct logfs_super {
	struct mtd_info *s_mtd;			/* underlying device */
	struct block_device *s_bdev;		/* underlying device */
@@ -378,7 +383,7 @@ struct logfs_super {
	u32	 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */
	u64	 s_last_version;
	struct logfs_area *s_journal_area;	/* open journal segment */
	__be64	s_je_array[64];
	__be64	s_je_array[MAX_JOURNAL_ENTRIES];
	int	s_no_je;

	int	 s_sum_index;			/* for the 12 summaries */
@@ -722,4 +727,10 @@ static inline struct logfs_area *get_area(struct super_block *sb,
	return logfs_super(sb)->s_area[(__force u8)gc_level];
}

static inline void logfs_mempool_destroy(mempool_t *pool)
{
	if (pool)
		mempool_destroy(pool);
}

#endif
+42 −33
Original line number Diff line number Diff line
@@ -430,25 +430,6 @@ static void inode_write_block(struct logfs_block *block)
	}
}

static gc_level_t inode_block_level(struct logfs_block *block)
{
	BUG_ON(block->inode->i_ino == LOGFS_INO_MASTER);
	return GC_LEVEL(LOGFS_MAX_LEVELS);
}

static gc_level_t indirect_block_level(struct logfs_block *block)
{
	struct page *page;
	struct inode *inode;
	u64 bix;
	level_t level;

	page = block->page;
	inode = page->mapping->host;
	logfs_unpack_index(page->index, &bix, &level);
	return expand_level(inode->i_ino, level);
}

/*
 * This silences a false, yet annoying gcc warning.  I hate it when my editor
 * jumps into bitops.h each time I recompile this file.
@@ -587,14 +568,12 @@ static void indirect_free_block(struct super_block *sb,

static struct logfs_block_ops inode_block_ops = {
	.write_block = inode_write_block,
	.block_level = inode_block_level,
	.free_block = inode_free_block,
	.write_alias = inode_write_alias,
};

struct logfs_block_ops indirect_block_ops = {
	.write_block = indirect_write_block,
	.block_level = indirect_block_level,
	.free_block = indirect_free_block,
	.write_alias = indirect_write_alias,
};
@@ -1241,6 +1220,18 @@ static void free_shadow(struct inode *inode, struct logfs_shadow *shadow)
	mempool_free(shadow, super->s_shadow_pool);
}

static void mark_segment(struct shadow_tree *tree, u32 segno)
{
	int err;

	if (!btree_lookup32(&tree->segment_map, segno)) {
		err = btree_insert32(&tree->segment_map, segno, (void *)1,
				GFP_NOFS);
		BUG_ON(err);
		tree->no_shadowed_segments++;
	}
}

/**
 * fill_shadow_tree - Propagate shadow tree changes due to a write
 * @inode:	Inode owning the page
@@ -1288,6 +1279,8 @@ static void fill_shadow_tree(struct inode *inode, struct page *page,

		super->s_dirty_used_bytes += shadow->new_len;
		super->s_dirty_free_bytes += shadow->old_len;
		mark_segment(tree, shadow->old_ofs >> super->s_segshift);
		mark_segment(tree, shadow->new_ofs >> super->s_segshift);
	}
}

@@ -1845,19 +1838,37 @@ static int __logfs_truncate(struct inode *inode, u64 size)
	return logfs_truncate_direct(inode, size);
}

int logfs_truncate(struct inode *inode, u64 size)
/*
 * Truncate, by changing the segment file, can consume a fair amount
 * of resources.  So back off from time to time and do some GC.
 * 8 or 2048 blocks should be well within safety limits even if
 * every single block resided in a different segment.
 */
#define TRUNCATE_STEP	(8 * 1024 * 1024)
int logfs_truncate(struct inode *inode, u64 target)
{
	struct super_block *sb = inode->i_sb;
	int err;
	u64 size = i_size_read(inode);
	int err = 0;

	size = ALIGN(size, TRUNCATE_STEP);
	while (size > target) {
		if (size > TRUNCATE_STEP)
			size -= TRUNCATE_STEP;
		else
			size = 0;
		if (size < target)
			size = target;

		logfs_get_wblocks(sb, NULL, 1);
	err = __logfs_truncate(inode, size);
		err = __logfs_truncate(inode, target);
		if (!err)
			err = __logfs_write_inode(inode, 0);
		logfs_put_wblocks(sb, NULL, 1);
	}

	if (!err)
		err = vmtruncate(inode, size);
		err = vmtruncate(inode, target);

	/* I don't trust error recovery yet. */
	WARN_ON(err);
@@ -2251,8 +2262,6 @@ void logfs_cleanup_rw(struct super_block *sb)
	struct logfs_super *super = logfs_super(sb);

	destroy_meta_inode(super->s_segfile_inode);
	if (super->s_block_pool)
		mempool_destroy(super->s_block_pool);
	if (super->s_shadow_pool)
		mempool_destroy(super->s_shadow_pool);
	logfs_mempool_destroy(super->s_block_pool);
	logfs_mempool_destroy(super->s_shadow_pool);
}
+1 −7
Original line number Diff line number Diff line
@@ -183,14 +183,8 @@ static int btree_write_alias(struct super_block *sb, struct logfs_block *block,
	return 0;
}

static gc_level_t btree_block_level(struct logfs_block *block)
{
	return expand_level(block->ino, block->level);
}

static struct logfs_block_ops btree_block_ops = {
	.write_block	= btree_write_block,
	.block_level	= btree_block_level,
	.free_block	= __free_block,
	.write_alias	= btree_write_alias,
};
@@ -919,7 +913,7 @@ int logfs_init_areas(struct super_block *sb)
	for (i--; i >= 0; i--)
		free_area(super->s_area[i]);
	free_area(super->s_journal_area);
	mempool_destroy(super->s_alias_pool);
	logfs_mempool_destroy(super->s_alias_pool);
	return -ENOMEM;
}

Loading