diff options
Diffstat (limited to 'fs/logfs/dev_mtd.c')
-rw-r--r-- | fs/logfs/dev_mtd.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index cafb6ef2e05b..a85d47d13e4b 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
10 | #include <linux/mount.h> | 10 | #include <linux/mount.h> |
11 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
12 | #include <linux/slab.h> | ||
12 | 13 | ||
13 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) | 14 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) |
14 | 15 | ||
@@ -126,7 +127,8 @@ static int mtd_readpage(void *_sb, struct page *page) | |||
126 | 127 | ||
127 | err = mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE, | 128 | err = mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE, |
128 | page_address(page)); | 129 | page_address(page)); |
129 | if (err == -EUCLEAN) { | 130 | if (err == -EUCLEAN || err == -EBADMSG) { |
131 | /* -EBADMSG happens regularly on power failures */ | ||
130 | err = 0; | 132 | err = 0; |
131 | /* FIXME: force GC this segment */ | 133 | /* FIXME: force GC this segment */ |
132 | } | 134 | } |
@@ -233,12 +235,32 @@ static void mtd_put_device(struct super_block *sb) | |||
233 | put_mtd_device(logfs_super(sb)->s_mtd); | 235 | put_mtd_device(logfs_super(sb)->s_mtd); |
234 | } | 236 | } |
235 | 237 | ||
238 | static int mtd_can_write_buf(struct super_block *sb, u64 ofs) | ||
239 | { | ||
240 | struct logfs_super *super = logfs_super(sb); | ||
241 | void *buf; | ||
242 | int err; | ||
243 | |||
244 | buf = kmalloc(super->s_writesize, GFP_KERNEL); | ||
245 | if (!buf) | ||
246 | return -ENOMEM; | ||
247 | err = mtd_read(sb, ofs, super->s_writesize, buf); | ||
248 | if (err) | ||
249 | goto out; | ||
250 | if (memchr_inv(buf, 0xff, super->s_writesize)) | ||
251 | err = -EIO; | ||
252 | kfree(buf); | ||
253 | out: | ||
254 | return err; | ||
255 | } | ||
256 | |||
236 | static const struct logfs_device_ops mtd_devops = { | 257 | static const struct logfs_device_ops mtd_devops = { |
237 | .find_first_sb = mtd_find_first_sb, | 258 | .find_first_sb = mtd_find_first_sb, |
238 | .find_last_sb = mtd_find_last_sb, | 259 | .find_last_sb = mtd_find_last_sb, |
239 | .readpage = mtd_readpage, | 260 | .readpage = mtd_readpage, |
240 | .writeseg = mtd_writeseg, | 261 | .writeseg = mtd_writeseg, |
241 | .erase = mtd_erase, | 262 | .erase = mtd_erase, |
263 | .can_write_buf = mtd_can_write_buf, | ||
242 | .sync = mtd_sync, | 264 | .sync = mtd_sync, |
243 | .put_device = mtd_put_device, | 265 | .put_device = mtd_put_device, |
244 | }; | 266 | }; |
@@ -250,5 +272,7 @@ int logfs_get_sb_mtd(struct file_system_type *type, int flags, | |||
250 | const struct logfs_device_ops *devops = &mtd_devops; | 272 | const struct logfs_device_ops *devops = &mtd_devops; |
251 | 273 | ||
252 | mtd = get_mtd_device(NULL, mtdnr); | 274 | mtd = get_mtd_device(NULL, mtdnr); |
275 | if (IS_ERR(mtd)) | ||
276 | return PTR_ERR(mtd); | ||
253 | return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt); | 277 | return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt); |
254 | } | 278 | } |