]>
Commit | Line | Data |
---|---|---|
31023864 NJ |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. | |
4 | */ | |
5 | ||
6 | #include <linux/slab.h> | |
5f60d5f6 | 7 | #include <linux/unaligned.h> |
31023864 | 8 | #include <linux/buffer_head.h> |
1b613838 | 9 | #include <linux/blkdev.h> |
31023864 NJ |
10 | |
11 | #include "exfat_raw.h" | |
12 | #include "exfat_fs.h" | |
13 | ||
14 | static int exfat_mirror_bh(struct super_block *sb, sector_t sec, | |
15 | struct buffer_head *bh) | |
16 | { | |
17 | struct buffer_head *c_bh; | |
18 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
19 | sector_t sec2; | |
20 | int err = 0; | |
21 | ||
22 | if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { | |
23 | sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; | |
24 | c_bh = sb_getblk(sb, sec2); | |
25 | if (!c_bh) | |
26 | return -ENOMEM; | |
27 | memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); | |
28 | set_buffer_uptodate(c_bh); | |
29 | mark_buffer_dirty(c_bh); | |
30 | if (sb->s_flags & SB_SYNCHRONOUS) | |
31 | err = sync_dirty_buffer(c_bh); | |
32 | brelse(c_bh); | |
33 | } | |
34 | ||
35 | return err; | |
36 | } | |
37 | ||
38 | static int __exfat_ent_get(struct super_block *sb, unsigned int loc, | |
39 | unsigned int *content) | |
40 | { | |
41 | unsigned int off; | |
42 | sector_t sec; | |
43 | struct buffer_head *bh; | |
44 | ||
45 | sec = FAT_ENT_OFFSET_SECTOR(sb, loc); | |
46 | off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); | |
47 | ||
48 | bh = sb_bread(sb, sec); | |
49 | if (!bh) | |
50 | return -EIO; | |
51 | ||
52 | *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); | |
53 | ||
54 | /* remap reserved clusters to simplify code */ | |
55 | if (*content > EXFAT_BAD_CLUSTER) | |
56 | *content = EXFAT_EOF_CLUSTER; | |
57 | ||
58 | brelse(bh); | |
59 | return 0; | |
60 | } | |
61 | ||
62 | int exfat_ent_set(struct super_block *sb, unsigned int loc, | |
63 | unsigned int content) | |
64 | { | |
65 | unsigned int off; | |
66 | sector_t sec; | |
67 | __le32 *fat_entry; | |
68 | struct buffer_head *bh; | |
69 | ||
70 | sec = FAT_ENT_OFFSET_SECTOR(sb, loc); | |
71 | off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); | |
72 | ||
73 | bh = sb_bread(sb, sec); | |
74 | if (!bh) | |
75 | return -EIO; | |
76 | ||
77 | fat_entry = (__le32 *)&(bh->b_data[off]); | |
78 | *fat_entry = cpu_to_le32(content); | |
2c7f8937 | 79 | exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS); |
31023864 NJ |
80 | exfat_mirror_bh(sb, sec, bh); |
81 | brelse(bh); | |
82 | return 0; | |
83 | } | |
84 | ||
31023864 NJ |
85 | int exfat_ent_get(struct super_block *sb, unsigned int loc, |
86 | unsigned int *content) | |
87 | { | |
88 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
89 | int err; | |
90 | ||
91 | if (!is_valid_cluster(sbi, loc)) { | |
92 | exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", | |
93 | loc); | |
94 | return -EIO; | |
95 | } | |
96 | ||
97 | err = __exfat_ent_get(sb, loc, content); | |
98 | if (err) { | |
99 | exfat_fs_error(sb, | |
100 | "failed to access to FAT (entry 0x%08x, err:%d)", | |
101 | loc, err); | |
102 | return err; | |
103 | } | |
104 | ||
105 | if (*content == EXFAT_FREE_CLUSTER) { | |
106 | exfat_fs_error(sb, | |
107 | "invalid access to FAT free cluster (entry 0x%08x)", | |
108 | loc); | |
109 | return -EIO; | |
110 | } | |
111 | ||
112 | if (*content == EXFAT_BAD_CLUSTER) { | |
113 | exfat_fs_error(sb, | |
114 | "invalid access to FAT bad cluster (entry 0x%08x)", | |
115 | loc); | |
116 | return -EIO; | |
117 | } | |
118 | ||
119 | if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { | |
120 | exfat_fs_error(sb, | |
121 | "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", | |
122 | loc, *content); | |
123 | return -EIO; | |
124 | } | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, | |
130 | unsigned int len) | |
131 | { | |
132 | if (!len) | |
133 | return 0; | |
134 | ||
135 | while (len > 1) { | |
136 | if (exfat_ent_set(sb, chain, chain + 1)) | |
137 | return -EIO; | |
138 | chain++; | |
139 | len--; | |
140 | } | |
141 | ||
142 | if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) | |
143 | return -EIO; | |
144 | return 0; | |
145 | } | |
146 | ||
5c2d7285 HK |
147 | /* This function must be called with bitmap_lock held */ |
148 | static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) | |
31023864 | 149 | { |
31023864 NJ |
150 | struct super_block *sb = inode->i_sb; |
151 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
f728760a | 152 | int cur_cmap_i, next_cmap_i; |
5c2d7285 HK |
153 | unsigned int num_clusters = 0; |
154 | unsigned int clu; | |
31023864 NJ |
155 | |
156 | /* invalid cluster number */ | |
157 | if (p_chain->dir == EXFAT_FREE_CLUSTER || | |
158 | p_chain->dir == EXFAT_EOF_CLUSTER || | |
159 | p_chain->dir < EXFAT_FIRST_CLUSTER) | |
160 | return 0; | |
161 | ||
162 | /* no cluster to truncate */ | |
163 | if (p_chain->size == 0) | |
164 | return 0; | |
165 | ||
166 | /* check cluster validation */ | |
a949824f | 167 | if (!is_valid_cluster(sbi, p_chain->dir)) { |
d1727d55 | 168 | exfat_err(sb, "invalid start cluster (%u)", p_chain->dir); |
31023864 NJ |
169 | return -EIO; |
170 | } | |
171 | ||
31023864 NJ |
172 | clu = p_chain->dir; |
173 | ||
f728760a HK |
174 | cur_cmap_i = next_cmap_i = |
175 | BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu)); | |
176 | ||
31023864 | 177 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { |
f728760a | 178 | unsigned int last_cluster = p_chain->dir + p_chain->size - 1; |
31023864 | 179 | do { |
f728760a HK |
180 | bool sync = false; |
181 | ||
182 | if (clu < last_cluster) | |
183 | next_cmap_i = | |
184 | BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu+1)); | |
185 | ||
186 | /* flush bitmap only if index would be changed or for last cluster */ | |
187 | if (clu == last_cluster || cur_cmap_i != next_cmap_i) { | |
188 | sync = true; | |
189 | cur_cmap_i = next_cmap_i; | |
190 | } | |
31023864 | 191 | |
f728760a HK |
192 | exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode))); |
193 | clu++; | |
31023864 NJ |
194 | num_clusters++; |
195 | } while (num_clusters < p_chain->size); | |
196 | } else { | |
197 | do { | |
f728760a HK |
198 | bool sync = false; |
199 | unsigned int n_clu = clu; | |
200 | int err = exfat_get_next_cluster(sb, &n_clu); | |
201 | ||
202 | if (err || n_clu == EXFAT_EOF_CLUSTER) | |
203 | sync = true; | |
204 | else | |
205 | next_cmap_i = | |
206 | BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(n_clu)); | |
207 | ||
208 | if (cur_cmap_i != next_cmap_i) { | |
209 | sync = true; | |
210 | cur_cmap_i = next_cmap_i; | |
211 | } | |
212 | ||
213 | exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode))); | |
214 | clu = n_clu; | |
215 | num_clusters++; | |
31023864 | 216 | |
f728760a | 217 | if (err) |
31023864 | 218 | goto dec_used_clus; |
a5324b3a YM |
219 | |
220 | if (num_clusters >= sbi->num_clusters - EXFAT_FIRST_CLUSTER) { | |
221 | /* | |
222 | * The cluster chain includes a loop, scan the | |
223 | * bitmap to get the number of used clusters. | |
224 | */ | |
225 | exfat_count_used_clusters(sb, &sbi->used_clusters); | |
226 | ||
227 | return 0; | |
228 | } | |
31023864 NJ |
229 | } while (clu != EXFAT_EOF_CLUSTER); |
230 | } | |
231 | ||
232 | dec_used_clus: | |
233 | sbi->used_clusters -= num_clusters; | |
234 | return 0; | |
235 | } | |
236 | ||
5c2d7285 HK |
237 | int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) |
238 | { | |
239 | int ret = 0; | |
240 | ||
241 | mutex_lock(&EXFAT_SB(inode->i_sb)->bitmap_lock); | |
242 | ret = __exfat_free_cluster(inode, p_chain); | |
243 | mutex_unlock(&EXFAT_SB(inode->i_sb)->bitmap_lock); | |
244 | ||
245 | return ret; | |
246 | } | |
247 | ||
31023864 NJ |
248 | int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, |
249 | unsigned int *ret_clu) | |
250 | { | |
251 | unsigned int clu, next; | |
252 | unsigned int count = 0; | |
253 | ||
254 | next = p_chain->dir; | |
255 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
256 | *ret_clu = next + p_chain->size - 1; | |
257 | return 0; | |
258 | } | |
259 | ||
260 | do { | |
261 | count++; | |
262 | clu = next; | |
263 | if (exfat_ent_get(sb, clu, &next)) | |
264 | return -EIO; | |
265 | } while (next != EXFAT_EOF_CLUSTER); | |
266 | ||
267 | if (p_chain->size != count) { | |
268 | exfat_fs_error(sb, | |
269 | "bogus directory size (clus : ondisk(%d) != counted(%d))", | |
270 | p_chain->size, count); | |
271 | return -EIO; | |
272 | } | |
273 | ||
274 | *ret_clu = clu; | |
275 | return 0; | |
276 | } | |
277 | ||
31023864 NJ |
278 | int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) |
279 | { | |
280 | struct super_block *sb = dir->i_sb; | |
281 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
1b613838 | 282 | struct buffer_head *bh; |
2e9ceb67 | 283 | sector_t blknr, last_blknr, i; |
31023864 NJ |
284 | |
285 | blknr = exfat_cluster_to_sector(sbi, clu); | |
286 | last_blknr = blknr + sbi->sect_per_clus; | |
287 | ||
288 | if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { | |
289 | exfat_fs_error_ratelimit(sb, | |
290 | "%s: out of range(sect:%llu len:%u)", | |
291 | __func__, (unsigned long long)blknr, | |
292 | sbi->sect_per_clus); | |
293 | return -EIO; | |
294 | } | |
295 | ||
296 | /* Zeroing the unused blocks on this cluster */ | |
1b613838 YM |
297 | for (i = blknr; i < last_blknr; i++) { |
298 | bh = sb_getblk(sb, i); | |
299 | if (!bh) | |
300 | return -ENOMEM; | |
31023864 | 301 | |
1b613838 YM |
302 | memset(bh->b_data, 0, sb->s_blocksize); |
303 | set_buffer_uptodate(bh); | |
304 | mark_buffer_dirty(bh); | |
305 | brelse(bh); | |
4dc7d35e | 306 | } |
31023864 | 307 | |
1b613838 YM |
308 | if (IS_DIRSYNC(dir)) |
309 | return sync_blockdev_range(sb->s_bdev, | |
310 | EXFAT_BLK_TO_B(blknr, sb), | |
311 | EXFAT_BLK_TO_B(last_blknr, sb) - 1); | |
312 | ||
313 | return 0; | |
31023864 NJ |
314 | } |
315 | ||
316 | int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, | |
23befe49 | 317 | struct exfat_chain *p_chain, bool sync_bmap) |
31023864 NJ |
318 | { |
319 | int ret = -ENOSPC; | |
d5c514b6 | 320 | unsigned int total_cnt; |
31023864 NJ |
321 | unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; |
322 | struct super_block *sb = inode->i_sb; | |
323 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
324 | ||
325 | total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); | |
326 | ||
327 | if (unlikely(total_cnt < sbi->used_clusters)) { | |
328 | exfat_fs_error_ratelimit(sb, | |
329 | "%s: invalid used clusters(t:%u,u:%u)\n", | |
330 | __func__, total_cnt, sbi->used_clusters); | |
331 | return -EIO; | |
332 | } | |
333 | ||
334 | if (num_alloc > total_cnt - sbi->used_clusters) | |
335 | return -ENOSPC; | |
336 | ||
5c2d7285 HK |
337 | mutex_lock(&sbi->bitmap_lock); |
338 | ||
31023864 NJ |
339 | hint_clu = p_chain->dir; |
340 | /* find new cluster */ | |
341 | if (hint_clu == EXFAT_EOF_CLUSTER) { | |
342 | if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { | |
512b74d1 | 343 | exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)", |
d1727d55 | 344 | sbi->clu_srch_ptr); |
31023864 NJ |
345 | sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; |
346 | } | |
347 | ||
348 | hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); | |
5c2d7285 HK |
349 | if (hint_clu == EXFAT_EOF_CLUSTER) { |
350 | ret = -ENOSPC; | |
351 | goto unlock; | |
352 | } | |
31023864 NJ |
353 | } |
354 | ||
355 | /* check cluster validation */ | |
a949824f | 356 | if (!is_valid_cluster(sbi, hint_clu)) { |
3ce937cb YM |
357 | if (hint_clu != sbi->num_clusters) |
358 | exfat_err(sb, "hint_cluster is invalid (%u), rewind to the first cluster", | |
359 | hint_clu); | |
31023864 | 360 | hint_clu = EXFAT_FIRST_CLUSTER; |
8d2909ee | 361 | p_chain->flags = ALLOC_FAT_CHAIN; |
31023864 NJ |
362 | } |
363 | ||
31023864 NJ |
364 | p_chain->dir = EXFAT_EOF_CLUSTER; |
365 | ||
366 | while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != | |
367 | EXFAT_EOF_CLUSTER) { | |
368 | if (new_clu != hint_clu && | |
369 | p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
370 | if (exfat_chain_cont_cluster(sb, p_chain->dir, | |
d5c514b6 | 371 | p_chain->size)) { |
31023864 NJ |
372 | ret = -EIO; |
373 | goto free_cluster; | |
374 | } | |
375 | p_chain->flags = ALLOC_FAT_CHAIN; | |
376 | } | |
377 | ||
378 | /* update allocation bitmap */ | |
23befe49 | 379 | if (exfat_set_bitmap(inode, new_clu, sync_bmap)) { |
31023864 NJ |
380 | ret = -EIO; |
381 | goto free_cluster; | |
382 | } | |
383 | ||
31023864 NJ |
384 | /* update FAT table */ |
385 | if (p_chain->flags == ALLOC_FAT_CHAIN) { | |
386 | if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { | |
387 | ret = -EIO; | |
388 | goto free_cluster; | |
389 | } | |
390 | } | |
391 | ||
392 | if (p_chain->dir == EXFAT_EOF_CLUSTER) { | |
393 | p_chain->dir = new_clu; | |
394 | } else if (p_chain->flags == ALLOC_FAT_CHAIN) { | |
395 | if (exfat_ent_set(sb, last_clu, new_clu)) { | |
396 | ret = -EIO; | |
397 | goto free_cluster; | |
398 | } | |
399 | } | |
d5c514b6 YM |
400 | p_chain->size++; |
401 | ||
31023864 NJ |
402 | last_clu = new_clu; |
403 | ||
d5c514b6 | 404 | if (p_chain->size == num_alloc) { |
31023864 | 405 | sbi->clu_srch_ptr = hint_clu; |
d5c514b6 | 406 | sbi->used_clusters += num_alloc; |
31023864 | 407 | |
5c2d7285 | 408 | mutex_unlock(&sbi->bitmap_lock); |
31023864 NJ |
409 | return 0; |
410 | } | |
411 | ||
412 | hint_clu = new_clu + 1; | |
413 | if (hint_clu >= sbi->num_clusters) { | |
414 | hint_clu = EXFAT_FIRST_CLUSTER; | |
415 | ||
416 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
417 | if (exfat_chain_cont_cluster(sb, p_chain->dir, | |
d5c514b6 | 418 | p_chain->size)) { |
31023864 NJ |
419 | ret = -EIO; |
420 | goto free_cluster; | |
421 | } | |
422 | p_chain->flags = ALLOC_FAT_CHAIN; | |
423 | } | |
424 | } | |
425 | } | |
426 | free_cluster: | |
d5c514b6 | 427 | __exfat_free_cluster(inode, p_chain); |
5c2d7285 HK |
428 | unlock: |
429 | mutex_unlock(&sbi->bitmap_lock); | |
31023864 NJ |
430 | return ret; |
431 | } | |
432 | ||
433 | int exfat_count_num_clusters(struct super_block *sb, | |
434 | struct exfat_chain *p_chain, unsigned int *ret_count) | |
435 | { | |
436 | unsigned int i, count; | |
437 | unsigned int clu; | |
438 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
439 | ||
440 | if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { | |
441 | *ret_count = 0; | |
442 | return 0; | |
443 | } | |
444 | ||
445 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
446 | *ret_count = p_chain->size; | |
447 | return 0; | |
448 | } | |
449 | ||
450 | clu = p_chain->dir; | |
451 | count = 0; | |
452 | for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { | |
453 | count++; | |
454 | if (exfat_ent_get(sb, clu, &clu)) | |
455 | return -EIO; | |
456 | if (clu == EXFAT_EOF_CLUSTER) | |
457 | break; | |
458 | } | |
459 | ||
460 | *ret_count = count; | |
461 | return 0; | |
462 | } |