aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJoern Engel <joern@logfs.org>2010-03-04 15:30:58 -0500
committerJoern Engel <joern@logfs.org>2010-03-04 15:30:58 -0500
commit9421502b4fc894cc477be8fc49776830e37ca157 (patch)
tree9c9b1bfa42b2acdf4b5e080a256c3cd37852a94f /fs
parent5c564c2a04d4bb6ba79eeb83bd06de584479f362 (diff)
[LogFS] Fix bdev erases
Erases for block devices were always just emulated by writing 0xff. Some time back the write was removed and only the page cache was changed to 0xff. Superficialy a good idea with two problems: 1. Touching the page cache isn't necessary either. 2. However, writing out 0xff _is_ necessary for the journal. As the journal is scanned linearly, an old non-overwritten commit entry can be used on next mount and cause havoc. This should fix both aspects.
Diffstat (limited to 'fs')
-rw-r--r--fs/logfs/dev_bdev.c88
-rw-r--r--fs/logfs/dev_mtd.c3
-rw-r--r--fs/logfs/journal.c2
-rw-r--r--fs/logfs/logfs.h6
-rw-r--r--fs/logfs/segment.c6
-rw-r--r--fs/logfs/super.c12
6 files changed, 97 insertions, 20 deletions
diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c
index 58a057b6e1af..9718c22f186d 100644
--- a/fs/logfs/dev_bdev.c
+++ b/fs/logfs/dev_bdev.c
@@ -167,27 +167,91 @@ static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len)
167 generic_unplug_device(bdev_get_queue(logfs_super(sb)->s_bdev)); 167 generic_unplug_device(bdev_get_queue(logfs_super(sb)->s_bdev));
168} 168}
169 169
170static int bdev_erase(struct super_block *sb, loff_t to, size_t len) 170
171static void erase_end_io(struct bio *bio, int err)
172{
173 const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
174 struct super_block *sb = bio->bi_private;
175 struct logfs_super *super = logfs_super(sb);
176
177 BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */
178 BUG_ON(err);
179 BUG_ON(bio->bi_vcnt == 0);
180 bio_put(bio);
181 if (atomic_dec_and_test(&super->s_pending_writes))
182 wake_up(&wq);
183}
184
185static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
186 size_t nr_pages)
187{
188 struct logfs_super *super = logfs_super(sb);
189 struct bio *bio;
190 struct request_queue *q = bdev_get_queue(sb->s_bdev);
191 unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9);
192 int i;
193
194 bio = bio_alloc(GFP_NOFS, max_pages);
195 BUG_ON(!bio); /* FIXME: handle this */
196
197 for (i = 0; i < nr_pages; i++) {
198 if (i >= max_pages) {
199 /* Block layer cannot split bios :( */
200 bio->bi_vcnt = i;
201 bio->bi_idx = 0;
202 bio->bi_size = i * PAGE_SIZE;
203 bio->bi_bdev = super->s_bdev;
204 bio->bi_sector = ofs >> 9;
205 bio->bi_private = sb;
206 bio->bi_end_io = erase_end_io;
207 atomic_inc(&super->s_pending_writes);
208 submit_bio(WRITE, bio);
209
210 ofs += i * PAGE_SIZE;
211 index += i;
212 nr_pages -= i;
213 i = 0;
214
215 bio = bio_alloc(GFP_NOFS, max_pages);
216 BUG_ON(!bio);
217 }
218 bio->bi_io_vec[i].bv_page = super->s_erase_page;
219 bio->bi_io_vec[i].bv_len = PAGE_SIZE;
220 bio->bi_io_vec[i].bv_offset = 0;
221 }
222 bio->bi_vcnt = nr_pages;
223 bio->bi_idx = 0;
224 bio->bi_size = nr_pages * PAGE_SIZE;
225 bio->bi_bdev = super->s_bdev;
226 bio->bi_sector = ofs >> 9;
227 bio->bi_private = sb;
228 bio->bi_end_io = erase_end_io;
229 atomic_inc(&super->s_pending_writes);
230 submit_bio(WRITE, bio);
231 return 0;
232}
233
234static int bdev_erase(struct super_block *sb, loff_t to, size_t len,
235 int ensure_write)
171{ 236{
172 struct logfs_super *super = logfs_super(sb); 237 struct logfs_super *super = logfs_super(sb);
173 struct address_space *mapping = super->s_mapping_inode->i_mapping;
174 struct page *page;
175 pgoff_t index = to >> PAGE_SHIFT;
176 int i, nr_pages = len >> PAGE_SHIFT;
177 238
178 BUG_ON(to & (PAGE_SIZE - 1)); 239 BUG_ON(to & (PAGE_SIZE - 1));
179 BUG_ON(len & (PAGE_SIZE - 1)); 240 BUG_ON(len & (PAGE_SIZE - 1));
180 241
181 if (logfs_super(sb)->s_flags & LOGFS_SB_FLAG_RO) 242 if (super->s_flags & LOGFS_SB_FLAG_RO)
182 return -EROFS; 243 return -EROFS;
183 244
184 for (i = 0; i < nr_pages; i++) { 245 if (ensure_write) {
185 page = find_get_page(mapping, index + i); 246 /*
186 if (page) { 247 * Object store doesn't care whether erases happen or not.
187 memset(page_address(page), 0xFF, PAGE_SIZE); 248 * But for the journal they are required. Otherwise a scan
188 page_cache_release(page); 249 * can find an old commit entry and assume it is the current
189 } 250 * one, travelling back in time.
251 */
252 do_erase(sb, to, to >> PAGE_SHIFT, len >> PAGE_SHIFT);
190 } 253 }
254
191 return 0; 255 return 0;
192} 256}
193 257
diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c
index 68e99d046c23..cafb6ef2e05b 100644
--- a/fs/logfs/dev_mtd.c
+++ b/fs/logfs/dev_mtd.c
@@ -83,7 +83,8 @@ static int mtd_erase_mapping(struct super_block *sb, loff_t ofs, size_t len)
83 return 0; 83 return 0;
84} 84}
85 85
86static int mtd_erase(struct super_block *sb, loff_t ofs, size_t len) 86static int mtd_erase(struct super_block *sb, loff_t ofs, size_t len,
87 int ensure_write)
87{ 88{
88 struct mtd_info *mtd = logfs_super(sb)->s_mtd; 89 struct mtd_info *mtd = logfs_super(sb)->s_mtd;
89 struct erase_info ei; 90 struct erase_info ei;
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c
index 2f2e8e4fd02d..c0e7d63221d4 100644
--- a/fs/logfs/journal.c
+++ b/fs/logfs/journal.c
@@ -392,7 +392,7 @@ static int journal_erase_segment(struct logfs_area *area)
392 u64 ofs; 392 u64 ofs;
393 int err; 393 int err;
394 394
395 err = logfs_erase_segment(sb, area->a_segno); 395 err = logfs_erase_segment(sb, area->a_segno, 1);
396 if (err) 396 if (err)
397 return err; 397 return err;
398 398
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h
index e3082abe9e3b..72592114a28f 100644
--- a/fs/logfs/logfs.h
+++ b/fs/logfs/logfs.h
@@ -151,7 +151,8 @@ struct logfs_device_ops {
151 int (*write_sb)(struct super_block *sb, struct page *page); 151 int (*write_sb)(struct super_block *sb, struct page *page);
152 int (*readpage)(void *_sb, struct page *page); 152 int (*readpage)(void *_sb, struct page *page);
153 void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); 153 void (*writeseg)(struct super_block *sb, u64 ofs, size_t len);
154 int (*erase)(struct super_block *sb, loff_t ofs, size_t len); 154 int (*erase)(struct super_block *sb, loff_t ofs, size_t len,
155 int ensure_write);
155 void (*sync)(struct super_block *sb); 156 void (*sync)(struct super_block *sb);
156 void (*put_device)(struct super_block *sb); 157 void (*put_device)(struct super_block *sb);
157}; 158};
@@ -327,6 +328,7 @@ struct logfs_super {
327 u64 s_feature_compat; 328 u64 s_feature_compat;
328 u64 s_feature_flags; 329 u64 s_feature_flags;
329 u64 s_sb_ofs[2]; 330 u64 s_sb_ofs[2];
331 struct page *s_erase_page; /* for dev_bdev.c */
330 /* alias.c fields */ 332 /* alias.c fields */
331 struct btree_head32 s_segment_alias; /* remapped segments */ 333 struct btree_head32 s_segment_alias; /* remapped segments */
332 int s_no_object_aliases; 334 int s_no_object_aliases;
@@ -572,7 +574,7 @@ int get_page_reserve(struct inode *inode, struct page *page);
572extern struct logfs_block_ops indirect_block_ops; 574extern struct logfs_block_ops indirect_block_ops;
573 575
574/* segment.c */ 576/* segment.c */
575int logfs_erase_segment(struct super_block *sb, u32 ofs); 577int logfs_erase_segment(struct super_block *sb, u32 ofs, int ensure_erase);
576int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf); 578int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf);
577int logfs_segment_read(struct inode *inode, struct page *page, u64 ofs, u64 bix, 579int logfs_segment_read(struct inode *inode, struct page *page, u64 ofs, u64 bix,
578 level_t level); 580 level_t level);
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c
index 5f58b74516ca..664cd0dd3576 100644
--- a/fs/logfs/segment.c
+++ b/fs/logfs/segment.c
@@ -25,14 +25,14 @@ static int logfs_mark_segment_bad(struct super_block *sb, u32 segno)
25 return 0; 25 return 0;
26} 26}
27 27
28int logfs_erase_segment(struct super_block *sb, u32 segno) 28int logfs_erase_segment(struct super_block *sb, u32 segno, int ensure_erase)
29{ 29{
30 struct logfs_super *super = logfs_super(sb); 30 struct logfs_super *super = logfs_super(sb);
31 31
32 super->s_gec++; 32 super->s_gec++;
33 33
34 return super->s_devops->erase(sb, (u64)segno << super->s_segshift, 34 return super->s_devops->erase(sb, (u64)segno << super->s_segshift,
35 super->s_segsize); 35 super->s_segsize, ensure_erase);
36} 36}
37 37
38static s64 logfs_get_free_bytes(struct logfs_area *area, size_t bytes) 38static s64 logfs_get_free_bytes(struct logfs_area *area, size_t bytes)
@@ -798,7 +798,7 @@ static int ostore_erase_segment(struct logfs_area *area)
798 u64 ofs; 798 u64 ofs;
799 int err; 799 int err;
800 800
801 err = logfs_erase_segment(sb, area->a_segno); 801 err = logfs_erase_segment(sb, area->a_segno, 0);
802 if (err) 802 if (err)
803 return err; 803 return err;
804 804
diff --git a/fs/logfs/super.c b/fs/logfs/super.c
index d128a2c1c8d1..94d80f7ee7c2 100644
--- a/fs/logfs/super.c
+++ b/fs/logfs/super.c
@@ -317,6 +317,7 @@ static int logfs_make_writeable(struct super_block *sb)
317 317
318static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) 318static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt)
319{ 319{
320 struct logfs_super *super = logfs_super(sb);
320 struct inode *rootdir; 321 struct inode *rootdir;
321 int err; 322 int err;
322 323
@@ -329,15 +330,22 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt)
329 if (!sb->s_root) 330 if (!sb->s_root)
330 goto fail; 331 goto fail;
331 332
333 super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
334 if (!super->s_erase_page)
335 goto fail2;
336 memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE);
337
332 /* FIXME: check for read-only mounts */ 338 /* FIXME: check for read-only mounts */
333 err = logfs_make_writeable(sb); 339 err = logfs_make_writeable(sb);
334 if (err) 340 if (err)
335 goto fail2; 341 goto fail3;
336 342
337 log_super("LogFS: Finished mounting\n"); 343 log_super("LogFS: Finished mounting\n");
338 simple_set_mnt(mnt, sb); 344 simple_set_mnt(mnt, sb);
339 return 0; 345 return 0;
340 346
347fail3:
348 __free_page(super->s_erase_page);
341fail2: 349fail2:
342 iput(rootdir); 350 iput(rootdir);
343fail: 351fail:
@@ -498,6 +506,8 @@ static void logfs_kill_sb(struct super_block *sb)
498 logfs_cleanup_journal(sb); 506 logfs_cleanup_journal(sb);
499 logfs_cleanup_areas(sb); 507 logfs_cleanup_areas(sb);
500 logfs_cleanup_rw(sb); 508 logfs_cleanup_rw(sb);
509 if (super->s_erase_page)
510 __free_page(super->s_erase_page);
501 super->s_devops->put_device(sb); 511 super->s_devops->put_device(sb);
502 mempool_destroy(super->s_btree_pool); 512 mempool_destroy(super->s_btree_pool);
503 mempool_destroy(super->s_alias_pool); 513 mempool_destroy(super->s_alias_pool);