Blame view

fs/logfs/dev_bdev.c 7.76 KB
5db53f3e8   Joern Engel   [LogFS] add new f...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * fs/logfs/dev_bdev.c	- Device access methods for block devices
   *
   * As should be obvious for Linux kernel code, license is GPLv2
   *
   * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org>
   */
  #include "logfs.h"
  #include <linux/bio.h>
  #include <linux/blkdev.h>
  #include <linux/buffer_head.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/gfp.h>
268bb0ce3   Linus Torvalds   sanitize <linux/p...
13
  #include <linux/prefetch.h>
5db53f3e8   Joern Engel   [LogFS] add new f...
14
15
  
  #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1))
95fe6c1a2   Mike Christie   block, fs, mm, dr...
16
  static int sync_request(struct page *page, struct block_device *bdev, int op)
5db53f3e8   Joern Engel   [LogFS] add new f...
17
18
19
  {
  	struct bio bio;
  	struct bio_vec bio_vec;
5db53f3e8   Joern Engel   [LogFS] add new f...
20
21
  
  	bio_init(&bio);
cd8bfa9c8   Prasad Joshi   logfs: initialize...
22
  	bio.bi_max_vecs = 1;
5db53f3e8   Joern Engel   [LogFS] add new f...
23
24
25
26
27
  	bio.bi_io_vec = &bio_vec;
  	bio_vec.bv_page = page;
  	bio_vec.bv_len = PAGE_SIZE;
  	bio_vec.bv_offset = 0;
  	bio.bi_vcnt = 1;
5db53f3e8   Joern Engel   [LogFS] add new f...
28
  	bio.bi_bdev = bdev;
4f024f379   Kent Overstreet   block: Abstract o...
29
30
  	bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9);
  	bio.bi_iter.bi_size = PAGE_SIZE;
95fe6c1a2   Mike Christie   block, fs, mm, dr...
31
  	bio_set_op_attrs(&bio, op, 0);
5db53f3e8   Joern Engel   [LogFS] add new f...
32

4e49ea4a3   Mike Christie   block/fs/drivers:...
33
  	return submit_bio_wait(&bio);
5db53f3e8   Joern Engel   [LogFS] add new f...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  }
  
  static int bdev_readpage(void *_sb, struct page *page)
  {
  	struct super_block *sb = _sb;
  	struct block_device *bdev = logfs_super(sb)->s_bdev;
  	int err;
  
  	err = sync_request(page, bdev, READ);
  	if (err) {
  		ClearPageUptodate(page);
  		SetPageError(page);
  	} else {
  		SetPageUptodate(page);
  		ClearPageError(page);
  	}
  	unlock_page(page);
  	return err;
  }
  
  static DECLARE_WAIT_QUEUE_HEAD(wq);
4246a0b63   Christoph Hellwig   block: add a bi_e...
55
  static void writeseg_end_io(struct bio *bio)
5db53f3e8   Joern Engel   [LogFS] add new f...
56
  {
2c30c71bd   Kent Overstreet   block: Convert va...
57
58
  	struct bio_vec *bvec;
  	int i;
5db53f3e8   Joern Engel   [LogFS] add new f...
59
60
  	struct super_block *sb = bio->bi_private;
  	struct logfs_super *super = logfs_super(sb);
5db53f3e8   Joern Engel   [LogFS] add new f...
61

4246a0b63   Christoph Hellwig   block: add a bi_e...
62
  	BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */
5db53f3e8   Joern Engel   [LogFS] add new f...
63

2c30c71bd   Kent Overstreet   block: Convert va...
64
65
  	bio_for_each_segment_all(bvec, bio, i) {
  		end_page_writeback(bvec->bv_page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
66
  		put_page(bvec->bv_page);
2c30c71bd   Kent Overstreet   block: Convert va...
67
  	}
5db53f3e8   Joern Engel   [LogFS] add new f...
68
69
70
71
72
73
74
75
76
77
78
79
  	bio_put(bio);
  	if (atomic_dec_and_test(&super->s_pending_writes))
  		wake_up(&wq);
  }
  
  static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index,
  		size_t nr_pages)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct address_space *mapping = super->s_mapping_inode->i_mapping;
  	struct bio *bio;
  	struct page *page;
9f0bbd8ca   Prasad Joshi   logfs: query bloc...
80
  	unsigned int max_pages;
