diff options
Diffstat (limited to 'fs/logfs/dev_bdev.c')
-rw-r--r-- | fs/logfs/dev_bdev.c | 88 |
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 | ||
170 | static int bdev_erase(struct super_block *sb, loff_t to, size_t len) | 170 | |
171 | static 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 | |||
185 | static 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 | |||
234 | static 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 | ||