• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
4  */
5 
6 #include <linux/blkdev.h>
7 #include <linux/buffer_head.h>
8 #include <linux/fs.h>
9 #include "exfat.h"
10 
bdev_open(struct super_block * sb)11 void bdev_open(struct super_block *sb)
12 {
13 	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
14 
15 	if (p_bd->opened)
16 		return;
17 
18 	p_bd->sector_size      = bdev_logical_block_size(sb->s_bdev);
19 	p_bd->sector_size_bits = ilog2(p_bd->sector_size);
20 	p_bd->sector_size_mask = p_bd->sector_size - 1;
21 	p_bd->num_sectors      = i_size_read(sb->s_bdev->bd_inode) >>
22 				 p_bd->sector_size_bits;
23 	p_bd->opened = true;
24 }
25 
bdev_close(struct super_block * sb)26 void bdev_close(struct super_block *sb)
27 {
28 	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
29 
30 	p_bd->opened = false;
31 }
32 
bdev_read(struct super_block * sb,sector_t secno,struct buffer_head ** bh,u32 num_secs,bool read)33 int bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh,
34 	      u32 num_secs, bool read)
35 {
36 	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
37 	struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
38 #ifdef CONFIG_EXFAT_KERNEL_DEBUG
39 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
40 	long flags = sbi->debug_flags;
41 
42 	if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
43 		return FFS_MEDIAERR;
44 #endif /* CONFIG_EXFAT_KERNEL_DEBUG */
45 
46 	if (!p_bd->opened)
47 		return FFS_MEDIAERR;
48 
49 	if (*bh)
50 		__brelse(*bh);
51 
52 	if (read)
53 		*bh = __bread(sb->s_bdev, secno,
54 			      num_secs << p_bd->sector_size_bits);
55 	else
56 		*bh = __getblk(sb->s_bdev, secno,
57 			       num_secs << p_bd->sector_size_bits);
58 
59 	if (*bh)
60 		return 0;
61 
62 	WARN(!p_fs->dev_ejected,
63 	     "[EXFAT] No bh, device seems wrong or to be ejected.\n");
64 
65 	return FFS_MEDIAERR;
66 }
67 
bdev_write(struct super_block * sb,sector_t secno,struct buffer_head * bh,u32 num_secs,bool sync)68 int bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh,
69 	       u32 num_secs, bool sync)
70 {
71 	s32 count;
72 	struct buffer_head *bh2;
73 	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
74 	struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
75 #ifdef CONFIG_EXFAT_KERNEL_DEBUG
76 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
77 	long flags = sbi->debug_flags;
78 
79 	if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
80 		return FFS_MEDIAERR;
81 #endif /* CONFIG_EXFAT_KERNEL_DEBUG */
82 
83 	if (!p_bd->opened)
84 		return FFS_MEDIAERR;
85 
86 	if (secno == bh->b_blocknr) {
87 		lock_buffer(bh);
88 		set_buffer_uptodate(bh);
89 		mark_buffer_dirty(bh);
90 		unlock_buffer(bh);
91 		if (sync && (sync_dirty_buffer(bh) != 0))
92 			return FFS_MEDIAERR;
93 	} else {
94 		count = num_secs << p_bd->sector_size_bits;
95 
96 		bh2 = __getblk(sb->s_bdev, secno, count);
97 		if (!bh2)
98 			goto no_bh;
99 
100 		lock_buffer(bh2);
101 		memcpy(bh2->b_data, bh->b_data, count);
102 		set_buffer_uptodate(bh2);
103 		mark_buffer_dirty(bh2);
104 		unlock_buffer(bh2);
105 		if (sync && (sync_dirty_buffer(bh2) != 0)) {
106 			__brelse(bh2);
107 			goto no_bh;
108 		}
109 		__brelse(bh2);
110 	}
111 
112 	return 0;
113 
114 no_bh:
115 	WARN(!p_fs->dev_ejected,
116 	     "[EXFAT] No bh, device seems wrong or to be ejected.\n");
117 
118 	return FFS_MEDIAERR;
119 }
120 
bdev_sync(struct super_block * sb)121 int bdev_sync(struct super_block *sb)
122 {
123 	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
124 #ifdef CONFIG_EXFAT_KERNEL_DEBUG
125 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
126 	long flags = sbi->debug_flags;
127 
128 	if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
129 		return FFS_MEDIAERR;
130 #endif /* CONFIG_EXFAT_KERNEL_DEBUG */
131 
132 	if (!p_bd->opened)
133 		return FFS_MEDIAERR;
134 
135 	return sync_blockdev(sb->s_bdev);
136 }
137