5db53f3e8   Joern Engel   [LogFS] add new f...
81
  	int i;
ce4f2fd7e   Sudip Mukherjee   logfs: fix build ...
82
  	max_pages = min_t(size_t, nr_pages, BIO_MAX_PAGES);
9f0bbd8ca   Prasad Joshi   logfs: query bloc...
83

5db53f3e8   Joern Engel   [LogFS] add new f...
84
  	bio = bio_alloc(GFP_NOFS, max_pages);
59fe27c0a   Joern Engel   Limit max_pages f...
85
  	BUG_ON(!bio);
5db53f3e8   Joern Engel   [LogFS] add new f...
86
87
88
89
90
  
  	for (i = 0; i < nr_pages; i++) {
  		if (i >= max_pages) {
  			/* Block layer cannot split bios :( */
  			bio->bi_vcnt = i;
4f024f379   Kent Overstreet   block: Abstract o...
91
  			bio->bi_iter.bi_size = i * PAGE_SIZE;
5db53f3e8   Joern Engel   [LogFS] add new f...
92
  			bio->bi_bdev = super->s_bdev;
4f024f379   Kent Overstreet   block: Abstract o...
93
  			bio->bi_iter.bi_sector = ofs >> 9;
5db53f3e8   Joern Engel   [LogFS] add new f...
94
95
  			bio->bi_private = sb;
  			bio->bi_end_io = writeseg_end_io;
95fe6c1a2   Mike Christie   block, fs, mm, dr...
96
  			bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
5db53f3e8   Joern Engel   [LogFS] add new f...
97
  			atomic_inc(&super->s_pending_writes);
4e49ea4a3   Mike Christie   block/fs/drivers:...
98
  			submit_bio(bio);
5db53f3e8   Joern Engel   [LogFS] add new f...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  
  			ofs += i * PAGE_SIZE;
  			index += i;
  			nr_pages -= i;
  			i = 0;
  
  			bio = bio_alloc(GFP_NOFS, max_pages);
  			BUG_ON(!bio);
  		}
  		page = find_lock_page(mapping, index + i);
  		BUG_ON(!page);
  		bio->bi_io_vec[i].bv_page = page;
  		bio->bi_io_vec[i].bv_len = PAGE_SIZE;
  		bio->bi_io_vec[i].bv_offset = 0;
  
  		BUG_ON(PageWriteback(page));
  		set_page_writeback(page);
  		unlock_page(page);
  	}
  	bio->bi_vcnt = nr_pages;
4f024f379   Kent Overstreet   block: Abstract o...
119
  	bio->bi_iter.bi_size = nr_pages * PAGE_SIZE;
5db53f3e8   Joern Engel   [LogFS] add new f...
120
  	bio->bi_bdev = super->s_bdev;
4f024f379   Kent Overstreet   block: Abstract o...
121
  	bio->bi_iter.bi_sector = ofs >> 9;
5db53f3e8   Joern Engel   [LogFS] add new f...
122
123
  	bio->bi_private = sb;
  	bio->bi_end_io = writeseg_end_io;
95fe6c1a2   Mike Christie   block, fs, mm, dr...
124
  	bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
5db53f3e8   Joern Engel   [LogFS] add new f...
125
  	atomic_inc(&super->s_pending_writes);
4e49ea4a3   Mike Christie   block/fs/drivers:...
126
  	submit_bio(bio);
5db53f3e8   Joern Engel   [LogFS] add new f...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  	return 0;
  }
  
  static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len)
  {
  	struct logfs_super *super = logfs_super(sb);
  	int head;
  
  	BUG_ON(super->s_flags & LOGFS_SB_FLAG_RO);
  
  	if (len == 0) {
  		/* This can happen when the object fit perfectly into a
  		 * segment, the segment gets written per sync and subsequently
  		 * closed.
  		 */
  		return;
  	}
  	head = ofs & (PAGE_SIZE - 1);
  	if (head) {
  		ofs -= head;
  		len += head;
  	}
  	len = PAGE_ALIGN(len);
  	__bdev_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT);
5db53f3e8   Joern Engel   [LogFS] add new f...
151
  }
9421502b4   Joern Engel   [LogFS] Fix bdev ...
152

4246a0b63   Christoph Hellwig   block: add a bi_e...
153
  static void erase_end_io(struct bio *bio)
