blob: 9bfa0151d7c9048610becc95c2e02508fe2e6f25 [file] [log] [blame]
Joern Engel5db53f32009-11-20 20:13:39 +01001/*
2 * fs/logfs/dev_bdev.c - Device access methods for block devices
3 *
4 * As should be obvious for Linux kernel code, license is GPLv2
5 *
6 * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org>
7 */
8#include "logfs.h"
9#include <linux/bio.h>
10#include <linux/blkdev.h>
11#include <linux/buffer_head.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/gfp.h>
Linus Torvalds268bb0c2011-05-20 12:50:29 -070013#include <linux/prefetch.h>
Joern Engel5db53f32009-11-20 20:13:39 +010014
15#define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1))
16
Mike Christie95fe6c12016-06-05 14:31:48 -050017static int sync_request(struct page *page, struct block_device *bdev, int op)
Joern Engel5db53f32009-11-20 20:13:39 +010018{
19 struct bio bio;
20 struct bio_vec bio_vec;
Joern Engel5db53f32009-11-20 20:13:39 +010021
Ming Lei3a83f462016-11-22 08:57:21 -070022 bio_init(&bio, &bio_vec, 1);
Joern Engel5db53f32009-11-20 20:13:39 +010023 bio.bi_bdev = bdev;
Ming Lei739a9972016-11-11 20:05:37 +080024 bio_add_page(&bio, page, PAGE_SIZE, 0);
Kent Overstreet4f024f32013-10-11 15:44:27 -070025 bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9);
Mike Christie95fe6c12016-06-05 14:31:48 -050026 bio_set_op_attrs(&bio, op, 0);
Joern Engel5db53f32009-11-20 20:13:39 +010027
Mike Christie4e49ea42016-06-05 14:31:41 -050028 return submit_bio_wait(&bio);
Joern Engel5db53f32009-11-20 20:13:39 +010029}
30
31static int bdev_readpage(void *_sb, struct page *page)
32{
33 struct super_block *sb = _sb;
34 struct block_device *bdev = logfs_super(sb)->s_bdev;
35 int err;
36
37 err = sync_request(page, bdev, READ);
38 if (err) {
39 ClearPageUptodate(page);
40 SetPageError(page);
41 } else {
42 SetPageUptodate(page);
43 ClearPageError(page);
44 }
45 unlock_page(page);
46 return err;
47}
48
49static DECLARE_WAIT_QUEUE_HEAD(wq);
50
Christoph Hellwig4246a0b2015-07-20 15:29:37 +020051static void writeseg_end_io(struct bio *bio)
Joern Engel5db53f32009-11-20 20:13:39 +010052{
Kent Overstreet2c30c712013-11-07 12:20:26 -080053 struct bio_vec *bvec;
54 int i;
Joern Engel5db53f32009-11-20 20:13:39 +010055 struct super_block *sb = bio->bi_private;
56 struct logfs_super *super = logfs_super(sb);
Joern Engel5db53f32009-11-20 20:13:39 +010057
Christoph Hellwig4246a0b2015-07-20 15:29:37 +020058 BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */
Joern Engel5db53f32009-11-20 20:13:39 +010059
Kent Overstreet2c30c712013-11-07 12:20:26 -080060 bio_for_each_segment_all(bvec, bio, i) {
61 end_page_writeback(bvec->bv_page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +030062 put_page(bvec->bv_page);
Kent Overstreet2c30c712013-11-07 12:20:26 -080063 }
Joern Engel5db53f32009-11-20 20:13:39 +010064 bio_put(bio);
65 if (atomic_dec_and_test(&super->s_pending_writes))
66 wake_up(&wq);
67}
68
69static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index,
70 size_t nr_pages)
71{
72 struct logfs_super *super = logfs_super(sb);
73 struct address_space *mapping = super->s_mapping_inode->i_mapping;
Ming Leid4f98a82016-11-11 20:05:38 +080074 struct bio *bio = NULL;
Joern Engel5db53f32009-11-20 20:13:39 +010075 struct page *page;
Prasad Joshi9f0bbd82012-07-23 10:32:11 +053076 unsigned int max_pages;
Ming Leid4f98a82016-11-11 20:05:38 +080077 int i, ret;
Joern Engel5db53f32009-11-20 20:13:39 +010078
Sudip Mukherjeece4f2fd2015-11-05 18:43:49 -080079 max_pages = min_t(size_t, nr_pages, BIO_MAX_PAGES);
Prasad Joshi9f0bbd82012-07-23 10:32:11 +053080
Joern Engel5db53f32009-11-20 20:13:39 +010081 for (i = 0; i < nr_pages; i++) {
Ming Leid4f98a82016-11-11 20:05:38 +080082 if (!bio) {
83 bio = bio_alloc(GFP_NOFS, max_pages);
84 BUG_ON(!bio);
85
Joern Engel5db53f32009-11-20 20:13:39 +010086 bio->bi_bdev = super->s_bdev;
Kent Overstreet4f024f32013-10-11 15:44:27 -070087 bio->bi_iter.bi_sector = ofs >> 9;
Joern Engel5db53f32009-11-20 20:13:39 +010088 bio->bi_private = sb;
89 bio->bi_end_io = writeseg_end_io;
Mike Christie95fe6c12016-06-05 14:31:48 -050090 bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
Joern Engel5db53f32009-11-20 20:13:39 +010091 }
92 page = find_lock_page(mapping, index + i);
93 BUG_ON(!page);
Ming Leid4f98a82016-11-11 20:05:38 +080094 ret = bio_add_page(bio, page, PAGE_SIZE, 0);
Joern Engel5db53f32009-11-20 20:13:39 +010095
96 BUG_ON(PageWriteback(page));
97 set_page_writeback(page);
98 unlock_page(page);
Ming Leid4f98a82016-11-11 20:05:38 +080099
100 if (!ret) {
101 /* Block layer cannot split bios :( */
102 ofs += bio->bi_iter.bi_size;
103 atomic_inc(&super->s_pending_writes);
104 submit_bio(bio);
105 bio = NULL;
106 }
Joern Engel5db53f32009-11-20 20:13:39 +0100107 }
Ming Leid4f98a82016-11-11 20:05:38 +0800108
109 if (bio) {
110 atomic_inc(&super->s_pending_writes);
111 submit_bio(bio);
112 }
Joern Engel5db53f32009-11-20 20:13:39 +0100113 return 0;
114}
115
116static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len)
117{
118 struct logfs_super *super = logfs_super(sb);
119 int head;
120
121 BUG_ON(super->s_flags & LOGFS_SB_FLAG_RO);
122
123 if (len == 0) {
124 /* This can happen when the object fit perfectly into a
125 * segment, the segment gets written per sync and subsequently
126 * closed.
127 */
128 return;
129 }
130 head = ofs & (PAGE_SIZE - 1);
131 if (head) {
132 ofs -= head;
133 len += head;
134 }
135 len = PAGE_ALIGN(len);
136 __bdev_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT);
Joern Engel5db53f32009-11-20 20:13:39 +0100137}
138
Joern Engel94215022010-03-04 21:30:58 +0100139
Christoph Hellwig4246a0b2015-07-20 15:29:37 +0200140static void erase_end_io(struct bio *bio)
Joern Engel94215022010-03-04 21:30:58 +0100141{
Joern Engel94215022010-03-04 21:30:58 +0100142 struct super_block *sb = bio->bi_private;
143 struct logfs_super *super = logfs_super(sb);
144
Christoph Hellwig4246a0b2015-07-20 15:29:37 +0200145 BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */
Joern Engel94215022010-03-04 21:30:58 +0100146 bio_put(bio);
147 if (atomic_dec_and_test(&super->s_pending_writes))
148 wake_up(&wq);
149}
150
151static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
152 size_t nr_pages)
Joern Engel5db53f32009-11-20 20:13:39 +0100153{
154 struct logfs_super *super = logfs_super(sb);
Ming Leic1248432016-11-11 20:05:39 +0800155 struct bio *bio = NULL;
Prasad Joshi9f0bbd82012-07-23 10:32:11 +0530156 unsigned int max_pages;
Ming Leic1248432016-11-11 20:05:39 +0800157 int i, ret;
Joern Engel94215022010-03-04 21:30:58 +0100158
Sudip Mukherjeece4f2fd2015-11-05 18:43:49 -0800159 max_pages = min_t(size_t, nr_pages, BIO_MAX_PAGES);
Prasad Joshi9f0bbd82012-07-23 10:32:11 +0530160
Joern Engel94215022010-03-04 21:30:58 +0100161 for (i = 0; i < nr_pages; i++) {
Ming Leic1248432016-11-11 20:05:39 +0800162 if (!bio) {
163 bio = bio_alloc(GFP_NOFS, max_pages);
164 BUG_ON(!bio);
165
Joern Engel94215022010-03-04 21:30:58 +0100166 bio->bi_bdev = super->s_bdev;
Kent Overstreet4f024f32013-10-11 15:44:27 -0700167 bio->bi_iter.bi_sector = ofs >> 9;
Joern Engel94215022010-03-04 21:30:58 +0100168 bio->bi_private = sb;
169 bio->bi_end_io = erase_end_io;
Mike Christie95fe6c12016-06-05 14:31:48 -0500170 bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
Ming Leic1248432016-11-11 20:05:39 +0800171 }
172 ret = bio_add_page(bio, super->s_erase_page, PAGE_SIZE, 0);
173 if (!ret) {
174 /* Block layer cannot split bios :( */
175 ofs += bio->bi_iter.bi_size;
Joern Engel94215022010-03-04 21:30:58 +0100176 atomic_inc(&super->s_pending_writes);
Mike Christie4e49ea42016-06-05 14:31:41 -0500177 submit_bio(bio);
Joern Engel94215022010-03-04 21:30:58 +0100178 }
Joern Engel94215022010-03-04 21:30:58 +0100179 }
Ming Leic1248432016-11-11 20:05:39 +0800180 if (bio) {
181 atomic_inc(&super->s_pending_writes);
182 submit_bio(bio);
183 }
Joern Engel94215022010-03-04 21:30:58 +0100184 return 0;
185}
186
187static int bdev_erase(struct super_block *sb, loff_t to, size_t len,
188 int ensure_write)
189{
190 struct logfs_super *super = logfs_super(sb);
Joern Engel5db53f32009-11-20 20:13:39 +0100191
192 BUG_ON(to & (PAGE_SIZE - 1));
193 BUG_ON(len & (PAGE_SIZE - 1));
194
Joern Engel94215022010-03-04 21:30:58 +0100195 if (super->s_flags & LOGFS_SB_FLAG_RO)
Joern Engel5db53f32009-11-20 20:13:39 +0100196 return -EROFS;
197
Joern Engel94215022010-03-04 21:30:58 +0100198 if (ensure_write) {
199 /*
200 * Object store doesn't care whether erases happen or not.
201 * But for the journal they are required. Otherwise a scan
202 * can find an old commit entry and assume it is the current
203 * one, travelling back in time.
204 */
205 do_erase(sb, to, to >> PAGE_SHIFT, len >> PAGE_SHIFT);
Joern Engel5db53f32009-11-20 20:13:39 +0100206 }
Joern Engel94215022010-03-04 21:30:58 +0100207
Joern Engel5db53f32009-11-20 20:13:39 +0100208 return 0;
209}
210
211static void bdev_sync(struct super_block *sb)
212{
213 struct logfs_super *super = logfs_super(sb);
214
215 wait_event(wq, atomic_read(&super->s_pending_writes) == 0);
216}
217
218static struct page *bdev_find_first_sb(struct super_block *sb, u64 *ofs)
219{
220 struct logfs_super *super = logfs_super(sb);
221 struct address_space *mapping = super->s_mapping_inode->i_mapping;
222 filler_t *filler = bdev_readpage;
223
224 *ofs = 0;
225 return read_cache_page(mapping, 0, filler, sb);
226}
227
228static struct page *bdev_find_last_sb(struct super_block *sb, u64 *ofs)
229{
230 struct logfs_super *super = logfs_super(sb);
231 struct address_space *mapping = super->s_mapping_inode->i_mapping;
232 filler_t *filler = bdev_readpage;
233 u64 pos = (super->s_bdev->bd_inode->i_size & ~0xfffULL) - 0x1000;
234 pgoff_t index = pos >> PAGE_SHIFT;
235
236 *ofs = pos;
237 return read_cache_page(mapping, index, filler, sb);
238}
239
240static int bdev_write_sb(struct super_block *sb, struct page *page)
241{
242 struct block_device *bdev = logfs_super(sb)->s_bdev;
243
244 /* Nothing special to do for block devices. */
245 return sync_request(page, bdev, WRITE);
246}
247
Al Viroe5a07262010-07-26 12:06:00 +0400248static void bdev_put_device(struct logfs_super *s)
Joern Engel5db53f32009-11-20 20:13:39 +0100249{
Tejun Heoe525fd82010-11-13 11:55:17 +0100250 blkdev_put(s->s_bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
Joern Engel5db53f32009-11-20 20:13:39 +0100251}
252
Joern Engel6f485b412010-05-07 19:38:40 +0200253static int bdev_can_write_buf(struct super_block *sb, u64 ofs)
254{
255 return 0;
256}
257
Joern Engel5db53f32009-11-20 20:13:39 +0100258static const struct logfs_device_ops bd_devops = {
259 .find_first_sb = bdev_find_first_sb,
260 .find_last_sb = bdev_find_last_sb,
261 .write_sb = bdev_write_sb,
262 .readpage = bdev_readpage,
263 .writeseg = bdev_writeseg,
264 .erase = bdev_erase,
Joern Engel6f485b412010-05-07 19:38:40 +0200265 .can_write_buf = bdev_can_write_buf,
Joern Engel5db53f32009-11-20 20:13:39 +0100266 .sync = bdev_sync,
267 .put_device = bdev_put_device,
268};
269
Al Viro7d945a32010-07-26 11:53:30 +0400270int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type,
271 const char *devname)
Joern Engel5db53f32009-11-20 20:13:39 +0100272{
273 struct block_device *bdev;
274
Tejun Heod4d77622010-11-13 11:55:18 +0100275 bdev = blkdev_get_by_path(devname, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
276 type);
Al Viro7d945a32010-07-26 11:53:30 +0400277 if (IS_ERR(bdev))
Joern Engel5db53f32009-11-20 20:13:39 +0100278 return PTR_ERR(bdev);
279
280 if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
281 int mtdnr = MINOR(bdev->bd_dev);
Tejun Heoe525fd82010-11-13 11:55:17 +0100282 blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
Al Viro7d945a32010-07-26 11:53:30 +0400283 return logfs_get_sb_mtd(p, mtdnr);
Joern Engel5db53f32009-11-20 20:13:39 +0100284 }
285
Al Viro0d85c792010-07-26 11:33:39 +0400286 p->s_bdev = bdev;
287 p->s_mtd = NULL;
288 p->s_devops = &bd_devops;
Al Viro7d945a32010-07-26 11:53:30 +0400289 return 0;
Joern Engel5db53f32009-11-20 20:13:39 +0100290}