2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
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.
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.
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/>.
18 /************************************************************************/
20 /* PROJECT : exFAT & FAT12/16/32 File System */
22 /* PURPOSE : sdFAT Block Device Driver Glue Layer */
24 /*----------------------------------------------------------------------*/
27 /************************************************************************/
29 #include <linux/blkdev.h>
30 #include <linux/log2.h>
31 #include <linux/backing-dev.h>
35 /*----------------------------------------------------------------------*/
36 /* Constant & Macro Definitions */
37 /*----------------------------------------------------------------------*/
39 /*----------------------------------------------------------------------*/
40 /* Global Variable Definitions */
41 /*----------------------------------------------------------------------*/
43 /*----------------------------------------------------------------------*/
44 /* Local Variable Definitions */
45 /*----------------------------------------------------------------------*/
47 /*----------------------------------------------------------------------*/
48 /* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY */
49 /************************************************************************/
51 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
53 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) */
54 static struct backing_dev_info
*inode_to_bdi(struct inode
*bd_inode
)
56 return bd_inode
->i_mapping
->backing_dev_info
;
60 /*======================================================================*/
61 /* Function Definitions */
62 /*======================================================================*/
63 s32
bdev_open_dev(struct super_block
*sb
)
65 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
70 fsi
->bd_opened
= true;
74 s32
bdev_close_dev(struct super_block
*sb
)
76 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
78 fsi
->bd_opened
= false;
82 static inline s32
block_device_ejected(struct super_block
*sb
)
84 struct inode
*bd_inode
= sb
->s_bdev
->bd_inode
;
85 struct backing_dev_info
*bdi
= inode_to_bdi(bd_inode
);
87 return (bdi
->dev
== NULL
);
90 s32
bdev_check_bdi_valid(struct super_block
*sb
)
92 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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);
108 /* Make a readahead request */
109 s32
bdev_readahead(struct super_block
*sb
, u32 secno
, u32 num_secs
)
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
;
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
);
125 blk_finish_plug(&plug
);
130 s32
bdev_mread(struct super_block
*sb
, u32 secno
, struct buffer_head
**bh
, u32 num_secs
, s32 read
)
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
;
138 if (flags
& SDFAT_DEBUGFLAGS_ERROR_RW
)
140 #endif /* CONFIG_SDFAT_DBG_IOCTL */
148 *bh
= __bread(sb
->s_bdev
, secno
, num_secs
<< blksize_bits
);
150 *bh
= __getblk(sb
->s_bdev
, secno
, num_secs
<< blksize_bits
);
152 /* read successfully */
157 * patch 1.2.4 : reset ONCE warning message per volume.
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);
168 s32
bdev_mwrite(struct super_block
*sb
, u32 secno
, struct buffer_head
*bh
, u32 num_secs
, s32 sync
)
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
;
177 if (flags
& SDFAT_DEBUGFLAGS_ERROR_RW
)
179 #endif /* CONFIG_SDFAT_DBG_IOCTL */
184 if (secno
== bh
->b_blocknr
) {
185 set_buffer_uptodate(bh
);
186 mark_buffer_dirty(bh
);
187 if (sync
&& (sync_dirty_buffer(bh
) != 0))
190 count
= num_secs
<< sb
->s_blocksize_bits
;
192 bh2
= __getblk(sb
->s_bdev
, secno
, count
);
198 memcpy(bh2
->b_data
, bh
->b_data
, count
);
199 set_buffer_uptodate(bh2
);
200 mark_buffer_dirty(bh2
);
202 if (sync
&& (sync_dirty_buffer(bh2
) != 0)) {
211 * patch 1.2.4 : reset ONCE warning message per volume.
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);
222 s32
bdev_sync_all(struct super_block
*sb
)
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
;
229 if (flags
& SDFAT_DEBUGFLAGS_ERROR_RW
)
231 #endif /* CONFIG_SDFAT_DBG_IOCTL */
236 return sync_blockdev(sb
->s_bdev
);
240 * Sector Read/Write Functions
242 s32
read_sect(struct super_block
*sb
, u32 sec
, struct buffer_head
**bh
, s32 read
)
244 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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
);
253 if (bdev_mread(sb
, sec
, bh
, 1, read
)) {
254 sdfat_fs_error_ratelimit(sb
,
255 "%s: I/O error (sect:%u)", __func__
, sec
);
262 s32
write_sect(struct super_block
*sb
, u32 sec
, struct buffer_head
*bh
, s32 sync
)
264 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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
);
273 if (bdev_mwrite(sb
, sec
, bh
, 1, sync
)) {
274 sdfat_fs_error_ratelimit(sb
, "%s: I/O error (sect:%u)",
282 s32
read_msect(struct super_block
*sb
, u32 sec
, struct buffer_head
**bh
, s32 num_secs
, s32 read
)
284 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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
);
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
);
302 s32
write_msect(struct super_block
*sb
, u32 sec
, struct buffer_head
*bh
, s32 num_secs
, s32 sync
)
304 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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
);
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
);
323 static inline void __blkdev_write_bhs(struct buffer_head
**bhs
, s32 nr_bhs
)
327 for (i
= 0; i
< nr_bhs
; i
++)
328 write_dirty_buffer(bhs
[i
], WRITE
);
331 static inline s32
__blkdev_sync_bhs(struct buffer_head
**bhs
, s32 nr_bhs
)
335 for (i
= 0; i
< nr_bhs
; i
++) {
336 wait_on_buffer(bhs
[i
]);
337 if (!err
&& !buffer_uptodate(bhs
[i
]))
343 static inline s32
__buffer_zeroed(struct super_block
*sb
, u32 blknr
, s32 num_secs
)
345 struct buffer_head
*bhs
[MAX_BUF_PER_PAGE
];
346 s32 nr_bhs
= MAX_BUF_PER_PAGE
;
347 u32 last_blknr
= blknr
+ num_secs
;
349 struct blk_plug plug
;
351 /* Zeroing the unused blocks on this cluster */
353 blk_start_plug(&plug
);
354 while (blknr
< last_blknr
) {
355 bhs
[n
] = sb_getblk(sb
, blknr
);
358 blk_finish_plug(&plug
);
361 memset(bhs
[n
]->b_data
, 0, sb
->s_blocksize
);
362 set_buffer_uptodate(bhs
[n
]);
363 mark_buffer_dirty(bhs
[n
]);
368 if (blknr
== last_blknr
)
372 __blkdev_write_bhs(bhs
, n
);
374 for (i
= 0; i
< n
; i
++)
379 __blkdev_write_bhs(bhs
, n
);
380 blk_finish_plug(&plug
);
382 err
= __blkdev_sync_bhs(bhs
, n
);
386 for (i
= 0; i
< n
; i
++)
392 EMSG("%s: failed zeroed sect %u\n", __func__
, blknr
);
393 for (i
= 0; i
< n
; i
++)
399 s32
write_msect_zero(struct super_block
*sb
, u32 sec
, s32 num_secs
)
401 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
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
);
409 /* Just return -EAGAIN if it is failed */
410 if (__buffer_zeroed(sb
, sec
, num_secs
))
414 } /* end of write_msect_zero */
416 /* end of blkdev.c */