9421502b4   Joern Engel   [LogFS] Fix bdev ...
154
  { 
9421502b4   Joern Engel   [LogFS] Fix bdev ...
155
156
  	struct super_block *sb = bio->bi_private; 
  	struct logfs_super *super = logfs_super(sb); 
4246a0b63   Christoph Hellwig   block: add a bi_e...
157
  	BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ 
9421502b4   Joern Engel   [LogFS] Fix bdev ...
158
159
160
161
162
163
164
165
166
167
168
  	BUG_ON(bio->bi_vcnt == 0); 
  	bio_put(bio); 
  	if (atomic_dec_and_test(&super->s_pending_writes))
  		wake_up(&wq); 
  } 
  
  static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
  		size_t nr_pages)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct bio *bio;
9f0bbd8ca   Prasad Joshi   logfs: query bloc...
169
  	unsigned int max_pages;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
170
  	int i;
ce4f2fd7e   Sudip Mukherjee   logfs: fix build ...
171
  	max_pages = min_t(size_t, nr_pages, BIO_MAX_PAGES);
9f0bbd8ca   Prasad Joshi   logfs: query bloc...
172

9421502b4   Joern Engel   [LogFS] Fix bdev ...
173
  	bio = bio_alloc(GFP_NOFS, max_pages);
59fe27c0a   Joern Engel   Limit max_pages f...
174
  	BUG_ON(!bio);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
175
176
177
178
179
  
  	for (i = 0; i < nr_pages; i++) {
  		if (i >= max_pages) {
  			/* Block layer cannot split bios :( */
  			bio->bi_vcnt = i;
4f024f379   Kent Overstreet   block: Abstract o...
180
  			bio->bi_iter.bi_size = i * PAGE_SIZE;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
181
  			bio->bi_bdev = super->s_bdev;
4f024f379   Kent Overstreet   block: Abstract o...
182
  			bio->bi_iter.bi_sector = ofs >> 9;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
183
184
  			bio->bi_private = sb;
  			bio->bi_end_io = erase_end_io;
95fe6c1a2   Mike Christie   block, fs, mm, dr...
185
  			bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
186
  			atomic_inc(&super->s_pending_writes);
4e49ea4a3   Mike Christie   block/fs/drivers:...
187
  			submit_bio(bio);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  
  			ofs += i * PAGE_SIZE;
  			index += i;
  			nr_pages -= i;
  			i = 0;
  
  			bio = bio_alloc(GFP_NOFS, max_pages);
  			BUG_ON(!bio);
  		}
  		bio->bi_io_vec[i].bv_page = super->s_erase_page;
  		bio->bi_io_vec[i].bv_len = PAGE_SIZE;
  		bio->bi_io_vec[i].bv_offset = 0;
  	}
  	bio->bi_vcnt = nr_pages;
4f024f379   Kent Overstreet   block: Abstract o...
202
  	bio->bi_iter.bi_size = nr_pages * PAGE_SIZE;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
203
  	bio->bi_bdev = super->s_bdev;
4f024f379   Kent Overstreet   block: Abstract o...
204
  	bio->bi_iter.bi_sector = ofs >> 9;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
205
206
  	bio->bi_private = sb;
  	bio->bi_end_io = erase_end_io;
95fe6c1a2   Mike Christie   block, fs, mm, dr...
207
  	bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
208
  	atomic_inc(&super->s_pending_writes);
4e49ea4a3   Mike Christie   block/fs/drivers:...
209
  	submit_bio(bio);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
210
211
212
213
214
  	return 0;
  }
  
  static int bdev_erase(struct super_block *sb, loff_t to, size_t len,
  		int ensure_write)
