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