aboutsummaryrefslogtreecommitdiffstats
path: root/fs/logfs/dev_bdev.c
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/logfs/dev_bdev.c
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/logfs/dev_bdev.c')
-rw-r--r--fs/logfs/dev_bdev.c88
1 files changed, 76 insertions, 12 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