diff options
author | Joern Engel <joern@logfs.org> | 2010-05-07 19:38:40 +0200 |
---|---|---|
committer | Joern Engel <joern@logfs.org> | 2010-05-07 19:38:40 +0200 |
commit | 6f485b41875dbf5160c1990322469c1f65f77b28 (patch) | |
tree | 9912cee9517b57c2cb3c0318861f2a9eeb4139b2 /fs/logfs/dev_mtd.c | |
parent | ccf31c10f125ab5233c8517f91d4b3bd0bd60936 (diff) | |
download | lwn-6f485b41875dbf5160c1990322469c1f65f77b28.tar.gz lwn-6f485b41875dbf5160c1990322469c1f65f77b28.zip |
logfs: handle powerfail on NAND flash
The write buffer may not have been written and may no longer be written
due to an interrupted write in the affected page.
Signed-off-by: Joern Engel <joern@logfs.org>
Diffstat (limited to 'fs/logfs/dev_mtd.c')
-rw-r--r-- | fs/logfs/dev_mtd.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index b02a4020241a..a85d47d13e4b 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c @@ -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, }; |