]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/hpfs/buffer.c | |
3 | * | |
4 | * Mikulas Patocka ([email protected]), 1998-1999 | |
5 | * | |
6 | * general buffer i/o | |
7 | */ | |
e8edc6e0 | 8 | #include <linux/sched.h> |
5a0e3ad6 | 9 | #include <linux/slab.h> |
275f495d | 10 | #include <linux/blkdev.h> |
1da177e4 LT |
11 | #include "hpfs_fn.h" |
12 | ||
a64eefaa MP |
13 | secno hpfs_search_hotfix_map(struct super_block *s, secno sec) |
14 | { | |
15 | unsigned i; | |
16 | struct hpfs_sb_info *sbi = hpfs_sb(s); | |
17 | for (i = 0; unlikely(i < sbi->n_hotfixes); i++) { | |
18 | if (sbi->hotfix_from[i] == sec) { | |
19 | return sbi->hotfix_to[i]; | |
20 | } | |
21 | } | |
22 | return sec; | |
23 | } | |
24 | ||
25 | unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n) | |
26 | { | |
27 | unsigned i; | |
28 | struct hpfs_sb_info *sbi = hpfs_sb(s); | |
29 | for (i = 0; unlikely(i < sbi->n_hotfixes); i++) { | |
30 | if (sbi->hotfix_from[i] >= sec && sbi->hotfix_from[i] < sec + n) { | |
31 | n = sbi->hotfix_from[i] - sec; | |
32 | } | |
33 | } | |
34 | return n; | |
35 | } | |
36 | ||
275f495d MP |
37 | void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n) |
38 | { | |
39 | struct buffer_head *bh; | |
40 | struct blk_plug plug; | |
41 | ||
42 | if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size)) | |
43 | return; | |
44 | ||
a64eefaa MP |
45 | if (unlikely(hpfs_search_hotfix_map_for_range(s, secno, n) != n)) |
46 | return; | |
47 | ||
275f495d MP |
48 | bh = sb_find_get_block(s, secno); |
49 | if (bh) { | |
50 | if (buffer_uptodate(bh)) { | |
51 | brelse(bh); | |
52 | return; | |
53 | } | |
54 | brelse(bh); | |
55 | }; | |
56 | ||
57 | blk_start_plug(&plug); | |
58 | while (n > 0) { | |
59 | if (unlikely(secno >= hpfs_sb(s)->sb_fs_size)) | |
60 | break; | |
61 | sb_breadahead(s, secno); | |
62 | secno++; | |
63 | n--; | |
64 | } | |
65 | blk_finish_plug(&plug); | |
66 | } | |
67 | ||
1da177e4 LT |
68 | /* Map a sector into a buffer and return pointers to it and to the buffer. */ |
69 | ||
70 | void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp, | |
71 | int ahead) | |
72 | { | |
73 | struct buffer_head *bh; | |
74 | ||
7dd29d8d MP |
75 | hpfs_lock_assert(s); |
76 | ||
275f495d MP |
77 | hpfs_prefetch_sectors(s, secno, ahead); |
78 | ||
1da177e4 LT |
79 | cond_resched(); |
80 | ||
a64eefaa | 81 | *bhp = bh = sb_bread(s, hpfs_search_hotfix_map(s, secno)); |
1da177e4 LT |
82 | if (bh != NULL) |
83 | return bh->b_data; | |
84 | else { | |
a19189e5 | 85 | pr_err("%s(): read error\n", __func__); |
1da177e4 LT |
86 | return NULL; |
87 | } | |
88 | } | |
89 | ||
90 | /* Like hpfs_map_sector but don't read anything */ | |
91 | ||
92 | void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp) | |
93 | { | |
94 | struct buffer_head *bh; | |
95 | /*return hpfs_map_sector(s, secno, bhp, 0);*/ | |
96 | ||
7dd29d8d MP |
97 | hpfs_lock_assert(s); |
98 | ||
1da177e4 LT |
99 | cond_resched(); |
100 | ||
a64eefaa | 101 | if ((*bhp = bh = sb_getblk(s, hpfs_search_hotfix_map(s, secno))) != NULL) { |
1da177e4 LT |
102 | if (!buffer_uptodate(bh)) wait_on_buffer(bh); |
103 | set_buffer_uptodate(bh); | |
104 | return bh->b_data; | |
105 | } else { | |
a19189e5 | 106 | pr_err("%s(): getblk failed\n", __func__); |
1da177e4 LT |
107 | return NULL; |
108 | } | |
109 | } | |
110 | ||
111 | /* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */ | |
112 | ||
113 | void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh, | |
114 | int ahead) | |
115 | { | |
1da177e4 LT |
116 | char *data; |
117 | ||
7dd29d8d MP |
118 | hpfs_lock_assert(s); |
119 | ||
1da177e4 LT |
120 | cond_resched(); |
121 | ||
122 | if (secno & 3) { | |
a19189e5 | 123 | pr_err("%s(): unaligned read\n", __func__); |
1da177e4 LT |
124 | return NULL; |
125 | } | |
126 | ||
275f495d MP |
127 | hpfs_prefetch_sectors(s, secno, 4 + ahead); |
128 | ||
a64eefaa MP |
129 | if (!hpfs_map_sector(s, secno + 0, &qbh->bh[0], 0)) goto bail0; |
130 | if (!hpfs_map_sector(s, secno + 1, &qbh->bh[1], 0)) goto bail1; | |
131 | if (!hpfs_map_sector(s, secno + 2, &qbh->bh[2], 0)) goto bail2; | |
132 | if (!hpfs_map_sector(s, secno + 3, &qbh->bh[3], 0)) goto bail3; | |
1c0b8a7a MP |
133 | |
134 | if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && | |
135 | likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && | |
136 | likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { | |
137 | return qbh->data = qbh->bh[0]->b_data; | |
138 | } | |
139 | ||
f52720ca | 140 | qbh->data = data = kmalloc(2048, GFP_NOFS); |
1da177e4 | 141 | if (!data) { |
a19189e5 | 142 | pr_err("%s(): out of memory\n", __func__); |
1c0b8a7a | 143 | goto bail4; |
1da177e4 LT |
144 | } |
145 | ||
1c0b8a7a MP |
146 | memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512); |
147 | memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512); | |
148 | memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512); | |
149 | memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512); | |
1da177e4 LT |
150 | |
151 | return data; | |
152 | ||
1c0b8a7a MP |
153 | bail4: |
154 | brelse(qbh->bh[3]); | |
1da177e4 LT |
155 | bail3: |
156 | brelse(qbh->bh[2]); | |
157 | bail2: | |
158 | brelse(qbh->bh[1]); | |
159 | bail1: | |
160 | brelse(qbh->bh[0]); | |
161 | bail0: | |
1da177e4 LT |
162 | return NULL; |
163 | } | |
164 | ||
165 | /* Don't read sectors */ | |
166 | ||
167 | void *hpfs_get_4sectors(struct super_block *s, unsigned secno, | |
168 | struct quad_buffer_head *qbh) | |
169 | { | |
170 | cond_resched(); | |
171 | ||
7dd29d8d MP |
172 | hpfs_lock_assert(s); |
173 | ||
1da177e4 | 174 | if (secno & 3) { |
a19189e5 | 175 | pr_err("%s(): unaligned read\n", __func__); |
1da177e4 LT |
176 | return NULL; |
177 | } | |
178 | ||
1c0b8a7a MP |
179 | if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0; |
180 | if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1; | |
181 | if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2; | |
182 | if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3; | |
183 | ||
184 | if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && | |
185 | likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && | |
186 | likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { | |
187 | return qbh->data = qbh->bh[0]->b_data; | |
188 | } | |
189 | ||
1da177e4 | 190 | if (!(qbh->data = kmalloc(2048, GFP_NOFS))) { |
a19189e5 | 191 | pr_err("%s(): out of memory\n", __func__); |
1c0b8a7a | 192 | goto bail4; |
1da177e4 | 193 | } |
1da177e4 LT |
194 | return qbh->data; |
195 | ||
1c0b8a7a MP |
196 | bail4: |
197 | brelse(qbh->bh[3]); | |
198 | bail3: | |
199 | brelse(qbh->bh[2]); | |
200 | bail2: | |
201 | brelse(qbh->bh[1]); | |
202 | bail1: | |
203 | brelse(qbh->bh[0]); | |
204 | bail0: | |
1da177e4 LT |
205 | return NULL; |
206 | } | |
207 | ||
208 | ||
209 | void hpfs_brelse4(struct quad_buffer_head *qbh) | |
210 | { | |
1c0b8a7a MP |
211 | if (unlikely(qbh->data != qbh->bh[0]->b_data)) |
212 | kfree(qbh->data); | |
1da177e4 | 213 | brelse(qbh->bh[0]); |
1c0b8a7a MP |
214 | brelse(qbh->bh[1]); |
215 | brelse(qbh->bh[2]); | |
216 | brelse(qbh->bh[3]); | |
1da177e4 LT |
217 | } |
218 | ||
219 | void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh) | |
220 | { | |
1c0b8a7a MP |
221 | if (unlikely(qbh->data != qbh->bh[0]->b_data)) { |
222 | memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512); | |
223 | memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512); | |
224 | memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); | |
225 | memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); | |
226 | } | |
1da177e4 LT |
227 | mark_buffer_dirty(qbh->bh[0]); |
228 | mark_buffer_dirty(qbh->bh[1]); | |
229 | mark_buffer_dirty(qbh->bh[2]); | |
230 | mark_buffer_dirty(qbh->bh[3]); | |
231 | } |