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 | } |
