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

Commit 7d32c0ac authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/joern/logfs:
  logfs: handle powerfail on NAND flash
  logfs: handle errors from get_mtd_device()
  logfs: remove unused variable
  logfs: fix sync
  logfs: fix compile failure
  logfs: initialize li->li_refcount
  logfs: commit reservations under space pressure
  logfs: survive logfs_buf_recover read errors
  logfs: Close i_ino reuse race
  logfs: fix logfs_seek_hole()
  logfs: Return -EINVAL if filesystem image doesn't match
  LogFS: Fix typo in b6349ac8
  logfs: testing the wrong variable
parents 3d2c978e 6f485b41
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -303,6 +303,11 @@ static void bdev_put_device(struct super_block *sb)
	close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE);
}

static int bdev_can_write_buf(struct super_block *sb, u64 ofs)
{
	return 0;
}

static const struct logfs_device_ops bd_devops = {
	.find_first_sb	= bdev_find_first_sb,
	.find_last_sb	= bdev_find_last_sb,
@@ -310,6 +315,7 @@ static const struct logfs_device_ops bd_devops = {
	.readpage	= bdev_readpage,
	.writeseg	= bdev_writeseg,
	.erase		= bdev_erase,
	.can_write_buf	= bdev_can_write_buf,
	.sync		= bdev_sync,
	.put_device	= bdev_put_device,
};
+25 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/completion.h>
#include <linux/mount.h>
#include <linux/sched.h>
#include <linux/slab.h>

#define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1))

@@ -126,7 +127,8 @@ static int mtd_readpage(void *_sb, struct page *page)

	err = mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE,
			page_address(page));
	if (err == -EUCLEAN) {
	if (err == -EUCLEAN || err == -EBADMSG) {
		/* -EBADMSG happens regularly on power failures */
		err = 0;
		/* FIXME: force GC this segment */
	}
@@ -233,12 +235,32 @@ static void mtd_put_device(struct super_block *sb)
	put_mtd_device(logfs_super(sb)->s_mtd);
}

static int mtd_can_write_buf(struct super_block *sb, u64 ofs)
{
	struct logfs_super *super = logfs_super(sb);
	void *buf;
	int err;

	buf = kmalloc(super->s_writesize, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
	err = mtd_read(sb, ofs, super->s_writesize, buf);
	if (err)
		goto out;
	if (memchr_inv(buf, 0xff, super->s_writesize))
		err = -EIO;
	kfree(buf);
out:
	return err;
}

static const struct logfs_device_ops mtd_devops = {
	.find_first_sb	= mtd_find_first_sb,
	.find_last_sb	= mtd_find_last_sb,
	.readpage	= mtd_readpage,
	.writeseg	= mtd_writeseg,
	.erase		= mtd_erase,
	.can_write_buf	= mtd_can_write_buf,
	.sync		= mtd_sync,
	.put_device	= mtd_put_device,
};
@@ -250,5 +272,7 @@ int logfs_get_sb_mtd(struct file_system_type *type, int flags,
	const struct logfs_device_ops *devops = &mtd_devops;

	mtd = get_mtd_device(NULL, mtdnr);
	if (IS_ERR(mtd))
		return PTR_ERR(mtd);
	return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt);
}
+12 −4
Original line number Diff line number Diff line
@@ -161,6 +161,16 @@ static int logfs_writepage(struct page *page, struct writeback_control *wbc)

static void logfs_invalidatepage(struct page *page, unsigned long offset)
{
	struct logfs_block *block = logfs_block(page);

	if (block->reserved_bytes) {
		struct super_block *sb = page->mapping->host->i_sb;
		struct logfs_super *super = logfs_super(sb);

		super->s_dirty_pages -= block->reserved_bytes;
		block->ops->free_block(sb, block);
		BUG_ON(bitmap_weight(block->alias_map, LOGFS_BLOCK_FACTOR));
	} else
		move_page_to_btree(page);
	BUG_ON(PagePrivate(page) || page->private);
}
@@ -212,10 +222,8 @@ int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
int logfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	struct super_block *sb = dentry->d_inode->i_sb;
	struct logfs_super *super = logfs_super(sb);

	/* FIXME: write anchor */
	super->s_devops->sync(sb);
	logfs_write_anchor(sb);
	return 0;
}

