diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-17 16:53:35 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-17 16:53:35 -0400 |
| commit | 7d32c0aca4fbd0319c860d12af5fae3e88c760e6 (patch) | |
| tree | 3df9712c128a98916601a98510e5160dac809264 | |
| parent | 3d2c978e0cd8b1157f9eebd13062d61fb7a75ad5 (diff) | |
| parent | 6f485b41875dbf5160c1990322469c1f65f77b28 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/joern/logfs
* 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
| -rw-r--r-- | fs/logfs/dev_bdev.c | 6 | ||||
| -rw-r--r-- | fs/logfs/dev_mtd.c | 26 | ||||
| -rw-r--r-- | fs/logfs/file.c | 16 | ||||
| -rw-r--r-- | fs/logfs/gc.c | 49 | ||||
| -rw-r--r-- | fs/logfs/inode.c | 6 | ||||
| -rw-r--r-- | fs/logfs/journal.c | 7 | ||||
| -rw-r--r-- | fs/logfs/logfs.h | 13 | ||||
| -rw-r--r-- | fs/logfs/readwrite.c | 19 | ||||
| -rw-r--r-- | fs/logfs/segment.c | 7 | ||||
| -rw-r--r-- | fs/logfs/super.c | 8 |
10 files changed, 104 insertions, 53 deletions
diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 243c00071f76..9bd2ce2a3040 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c | |||
| @@ -303,6 +303,11 @@ static void bdev_put_device(struct super_block *sb) | |||
| 303 | close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE); | 303 | close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE); |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | static int bdev_can_write_buf(struct super_block *sb, u64 ofs) | ||
| 307 | { | ||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 306 | static const struct logfs_device_ops bd_devops = { | 311 | static const struct logfs_device_ops bd_devops = { |
| 307 | .find_first_sb = bdev_find_first_sb, | 312 | .find_first_sb = bdev_find_first_sb, |
| 308 | .find_last_sb = bdev_find_last_sb, | 313 | .find_last_sb = bdev_find_last_sb, |
| @@ -310,6 +315,7 @@ static const struct logfs_device_ops bd_devops = { | |||
| 310 | .readpage = bdev_readpage, | 315 | .readpage = bdev_readpage, |
| 311 | .writeseg = bdev_writeseg, | 316 | .writeseg = bdev_writeseg, |
| 312 | .erase = bdev_erase, | 317 | .erase = bdev_erase, |
| 318 | .can_write_buf = bdev_can_write_buf, | ||
| 313 | .sync = bdev_sync, | 319 | .sync = bdev_sync, |
| 314 | .put_device = bdev_put_device, | 320 | .put_device = bdev_put_device, |
| 315 | }; | 321 | }; |
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 | } |
diff --git a/fs/logfs/file.c b/fs/logfs/file.c index 370f367a933e..0de524071870 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c | |||
| @@ -161,7 +161,17 @@ static int logfs_writepage(struct page *page, struct writeback_control *wbc) | |||
| 161 | 161 | ||
| 162 | static void logfs_invalidatepage(struct page *page, unsigned long offset) | 162 | static void logfs_invalidatepage(struct page *page, unsigned long offset) |
| 163 | { | 163 | { |
| 164 | move_page_to_btree(page); | 164 | struct logfs_block *block = logfs_block(page); |
| 165 | |||
| 166 | if (block->reserved_bytes) { | ||
| 167 | struct super_block *sb = page->mapping->host->i_sb; | ||
| 168 | struct logfs_super *super = logfs_super(sb); | ||
| 169 | |||
| 170 | super->s_dirty_pages -= block->reserved_bytes; | ||
| 171 | block->ops->free_block(sb, block); | ||
| 172 | BUG_ON(bitmap_weight(block->alias_map, LOGFS_BLOCK_FACTOR)); | ||
| 173 | } else | ||
| 174 | move_page_to_btree(page); | ||
| 165 | BUG_ON(PagePrivate(page) || page->private); | 175 | BUG_ON(PagePrivate(page) || page->private); |
| 166 | } | 176 | } |
| 167 | 177 | ||
| @@ -212,10 +222,8 @@ int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
| 212 | int logfs_fsync(struct file *file, struct dentry *dentry, int datasync) | 222 | int logfs_fsync(struct file *file, struct dentry *dentry, int datasync) |
| 213 | { | 223 | { |
| 214 | struct super_block *sb = dentry->d_inode->i_sb; | 224 | struct super_block *sb = dentry->d_inode->i_sb; |
| 215 | struct logfs_super *super = logfs_super(sb); | ||
| 216 | 225 | ||
| 217 | /* FIXME: write anchor */ | 226 | logfs_write_anchor(sb); |
| 218 | super->s_devops->sync(sb); | ||
| 219 | return 0; | 227 | return 0; |
| 220 | } | 228 | } |
| 221 | 229 | ||
diff --git a/fs/logfs/gc.c b/fs/logfs/gc.c index 76c242fbe1b0..caa4419285dc 100644 --- a/fs/logfs/gc.c +++ b/fs/logfs/gc.c | |||
| @@ -122,7 +122,7 @@ static void logfs_cleanse_block(struct super_block *sb, u64 ofs, u64 ino, | |||
| 122 | logfs_safe_iput(inode, cookie); | 122 | logfs_safe_iput(inode, cookie); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | static u32 logfs_gc_segment(struct super_block *sb, u32 segno, u8 dist) | 125 | static u32 logfs_gc_segment(struct super_block *sb, u32 segno) |
| 126 | { | 126 | { |
| 127 | struct logfs_super *super = logfs_super(sb); | 127 | struct logfs_super *super = logfs_super(sb); |
| 128 | struct logfs_segment_header sh; | 128 | struct logfs_segment_header sh; |
| @@ -401,7 +401,7 @@ static int __logfs_gc_once(struct super_block *sb, struct gc_candidate *cand) | |||
| 401 | segno, (u64)segno << super->s_segshift, | 401 | segno, (u64)segno << super->s_segshift, |
| 402 | dist, no_free_segments(sb), valid, | 402 | dist, no_free_segments(sb), valid, |
| 403 | super->s_free_bytes); | 403 | super->s_free_bytes); |
| 404 | cleaned = logfs_gc_segment(sb, segno, dist); | 404 | cleaned = logfs_gc_segment(sb, segno); |
| 405 | log_gc("GC segment #%02x complete - now %x valid\n", segno, | 405 | log_gc("GC segment #%02x complete - now %x valid\n", segno, |
| 406 | valid - cleaned); | 406 | valid - cleaned); |
| 407 | BUG_ON(cleaned != valid); | 407 | BUG_ON(cleaned != valid); |
| @@ -632,38 +632,31 @@ static int check_area(struct super_block *sb, int i) | |||
| 632 | { | 632 | { |
| 633 | struct logfs_super *super = logfs_super(sb); | 633 | struct logfs_super *super = logfs_super(sb); |
| 634 | struct logfs_area *area = super->s_area[i]; | 634 | struct logfs_area *area = super->s_area[i]; |
| 635 | struct logfs_object_header oh; | 635 | gc_level_t gc_level; |
| 636 | u32 cleaned, valid, ec; | ||
| 636 | u32 segno = area->a_segno; | 637 | u32 segno = area->a_segno; |
| 637 | u32 ofs = area->a_used_bytes; | 638 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
| 638 | __be32 crc; | ||
| 639 | int err; | ||
| 640 | 639 | ||
| 641 | if (!area->a_is_open) | 640 | if (!area->a_is_open) |
| 642 | return 0; | 641 | return 0; |
| 643 | 642 | ||
| 644 | for (ofs = area->a_used_bytes; | 643 | if (super->s_devops->can_write_buf(sb, ofs) == 0) |
| 645 | ofs <= super->s_segsize - sizeof(oh); | 644 | return 0; |
| 646 | ofs += (u32)be16_to_cpu(oh.len) + sizeof(oh)) { | ||
| 647 | err = wbuf_read(sb, dev_ofs(sb, segno, ofs), sizeof(oh), &oh); | ||
| 648 | if (err) | ||
| 649 | return err; | ||
| 650 | |||
| 651 | if (!memchr_inv(&oh, 0xff, sizeof(oh))) | ||
| 652 | break; | ||
| 653 | 645 | ||
| 654 | crc = logfs_crc32(&oh, sizeof(oh) - 4, 4); | 646 | printk(KERN_INFO"LogFS: Possibly incomplete write at %llx\n", ofs); |
| 655 | if (crc != oh.crc) { | 647 | /* |
| 656 | printk(KERN_INFO "interrupted header at %llx\n", | 648 | * The device cannot write back the write buffer. Most likely the |
| 657 | dev_ofs(sb, segno, ofs)); | 649 | * wbuf was already written out and the system crashed at some point |
| 658 | return 0; | 650 | * before the journal commit happened. In that case we wouldn't have |
| 659 | } | 651 | * to do anything. But if the crash happened before the wbuf was |
| 660 | } | 652 | * written out correctly, we must GC this segment. So assume the |
| 661 | if (ofs != area->a_used_bytes) { | 653 | * worst and always do the GC run. |
| 662 | printk(KERN_INFO "%x bytes unaccounted data found at %llx\n", | 654 | */ |
| 663 | ofs - area->a_used_bytes, | 655 | area->a_is_open = 0; |
| 664 | dev_ofs(sb, segno, area->a_used_bytes)); | 656 | valid = logfs_valid_bytes(sb, segno, &ec, &gc_level); |
| 665 | area->a_used_bytes = ofs; | 657 | cleaned = logfs_gc_segment(sb, segno); |
| 666 | } | 658 | if (cleaned != valid) |
| 659 | return -EIO; | ||
| 667 | return 0; | 660 | return 0; |
| 668 | } | 661 | } |
| 669 | 662 | ||
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index 14ed27274da2..755a92e8daa7 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c | |||
| @@ -193,6 +193,7 @@ static void logfs_init_inode(struct super_block *sb, struct inode *inode) | |||
| 193 | inode->i_ctime = CURRENT_TIME; | 193 | inode->i_ctime = CURRENT_TIME; |
| 194 | inode->i_mtime = CURRENT_TIME; | 194 | inode->i_mtime = CURRENT_TIME; |
| 195 | inode->i_nlink = 1; | 195 | inode->i_nlink = 1; |
| 196 | li->li_refcount = 1; | ||
| 196 | INIT_LIST_HEAD(&li->li_freeing_list); | 197 | INIT_LIST_HEAD(&li->li_freeing_list); |
| 197 | 198 | ||
| 198 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) | 199 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) |
| @@ -326,7 +327,7 @@ static void logfs_set_ino_generation(struct super_block *sb, | |||
| 326 | u64 ino; | 327 | u64 ino; |
| 327 | 328 | ||
| 328 | mutex_lock(&super->s_journal_mutex); | 329 | mutex_lock(&super->s_journal_mutex); |
| 329 | ino = logfs_seek_hole(super->s_master_inode, super->s_last_ino); | 330 | ino = logfs_seek_hole(super->s_master_inode, super->s_last_ino + 1); |
| 330 | super->s_last_ino = ino; | 331 | super->s_last_ino = ino; |
| 331 | super->s_inos_till_wrap--; | 332 | super->s_inos_till_wrap--; |
| 332 | if (super->s_inos_till_wrap < 0) { | 333 | if (super->s_inos_till_wrap < 0) { |
| @@ -386,8 +387,7 @@ static void logfs_init_once(void *_li) | |||
| 386 | 387 | ||
| 387 | static int logfs_sync_fs(struct super_block *sb, int wait) | 388 | static int logfs_sync_fs(struct super_block *sb, int wait) |
| 388 | { | 389 | { |
| 389 | /* FIXME: write anchor */ | 390 | logfs_write_anchor(sb); |
| 390 | logfs_super(sb)->s_devops->sync(sb); | ||
| 391 | return 0; | 391 | return 0; |
| 392 | } | 392 | } |
| 393 | 393 | ||
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index fb0a613f885b..4b0e0616b357 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c | |||
| @@ -132,10 +132,9 @@ static int read_area(struct super_block *sb, struct logfs_je_area *a) | |||
| 132 | 132 | ||
| 133 | ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); | 133 | ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
| 134 | if (super->s_writesize > 1) | 134 | if (super->s_writesize > 1) |
| 135 | logfs_buf_recover(area, ofs, a + 1, super->s_writesize); | 135 | return logfs_buf_recover(area, ofs, a + 1, super->s_writesize); |
| 136 | else | 136 | else |
| 137 | logfs_buf_recover(area, ofs, NULL, 0); | 137 | return logfs_buf_recover(area, ofs, NULL, 0); |
| 138 | return 0; | ||
| 139 | } | 138 | } |
| 140 | 139 | ||
| 141 | static void *unpack(void *from, void *to) | 140 | static void *unpack(void *from, void *to) |
| @@ -245,7 +244,7 @@ static int read_je(struct super_block *sb, u64 ofs) | |||
| 245 | read_erasecount(sb, unpack(jh, scratch)); | 244 | read_erasecount(sb, unpack(jh, scratch)); |
| 246 | break; | 245 | break; |
| 247 | case JE_AREA: | 246 | case JE_AREA: |
| 248 | read_area(sb, unpack(jh, scratch)); | 247 | err = read_area(sb, unpack(jh, scratch)); |
| 249 | break; | 248 | break; |
| 250 | case JE_OBJ_ALIAS: | 249 | case JE_OBJ_ALIAS: |
| 251 | err = logfs_load_object_aliases(sb, unpack(jh, scratch), | 250 | err = logfs_load_object_aliases(sb, unpack(jh, scratch), |
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index 0a3df1a0c936..93b55f337245 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h | |||
| @@ -144,6 +144,7 @@ struct logfs_area_ops { | |||
| 144 | * @erase: erase one segment | 144 | * @erase: erase one segment |
| 145 | * @read: read from the device | 145 | * @read: read from the device |
| 146 | * @erase: erase part of the device | 146 | * @erase: erase part of the device |
| 147 | * @can_write_buf: decide whether wbuf can be written to ofs | ||
| 147 | */ | 148 | */ |
| 148 | struct logfs_device_ops { | 149 | struct logfs_device_ops { |
| 149 | struct page *(*find_first_sb)(struct super_block *sb, u64 *ofs); | 150 | struct page *(*find_first_sb)(struct super_block *sb, u64 *ofs); |
| @@ -153,6 +154,7 @@ struct logfs_device_ops { | |||
| 153 | void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); | 154 | void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); |
| 154 | int (*erase)(struct super_block *sb, loff_t ofs, size_t len, | 155 | int (*erase)(struct super_block *sb, loff_t ofs, size_t len, |
| 155 | int ensure_write); | 156 | int ensure_write); |
| 157 | int (*can_write_buf)(struct super_block *sb, u64 ofs); | ||
| 156 | void (*sync)(struct super_block *sb); | 158 | void (*sync)(struct super_block *sb); |
| 157 | void (*put_device)(struct super_block *sb); | 159 | void (*put_device)(struct super_block *sb); |
| 158 | }; | 160 | }; |
| @@ -394,6 +396,7 @@ struct logfs_super { | |||
| 394 | int s_lock_count; | 396 | int s_lock_count; |
| 395 | mempool_t *s_block_pool; /* struct logfs_block pool */ | 397 | mempool_t *s_block_pool; /* struct logfs_block pool */ |
| 396 | mempool_t *s_shadow_pool; /* struct logfs_shadow pool */ | 398 | mempool_t *s_shadow_pool; /* struct logfs_shadow pool */ |
| 399 | struct list_head s_writeback_list; /* writeback pages */ | ||
| 397 | /* | 400 | /* |
| 398 | * Space accounting: | 401 | * Space accounting: |
| 399 | * - s_used_bytes specifies space used to store valid data objects. | 402 | * - s_used_bytes specifies space used to store valid data objects. |
| @@ -598,19 +601,19 @@ void freeseg(struct super_block *sb, u32 segno); | |||
| 598 | int logfs_init_areas(struct super_block *sb); | 601 | int logfs_init_areas(struct super_block *sb); |
| 599 | void logfs_cleanup_areas(struct super_block *sb); | 602 | void logfs_cleanup_areas(struct super_block *sb); |
| 600 | int logfs_open_area(struct logfs_area *area, size_t bytes); | 603 | int logfs_open_area(struct logfs_area *area, size_t bytes); |
| 601 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | 604 | int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, |
| 602 | int use_filler); | 605 | int use_filler); |
| 603 | 606 | ||
| 604 | static inline void logfs_buf_write(struct logfs_area *area, u64 ofs, | 607 | static inline int logfs_buf_write(struct logfs_area *area, u64 ofs, |
| 605 | void *buf, size_t len) | 608 | void *buf, size_t len) |
| 606 | { | 609 | { |
| 607 | __logfs_buf_write(area, ofs, buf, len, 0); | 610 | return __logfs_buf_write(area, ofs, buf, len, 0); |
| 608 | } | 611 | } |
| 609 | 612 | ||
| 610 | static inline void logfs_buf_recover(struct logfs_area *area, u64 ofs, | 613 | static inline int logfs_buf_recover(struct logfs_area *area, u64 ofs, |
| 611 | void *buf, size_t len) | 614 | void *buf, size_t len) |
| 612 | { | 615 | { |
| 613 | __logfs_buf_write(area, ofs, buf, len, 1); | 616 | return __logfs_buf_write(area, ofs, buf, len, 1); |
| 614 | } | 617 | } |
| 615 | 618 | ||
| 616 | /* super.c */ | 619 | /* super.c */ |
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 3159db6958e5..0718d112a1a5 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
| @@ -892,6 +892,8 @@ u64 logfs_seek_hole(struct inode *inode, u64 bix) | |||
| 892 | return bix; | 892 | return bix; |
| 893 | else if (li->li_data[INDIRECT_INDEX] & LOGFS_FULLY_POPULATED) | 893 | else if (li->li_data[INDIRECT_INDEX] & LOGFS_FULLY_POPULATED) |
| 894 | bix = maxbix(li->li_height); | 894 | bix = maxbix(li->li_height); |
| 895 | else if (bix >= maxbix(li->li_height)) | ||
| 896 | return bix; | ||
| 895 | else { | 897 | else { |
| 896 | bix = seek_holedata_loop(inode, bix, 0); | 898 | bix = seek_holedata_loop(inode, bix, 0); |
| 897 | if (bix < maxbix(li->li_height)) | 899 | if (bix < maxbix(li->li_height)) |
| @@ -1093,17 +1095,25 @@ static int logfs_reserve_bytes(struct inode *inode, int bytes) | |||
| 1093 | int get_page_reserve(struct inode *inode, struct page *page) | 1095 | int get_page_reserve(struct inode *inode, struct page *page) |
| 1094 | { | 1096 | { |
| 1095 | struct logfs_super *super = logfs_super(inode->i_sb); | 1097 | struct logfs_super *super = logfs_super(inode->i_sb); |
| 1098 | struct logfs_block *block = logfs_block(page); | ||
| 1096 | int ret; | 1099 | int ret; |
| 1097 | 1100 | ||
| 1098 | if (logfs_block(page) && logfs_block(page)->reserved_bytes) | 1101 | if (block && block->reserved_bytes) |
| 1099 | return 0; | 1102 | return 0; |
| 1100 | 1103 | ||
| 1101 | logfs_get_wblocks(inode->i_sb, page, WF_LOCK); | 1104 | logfs_get_wblocks(inode->i_sb, page, WF_LOCK); |
| 1102 | ret = logfs_reserve_bytes(inode, 6 * LOGFS_MAX_OBJECTSIZE); | 1105 | while ((ret = logfs_reserve_bytes(inode, 6 * LOGFS_MAX_OBJECTSIZE)) && |
| 1106 | !list_empty(&super->s_writeback_list)) { | ||
| 1107 | block = list_entry(super->s_writeback_list.next, | ||
| 1108 | struct logfs_block, alias_list); | ||
| 1109 | block->ops->write_block(block); | ||
| 1110 | } | ||
| 1103 | if (!ret) { | 1111 | if (!ret) { |
| 1104 | alloc_data_block(inode, page); | 1112 | alloc_data_block(inode, page); |
| 1105 | logfs_block(page)->reserved_bytes += 6 * LOGFS_MAX_OBJECTSIZE; | 1113 | block = logfs_block(page); |
| 1114 | block->reserved_bytes += 6 * LOGFS_MAX_OBJECTSIZE; | ||
| 1106 | super->s_dirty_pages += 6 * LOGFS_MAX_OBJECTSIZE; | 1115 | super->s_dirty_pages += 6 * LOGFS_MAX_OBJECTSIZE; |
| 1116 | list_move_tail(&block->alias_list, &super->s_writeback_list); | ||
| 1107 | } | 1117 | } |
| 1108 | logfs_put_wblocks(inode->i_sb, page, WF_LOCK); | 1118 | logfs_put_wblocks(inode->i_sb, page, WF_LOCK); |
| 1109 | return ret; | 1119 | return ret; |
| @@ -1861,7 +1871,7 @@ int logfs_truncate(struct inode *inode, u64 target) | |||
| 1861 | size = target; | 1871 | size = target; |
| 1862 | 1872 | ||
| 1863 | logfs_get_wblocks(sb, NULL, 1); | 1873 | logfs_get_wblocks(sb, NULL, 1); |
| 1864 | err = __logfs_truncate(inode, target); | 1874 | err = __logfs_truncate(inode, size); |
| 1865 | if (!err) | 1875 | if (!err) |
| 1866 | err = __logfs_write_inode(inode, 0); | 1876 | err = __logfs_write_inode(inode, 0); |
| 1867 | logfs_put_wblocks(sb, NULL, 1); | 1877 | logfs_put_wblocks(sb, NULL, 1); |
| @@ -2249,6 +2259,7 @@ int logfs_init_rw(struct super_block *sb) | |||
| 2249 | int min_fill = 3 * super->s_no_blocks; | 2259 | int min_fill = 3 * super->s_no_blocks; |
| 2250 | 2260 | ||
| 2251 | INIT_LIST_HEAD(&super->s_object_alias); | 2261 | INIT_LIST_HEAD(&super->s_object_alias); |
| 2262 | INIT_LIST_HEAD(&super->s_writeback_list); | ||
| 2252 | mutex_init(&super->s_write_mutex); | 2263 | mutex_init(&super->s_write_mutex); |
| 2253 | super->s_block_pool = mempool_create_kmalloc_pool(min_fill, | 2264 | super->s_block_pool = mempool_create_kmalloc_pool(min_fill, |
| 2254 | sizeof(struct logfs_block)); | 2265 | sizeof(struct logfs_block)); |
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index f77ce2b470ba..a9657afb70ad 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c | |||
| @@ -67,7 +67,7 @@ static struct page *get_mapping_page(struct super_block *sb, pgoff_t index, | |||
| 67 | return page; | 67 | return page; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | 70 | int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, |
| 71 | int use_filler) | 71 | int use_filler) |
| 72 | { | 72 | { |
| 73 | pgoff_t index = ofs >> PAGE_SHIFT; | 73 | pgoff_t index = ofs >> PAGE_SHIFT; |
| @@ -81,8 +81,10 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | |||
| 81 | copylen = min((ulong)len, PAGE_SIZE - offset); | 81 | copylen = min((ulong)len, PAGE_SIZE - offset); |
| 82 | 82 | ||
| 83 | page = get_mapping_page(area->a_sb, index, use_filler); | 83 | page = get_mapping_page(area->a_sb, index, use_filler); |
| 84 | SetPageUptodate(page); | 84 | if (IS_ERR(page)) |
| 85 | return PTR_ERR(page); | ||
| 85 | BUG_ON(!page); /* FIXME: reserve a pool */ | 86 | BUG_ON(!page); /* FIXME: reserve a pool */ |
| 87 | SetPageUptodate(page); | ||
| 86 | memcpy(page_address(page) + offset, buf, copylen); | 88 | memcpy(page_address(page) + offset, buf, copylen); |
| 87 | SetPagePrivate(page); | 89 | SetPagePrivate(page); |
| 88 | page_cache_release(page); | 90 | page_cache_release(page); |
| @@ -92,6 +94,7 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | |||
| 92 | offset = 0; | 94 | offset = 0; |
| 93 | index++; | 95 | index++; |
| 94 | } while (len); | 96 | } while (len); |
| 97 | return 0; | ||
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | static void pad_partial_page(struct logfs_area *area) | 100 | static void pad_partial_page(struct logfs_area *area) |
diff --git a/fs/logfs/super.c b/fs/logfs/super.c index d7c23ed8349a..d651e10a1e9c 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c | |||
| @@ -138,10 +138,14 @@ static int logfs_sb_set(struct super_block *sb, void *_super) | |||
| 138 | sb->s_fs_info = super; | 138 | sb->s_fs_info = super; |
| 139 | sb->s_mtd = super->s_mtd; | 139 | sb->s_mtd = super->s_mtd; |
| 140 | sb->s_bdev = super->s_bdev; | 140 | sb->s_bdev = super->s_bdev; |
| 141 | #ifdef CONFIG_BLOCK | ||
| 141 | if (sb->s_bdev) | 142 | if (sb->s_bdev) |
| 142 | sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info; | 143 | sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info; |
| 144 | #endif | ||
| 145 | #ifdef CONFIG_MTD | ||
| 143 | if (sb->s_mtd) | 146 | if (sb->s_mtd) |
| 144 | sb->s_bdi = sb->s_mtd->backing_dev_info; | 147 | sb->s_bdi = sb->s_mtd->backing_dev_info; |
| 148 | #endif | ||
| 145 | return 0; | 149 | return 0; |
| 146 | } | 150 | } |
| 147 | 151 | ||
| @@ -382,7 +386,7 @@ static struct page *find_super_block(struct super_block *sb) | |||
| 382 | if (!first || IS_ERR(first)) | 386 | if (!first || IS_ERR(first)) |
| 383 | return NULL; | 387 | return NULL; |
| 384 | last = super->s_devops->find_last_sb(sb, &super->s_sb_ofs[1]); | 388 | last = super->s_devops->find_last_sb(sb, &super->s_sb_ofs[1]); |
| 385 | if (!last || IS_ERR(first)) { | 389 | if (!last || IS_ERR(last)) { |
| 386 | page_cache_release(first); | 390 | page_cache_release(first); |
| 387 | return NULL; | 391 | return NULL; |
| 388 | } | 392 | } |
| @@ -413,7 +417,7 @@ static int __logfs_read_sb(struct super_block *sb) | |||
| 413 | 417 | ||
| 414 | page = find_super_block(sb); | 418 | page = find_super_block(sb); |
| 415 | if (!page) | 419 | if (!page) |
| 416 | return -EIO; | 420 | return -EINVAL; |
| 417 | 421 | ||
| 418 | ds = page_address(page); | 422 | ds = page_address(page); |
| 419 | super->s_size = be64_to_cpu(ds->ds_filesystem_size); | 423 | super->s_size = be64_to_cpu(ds->ds_filesystem_size); |
