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> | |
7 | #include <asm/unaligned.h> | |
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; |
31023864 NJ |
219 | } while (clu != EXFAT_EOF_CLUSTER); |
220 | } | |
221 | ||
222 | dec_used_clus: | |
223 | sbi->used_clusters -= num_clusters; | |
224 | return 0; | |
225 | } | |
226 | ||
5c2d7285 HK |
227 | int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) |
228 | { | |
229 | int ret = 0; | |
230 | ||
231 | mutex_lock(&EXFAT_SB(inode->i_sb)->bitmap_lock); | |
232 | ret = __exfat_free_cluster(inode, p_chain); | |
233 | mutex_unlock(&EXFAT_SB(inode->i_sb)->bitmap_lock); | |
234 | ||
235 | return ret; | |
236 | } | |
237 | ||
31023864 NJ |
238 | int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, |
239 | unsigned int *ret_clu) | |
240 | { | |
241 | unsigned int clu, next; | |
242 | unsigned int count = 0; | |
243 | ||
244 | next = p_chain->dir; | |
245 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
246 | *ret_clu = next + p_chain->size - 1; | |
247 | return 0; | |
248 | } | |
249 | ||
250 | do { | |
251 | count++; | |
252 | clu = next; | |
253 | if (exfat_ent_get(sb, clu, &next)) | |
254 | return -EIO; | |
255 | } while (next != EXFAT_EOF_CLUSTER); | |
256 | ||
257 | if (p_chain->size != count) { | |
258 | exfat_fs_error(sb, | |
259 | "bogus directory size (clus : ondisk(%d) != counted(%d))", | |
260 | p_chain->size, count); | |
261 | return -EIO; | |
262 | } | |
263 | ||
264 | *ret_clu = clu; | |
265 | return 0; | |
266 | } | |
267 | ||
31023864 NJ |
268 | int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) |
269 | { | |
270 | struct super_block *sb = dir->i_sb; | |
271 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
1b613838 | 272 | struct buffer_head *bh; |
2e9ceb67 | 273 | sector_t blknr, last_blknr, i; |
31023864 NJ |
274 | |
275 | blknr = exfat_cluster_to_sector(sbi, clu); | |
276 | last_blknr = blknr + sbi->sect_per_clus; | |
277 | ||
278 | if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { | |
279 | exfat_fs_error_ratelimit(sb, | |
280 | "%s: out of range(sect:%llu len:%u)", | |
281 | __func__, (unsigned long long)blknr, | |
282 | sbi->sect_per_clus); | |
283 | return -EIO; | |
284 | } | |
285 | ||
286 | /* Zeroing the unused blocks on this cluster */ | |
1b613838 YM |
287 | for (i = blknr; i < last_blknr; i++) { |
288 | bh = sb_getblk(sb, i); | |
289 | if (!bh) | |
290 | return -ENOMEM; | |
31023864 | 291 | |
1b613838 YM |
292 | memset(bh->b_data, 0, sb->s_blocksize); |
293 | set_buffer_uptodate(bh); | |
294 | mark_buffer_dirty(bh); | |
295 | brelse(bh); | |
4dc7d35e | 296 | } |
31023864 | 297 | |
1b613838 YM |
298 | if (IS_DIRSYNC(dir)) |
299 | return sync_blockdev_range(sb->s_bdev, | |
300 | EXFAT_BLK_TO_B(blknr, sb), | |
301 | EXFAT_BLK_TO_B(last_blknr, sb) - 1); | |
302 | ||
303 | return 0; | |
31023864 NJ |
304 | } |
305 | ||
306 | int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, | |
23befe49 | 307 | struct exfat_chain *p_chain, bool sync_bmap) |
31023864 NJ |
308 | { |
309 | int ret = -ENOSPC; | |
d5c514b6 | 310 | unsigned int total_cnt; |
31023864 NJ |
311 | unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; |
312 | struct super_block *sb = inode->i_sb; | |
313 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
314 | ||
315 | total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); | |
316 | ||
317 | if (unlikely(total_cnt < sbi->used_clusters)) { | |
318 | exfat_fs_error_ratelimit(sb, | |
319 | "%s: invalid used clusters(t:%u,u:%u)\n", | |
320 | __func__, total_cnt, sbi->used_clusters); | |
321 | return -EIO; | |
322 | } | |
323 | ||
324 | if (num_alloc > total_cnt - sbi->used_clusters) | |
325 | return -ENOSPC; | |
326 | ||
5c2d7285 HK |
327 | mutex_lock(&sbi->bitmap_lock); |
328 | ||
31023864 NJ |
329 | hint_clu = p_chain->dir; |
330 | /* find new cluster */ | |
331 | if (hint_clu == EXFAT_EOF_CLUSTER) { | |
332 | if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { | |
512b74d1 | 333 | exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)", |
d1727d55 | 334 | sbi->clu_srch_ptr); |
31023864 NJ |
335 | sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; |
336 | } | |
337 | ||
338 | hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); | |
5c2d7285 HK |
339 | if (hint_clu == EXFAT_EOF_CLUSTER) { |
340 | ret = -ENOSPC; | |
341 | goto unlock; | |
342 | } | |
31023864 NJ |
343 | } |
344 | ||
345 | /* check cluster validation */ | |
a949824f | 346 | if (!is_valid_cluster(sbi, hint_clu)) { |
3ce937cb YM |
347 | if (hint_clu != sbi->num_clusters) |
348 | exfat_err(sb, "hint_cluster is invalid (%u), rewind to the first cluster", | |
349 | hint_clu); | |
31023864 | 350 | hint_clu = EXFAT_FIRST_CLUSTER; |
8d2909ee | 351 | p_chain->flags = ALLOC_FAT_CHAIN; |
31023864 NJ |
352 | } |
353 | ||
31023864 NJ |
354 | p_chain->dir = EXFAT_EOF_CLUSTER; |
355 | ||
356 | while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != | |
357 | EXFAT_EOF_CLUSTER) { | |
358 | if (new_clu != hint_clu && | |
359 | p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
360 | if (exfat_chain_cont_cluster(sb, p_chain->dir, | |
d5c514b6 | 361 | p_chain->size)) { |
31023864 NJ |
362 | ret = -EIO; |
363 | goto free_cluster; | |
364 | } | |
365 | p_chain->flags = ALLOC_FAT_CHAIN; | |
366 | } | |
367 | ||
368 | /* update allocation bitmap */ | |
23befe49 | 369 | if (exfat_set_bitmap(inode, new_clu, sync_bmap)) { |
31023864 NJ |
370 | ret = -EIO; |
371 | goto free_cluster; | |
372 | } | |
373 | ||
31023864 NJ |
374 | /* update FAT table */ |
375 | if (p_chain->flags == ALLOC_FAT_CHAIN) { | |
376 | if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { | |
377 | ret = -EIO; | |
378 | goto free_cluster; | |
379 | } | |
380 | } | |
381 | ||
382 | if (p_chain->dir == EXFAT_EOF_CLUSTER) { | |
383 | p_chain->dir = new_clu; | |
384 | } else if (p_chain->flags == ALLOC_FAT_CHAIN) { | |
385 | if (exfat_ent_set(sb, last_clu, new_clu)) { | |
386 | ret = -EIO; | |
387 | goto free_cluster; | |
388 | } | |
389 | } | |
d5c514b6 YM |
390 | p_chain->size++; |
391 | ||
31023864 NJ |
392 | last_clu = new_clu; |
393 | ||
d5c514b6 | 394 | if (p_chain->size == num_alloc) { |
31023864 | 395 | sbi->clu_srch_ptr = hint_clu; |
d5c514b6 | 396 | sbi->used_clusters += num_alloc; |
31023864 | 397 | |
5c2d7285 | 398 | mutex_unlock(&sbi->bitmap_lock); |
31023864 NJ |
399 | return 0; |
400 | } | |
401 | ||
402 | hint_clu = new_clu + 1; | |
403 | if (hint_clu >= sbi->num_clusters) { | |
404 | hint_clu = EXFAT_FIRST_CLUSTER; | |
405 | ||
406 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
407 | if (exfat_chain_cont_cluster(sb, p_chain->dir, | |
d5c514b6 | 408 | p_chain->size)) { |
31023864 NJ |
409 | ret = -EIO; |
410 | goto free_cluster; | |
411 | } | |
412 | p_chain->flags = ALLOC_FAT_CHAIN; | |
413 | } | |
414 | } | |
415 | } | |
416 | free_cluster: | |
d5c514b6 | 417 | __exfat_free_cluster(inode, p_chain); |
5c2d7285 HK |
418 | unlock: |
419 | mutex_unlock(&sbi->bitmap_lock); | |
31023864 NJ |
420 | return ret; |
421 | } | |
422 | ||
423 | int exfat_count_num_clusters(struct super_block *sb, | |
424 | struct exfat_chain *p_chain, unsigned int *ret_count) | |
425 | { | |
426 | unsigned int i, count; | |
427 | unsigned int clu; | |
428 | struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
429 | ||
430 | if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { | |
431 | *ret_count = 0; | |
432 | return 0; | |
433 | } | |
434 | ||
435 | if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { | |
436 | *ret_count = p_chain->size; | |
437 | return 0; | |
438 | } | |
439 | ||
440 | clu = p_chain->dir; | |
441 | count = 0; | |
442 | for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { | |
443 | count++; | |
444 | if (exfat_ent_get(sb, clu, &clu)) | |
445 | return -EIO; | |
446 | if (clu == EXFAT_EOF_CLUSTER) | |
447 | break; | |
448 | } | |
449 | ||
450 | *ret_count = count; | |
451 | return 0; | |
452 | } |