5db53f3e8   Joern Engel   [LogFS] add new f...
215
216
  {
  	struct logfs_super *super = logfs_super(sb);
5db53f3e8   Joern Engel   [LogFS] add new f...
217
218
219
  
  	BUG_ON(to & (PAGE_SIZE - 1));
  	BUG_ON(len & (PAGE_SIZE - 1));
9421502b4   Joern Engel   [LogFS] Fix bdev ...
220
  	if (super->s_flags & LOGFS_SB_FLAG_RO)
5db53f3e8   Joern Engel   [LogFS] add new f...
221
  		return -EROFS;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
222
223
224
225
226
227
228
229
  	if (ensure_write) {
  		/*
  		 * Object store doesn't care whether erases happen or not.
  		 * But for the journal they are required.  Otherwise a scan
  		 * can find an old commit entry and assume it is the current
  		 * one, travelling back in time.
  		 */
  		do_erase(sb, to, to >> PAGE_SHIFT, len >> PAGE_SHIFT);
5db53f3e8   Joern Engel   [LogFS] add new f...
230
  	}
9421502b4   Joern Engel   [LogFS] Fix bdev ...
231

5db53f3e8   Joern Engel   [LogFS] add new f...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  	return 0;
  }
  
  static void bdev_sync(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  
  	wait_event(wq, atomic_read(&super->s_pending_writes) == 0);
  }
  
  static struct page *bdev_find_first_sb(struct super_block *sb, u64 *ofs)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct address_space *mapping = super->s_mapping_inode->i_mapping;
  	filler_t *filler = bdev_readpage;
  
  	*ofs = 0;
  	return read_cache_page(mapping, 0, filler, sb);
  }
  
  static struct page *bdev_find_last_sb(struct super_block *sb, u64 *ofs)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct address_space *mapping = super->s_mapping_inode->i_mapping;
  	filler_t *filler = bdev_readpage;
  	u64 pos = (super->s_bdev->bd_inode->i_size & ~0xfffULL) - 0x1000;
  	pgoff_t index = pos >> PAGE_SHIFT;
  
  	*ofs = pos;
  	return read_cache_page(mapping, index, filler, sb);
  }
  
  static int bdev_write_sb(struct super_block *sb, struct page *page)
  {
  	struct block_device *bdev = logfs_super(sb)->s_bdev;
  
  	/* Nothing special to do for block devices. */
  	return sync_request(page, bdev, WRITE);
  }
e5a0726a9   Al Viro   logfs: fix a leak...
271
  static void bdev_put_device(struct logfs_super *s)
5db53f3e8   Joern Engel   [LogFS] add new f...
272
  {
e525fd89d   Tejun Heo   block: make blkde...
273
  	blkdev_put(s->s_bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
5db53f3e8   Joern Engel   [LogFS] add new f...
274
  }
6f485b418   Joern Engel   logfs: handle pow...
275
276
277
278
  static int bdev_can_write_buf(struct super_block *sb, u64 ofs)
  {
  	return 0;
  }
5db53f3e8   Joern Engel   [LogFS] add new f...
279
280
281
282
283
284
285
  static const struct logfs_device_ops bd_devops = {
  	.find_first_sb	= bdev_find_first_sb,
  	.find_last_sb	= bdev_find_last_sb,
  	.write_sb	= bdev_write_sb,
  	.readpage	= bdev_readpage,
  	.writeseg	= bdev_writeseg,
  	.erase		= bdev_erase,
6f485b418   Joern Engel   logfs: handle pow...
286
  	.can_write_buf	= bdev_can_write_buf,
5db53f3e8   Joern Engel   [LogFS] add new f...
287
288
289
  	.sync		= bdev_sync,
  	.put_device	= bdev_put_device,
  };
7d945a3aa   Al Viro   logfs get_sb, part 3
290
291
  int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type,
  		const char *devname)
5db53f3e8   Joern Engel   [LogFS] add new f...
292
293
  {
  	struct block_device *bdev;
d4d776299   Tejun Heo   block: clean up b...
294
295
  	bdev = blkdev_get_by_path(devname, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
  				  type);
7d945a3aa   Al Viro   logfs get_sb, part 3
296
  	if (IS_ERR(bdev))
5db53f3e8   Joern Engel   [LogFS] add new f...
297
298
299
300
  		return PTR_ERR(bdev);
  
  	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
  		int mtdnr = MINOR(bdev->bd_dev);
e525fd89d   Tejun Heo   block: make blkde...
301
  		blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
7d945a3aa   Al Viro   logfs get_sb, part 3
302
  		return logfs_get_sb_mtd(p, mtdnr);
5db53f3e8   Joern Engel   [LogFS] add new f...
303
  	}
0d85c7996   Al Viro   logfs get_sb, part 2
304
305
306
  	p->s_bdev = bdev;
  	p->s_mtd = NULL;
  	p->s_devops = &bd_devops;
7d945a3aa   Al Viro   logfs get_sb, part 3
307
  	return 0;
5db53f3e8   Joern Engel   [LogFS] add new f...
308
  }