+21 −28
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ static void logfs_cleanse_block(struct super_block *sb, u64 ofs, u64 ino,
	logfs_safe_iput(inode, cookie);
}

static u32 logfs_gc_segment(struct super_block *sb, u32 segno, u8 dist)
static u32 logfs_gc_segment(struct super_block *sb, u32 segno)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_segment_header sh;
@@ -401,7 +401,7 @@ static int __logfs_gc_once(struct super_block *sb, struct gc_candidate *cand)
			segno, (u64)segno << super->s_segshift,
			dist, no_free_segments(sb), valid,
			super->s_free_bytes);
	cleaned = logfs_gc_segment(sb, segno, dist);
	cleaned = logfs_gc_segment(sb, segno);
	log_gc("GC segment #%02x complete - now %x valid\n", segno,
			valid - cleaned);
	BUG_ON(cleaned != valid);
@@ -632,38 +632,31 @@ static int check_area(struct super_block *sb, int i)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_area *area = super->s_area[i];
	struct logfs_object_header oh;
	gc_level_t gc_level;
	u32 cleaned, valid, ec;
	u32 segno = area->a_segno;
	u32 ofs = area->a_used_bytes;
	__be32 crc;
	int err;
	u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes);

	if (!area->a_is_open)
		return 0;

	for (ofs = area->a_used_bytes;
	     ofs <= super->s_segsize - sizeof(oh);
	     ofs += (u32)be16_to_cpu(oh.len) + sizeof(oh)) {
		err = wbuf_read(sb, dev_ofs(sb, segno, ofs), sizeof(oh), &oh);
		if (err)
			return err;

		if (!memchr_inv(&oh, 0xff, sizeof(oh)))
			break;

		crc = logfs_crc32(&oh, sizeof(oh) - 4, 4);
		if (crc != oh.crc) {
			printk(KERN_INFO "interrupted header at %llx\n",
					dev_ofs(sb, segno, ofs));
	if (super->s_devops->can_write_buf(sb, ofs) == 0)
		return 0;
		}
	}
	if (ofs != area->a_used_bytes) {
		printk(KERN_INFO "%x bytes unaccounted data found at %llx\n",
				ofs - area->a_used_bytes,
				dev_ofs(sb, segno, area->a_used_bytes));
		area->a_used_bytes = ofs;
	}

	printk(KERN_INFO"LogFS: Possibly incomplete write at %llx\n", ofs);
	/*
	 * The device cannot write back the write buffer.  Most likely the
	 * wbuf was already written out and the system crashed at some point
	 * before the journal commit happened.  In that case we wouldn't have
	 * to do anything.  But if the crash happened before the wbuf was
	 * written out correctly, we must GC this segment.  So assume the
	 * worst and always do the GC run.
	 */
	area->a_is_open = 0;
	valid = logfs_valid_bytes(sb, segno, &ec, &gc_level);
	cleaned = logfs_gc_segment(sb, segno);
	if (cleaned != valid)
		return -EIO;
	return 0;
}

+3 −3
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ static void logfs_init_inode(struct super_block *sb, struct inode *inode)
	inode->i_ctime	= CURRENT_TIME;
	inode->i_mtime	= CURRENT_TIME;
	inode->i_nlink	= 1;
	li->li_refcount = 1;
	INIT_LIST_HEAD(&li->li_freeing_list);

	for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++)
@@ -326,7 +327,7 @@ static void logfs_set_ino_generation(struct super_block *sb,
	u64 ino;

	mutex_lock(&super->s_journal_mutex);
	ino = logfs_seek_hole(super->s_master_inode, super->s_last_ino);
	ino = logfs_seek_hole(super->s_master_inode, super->s_last_ino + 1);
	super->s_last_ino = ino;
	super->s_inos_till_wrap--;
	if (super->s_inos_till_wrap < 0) {
@@ -386,8 +387,7 @@ static void logfs_init_once(void *_li)

static int logfs_sync_fs(struct super_block *sb, int wait)
{
	/* FIXME: write anchor */
	logfs_super(sb)->s_devops->sync(sb);
	logfs_write_anchor(sb);
	return 0;
}

Loading