fs: Add sdfat
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / fs / sdfat / blkdev.c
1 /*
2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /************************************************************************/
19 /* */
20 /* PROJECT : exFAT & FAT12/16/32 File System */
21 /* FILE : blkdev.c */
22 /* PURPOSE : sdFAT Block Device Driver Glue Layer */
23 /* */
24 /*----------------------------------------------------------------------*/
25 /* NOTES */
26 /* */
27 /************************************************************************/
28
29 #include <linux/blkdev.h>
30 #include <linux/log2.h>
31 #include <linux/backing-dev.h>
32
33 #include "sdfat.h"
34
35 /*----------------------------------------------------------------------*/
36 /* Constant & Macro Definitions */
37 /*----------------------------------------------------------------------*/
38
39 /*----------------------------------------------------------------------*/
40 /* Global Variable Definitions */
41 /*----------------------------------------------------------------------*/
42
43 /*----------------------------------------------------------------------*/
44 /* Local Variable Definitions */
45 /*----------------------------------------------------------------------*/
46
47 /*----------------------------------------------------------------------*/
48 /* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY */
49 /************************************************************************/
50
51 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
52 /* EMPTY */
53 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) */
54 static struct backing_dev_info *inode_to_bdi(struct inode *bd_inode)
55 {
56 return bd_inode->i_mapping->backing_dev_info;
57 }
58 #endif
59
60 /*======================================================================*/
61 /* Function Definitions */
62 /*======================================================================*/
63 s32 bdev_open_dev(struct super_block *sb)
64 {
65 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
66
67 if (fsi->bd_opened)
68 return 0;
69
70 fsi->bd_opened = true;
71 return 0;
72 }
73
74 s32 bdev_close_dev(struct super_block *sb)
75 {
76 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
77
78 fsi->bd_opened = false;
79 return 0;
80 }
81
82 static inline s32 block_device_ejected(struct super_block *sb)
83 {
84 struct inode *bd_inode = sb->s_bdev->bd_inode;
85 struct backing_dev_info *bdi = inode_to_bdi(bd_inode);
86
87 return (bdi->dev == NULL);
88 }
89
90 s32 bdev_check_bdi_valid(struct super_block *sb)
91 {
92 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
93
94 if (block_device_ejected(sb)) {
95 if (!(fsi->prev_eio & SDFAT_EIO_BDI)) {
96 fsi->prev_eio |= SDFAT_EIO_BDI;
97 sdfat_log_msg(sb, KERN_ERR, "%s: block device is "
98 "eliminated.(bdi:%p)", __func__, sb->s_bdi);
99 sdfat_debug_warn_on(1);
100 }
101 return -ENXIO;
102 }
103
104 return 0;
105 }
106
107
108 /* Make a readahead request */
109 s32 bdev_readahead(struct super_block *sb, u32 secno, u32 num_secs)
110 {
111 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
112 u32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits);
113 struct blk_plug plug;
114 u32 i;
115
116 if (!fsi->bd_opened)
117 return -EIO;
118
119 blk_start_plug(&plug);
120 for (i = 0; i < num_secs; i++) {
121 if (i && !(i & (sects_per_page - 1)))
122 blk_flush_plug(current);
123 sb_breadahead(sb, secno + i);
124 }
125 blk_finish_plug(&plug);
126
127 return 0;
128 }
129
130 s32 bdev_mread(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 num_secs, s32 read)
131 {
132 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
133 u8 blksize_bits = sb->s_blocksize_bits;
134 #ifdef CONFIG_SDFAT_DBG_IOCTL
135 struct sdfat_sb_info *sbi = SDFAT_SB(sb);
136 long flags = sbi->debug_flags;
137
138 if (flags & SDFAT_DEBUGFLAGS_ERROR_RW)
139 return -EIO;
140 #endif /* CONFIG_SDFAT_DBG_IOCTL */
141
142 if (!fsi->bd_opened)
143 return -EIO;
144
145 brelse(*bh);
146
147 if (read)
148 *bh = __bread(sb->s_bdev, secno, num_secs << blksize_bits);
149 else
150 *bh = __getblk(sb->s_bdev, secno, num_secs << blksize_bits);
151
152 /* read successfully */
153 if (*bh)
154 return 0;
155
156 /*
157 * patch 1.2.4 : reset ONCE warning message per volume.
158 */
159 if (!(fsi->prev_eio & SDFAT_EIO_READ)) {
160 fsi->prev_eio |= SDFAT_EIO_READ;
161 sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
162 sdfat_debug_warn_on(1);
163 }
164
165 return -EIO;
166 }
167
168 s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync)
169 {
170 s32 count;
171 struct buffer_head *bh2;
172 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
173 #ifdef CONFIG_SDFAT_DBG_IOCTL
174 struct sdfat_sb_info *sbi = SDFAT_SB(sb);
175 long flags = sbi->debug_flags;
176
177 if (flags & SDFAT_DEBUGFLAGS_ERROR_RW)
178 return -EIO;
179 #endif /* CONFIG_SDFAT_DBG_IOCTL */
180
181 if (!fsi->bd_opened)
182 return -EIO;
183
184 if (secno == bh->b_blocknr) {
185 set_buffer_uptodate(bh);
186 mark_buffer_dirty(bh);
187 if (sync && (sync_dirty_buffer(bh) != 0))
188 return -EIO;
189 } else {
190 count = num_secs << sb->s_blocksize_bits;
191
192 bh2 = __getblk(sb->s_bdev, secno, count);
193
194 if (!bh2)
195 goto no_bh;
196
197 lock_buffer(bh2);
198 memcpy(bh2->b_data, bh->b_data, count);
199 set_buffer_uptodate(bh2);
200 mark_buffer_dirty(bh2);
201 unlock_buffer(bh2);
202 if (sync && (sync_dirty_buffer(bh2) != 0)) {
203 __brelse(bh2);
204 goto no_bh;
205 }
206 __brelse(bh2);
207 }
208 return 0;
209 no_bh:
210 /*
211 * patch 1.2.4 : reset ONCE warning message per volume.
212 */
213 if (!(fsi->prev_eio & SDFAT_EIO_WRITE)) {
214 fsi->prev_eio |= SDFAT_EIO_WRITE;
215 sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
216 sdfat_debug_warn_on(1);
217 }
218
219 return -EIO;
220 }
221
222 s32 bdev_sync_all(struct super_block *sb)
223 {
224 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
225 #ifdef CONFIG_SDFAT_DBG_IOCTL
226 struct sdfat_sb_info *sbi = SDFAT_SB(sb);
227 long flags = sbi->debug_flags;
228
229 if (flags & SDFAT_DEBUGFLAGS_ERROR_RW)
230 return -EIO;
231 #endif /* CONFIG_SDFAT_DBG_IOCTL */
232
233 if (!fsi->bd_opened)
234 return -EIO;
235
236 return sync_blockdev(sb->s_bdev);
237 }
238
239 /*
240 * Sector Read/Write Functions
241 */
242 s32 read_sect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 read)
243 {
244 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
245
246 BUG_ON(!bh);
247 if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
248 sdfat_fs_error_ratelimit(sb,
249 "%s: out of range (sect:%u)", __func__, sec);
250 return -EIO;
251 }
252
253 if (bdev_mread(sb, sec, bh, 1, read)) {
254 sdfat_fs_error_ratelimit(sb,
255 "%s: I/O error (sect:%u)", __func__, sec);
256 return -EIO;
257 }
258
259 return 0;
260 }
261
262 s32 write_sect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync)
263 {
264 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
265
266 BUG_ON(!bh);
267 if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
268 sdfat_fs_error_ratelimit(sb,
269 "%s: out of range (sect:%u)", __func__, sec);
270 return -EIO;
271 }
272
273 if (bdev_mwrite(sb, sec, bh, 1, sync)) {
274 sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)",
275 __func__, sec);
276 return -EIO;
277 }
278
279 return 0;
280 }
281
282 s32 read_msect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 num_secs, s32 read)
283 {
284 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
285
286 BUG_ON(!bh);
287 if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
288 sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
289 __func__, sec, num_secs);
290 return -EIO;
291 }
292
293 if (bdev_mread(sb, sec, bh, num_secs, read)) {
294 sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
295 __func__, sec, num_secs);
296 return -EIO;
297 }
298
299 return 0;
300 }
301
302 s32 write_msect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 num_secs, s32 sync)
303 {
304 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
305
306 BUG_ON(!bh);
307 if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
308 sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
309 __func__, sec, num_secs);
310 return -EIO;
311 }
312
313
314 if (bdev_mwrite(sb, sec, bh, num_secs, sync)) {
315 sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
316 __func__, sec, num_secs);
317 return -EIO;
318 }
319
320 return 0;
321 }
322
323 static inline void __blkdev_write_bhs(struct buffer_head **bhs, s32 nr_bhs)
324 {
325 s32 i;
326
327 for (i = 0; i < nr_bhs; i++)
328 write_dirty_buffer(bhs[i], WRITE);
329 }
330
331 static inline s32 __blkdev_sync_bhs(struct buffer_head **bhs, s32 nr_bhs)
332 {
333 s32 i, err = 0;
334
335 for (i = 0; i < nr_bhs; i++) {
336 wait_on_buffer(bhs[i]);
337 if (!err && !buffer_uptodate(bhs[i]))
338 err = -EIO;
339 }
340 return err;
341 }
342
343 static inline s32 __buffer_zeroed(struct super_block *sb, u32 blknr, s32 num_secs)
344 {
345 struct buffer_head *bhs[MAX_BUF_PER_PAGE];
346 s32 nr_bhs = MAX_BUF_PER_PAGE;
347 u32 last_blknr = blknr + num_secs;
348 s32 err, i, n;
349 struct blk_plug plug;
350
351 /* Zeroing the unused blocks on this cluster */
352 n = 0;
353 blk_start_plug(&plug);
354 while (blknr < last_blknr) {
355 bhs[n] = sb_getblk(sb, blknr);
356 if (!bhs[n]) {
357 err = -ENOMEM;
358 blk_finish_plug(&plug);
359 goto error;
360 }
361 memset(bhs[n]->b_data, 0, sb->s_blocksize);
362 set_buffer_uptodate(bhs[n]);
363 mark_buffer_dirty(bhs[n]);
364
365 n++;
366 blknr++;
367
368 if (blknr == last_blknr)
369 break;
370
371 if (n == nr_bhs) {
372 __blkdev_write_bhs(bhs, n);
373
374 for (i = 0; i < n; i++)
375 brelse(bhs[i]);
376 n = 0;
377 }
378 }
379 __blkdev_write_bhs(bhs, n);
380 blk_finish_plug(&plug);
381
382 err = __blkdev_sync_bhs(bhs, n);
383 if (err)
384 goto error;
385
386 for (i = 0; i < n; i++)
387 brelse(bhs[i]);
388
389 return 0;
390
391 error:
392 EMSG("%s: failed zeroed sect %u\n", __func__, blknr);
393 for (i = 0; i < n; i++)
394 bforget(bhs[i]);
395
396 return err;
397 }
398
399 s32 write_msect_zero(struct super_block *sb, u32 sec, s32 num_secs)
400 {
401 FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
402
403 if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
404 sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
405 __func__, sec, num_secs);
406 return -EIO;
407 }
408
409 /* Just return -EAGAIN if it is failed */
410 if (__buffer_zeroed(sb, sec, num_secs))
411 return -EAGAIN;
412
413 return 0;
414 } /* end of write_msect_zero */
415
416 /* end of blkdev.c */