Pull exfat updates from Namjae Jeon: - Replace the internal table lookup algorithm with the hweight library and ffs of the bitops library. - Handle the two types of stream entry, valid data size (has been written) and data size separately. It improves compatibility with two differently sized files created on Windows. * tag 'exfat-for-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat: exfat: do not zero the extended part exfat: change to get file size from DataLength exfat: using ffs instead of internal logic exfat: using hweight instead of internal logic
Unified · Split
| @@ -5,42 +5,23 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | #include <linux/blkdev.h> |
| 7 | 7 | #include <linux/slab.h> |
| 8 | +#include <linux/bitmap.h> | |
| 8 | 9 | #include <linux/buffer_head.h> |
| 9 | 10 | |
| 10 | 11 | #include "exfat_raw.h" |
| 11 | 12 | #include "exfat_fs.h" |
| 12 | 13 | |
| 13 | −static const unsigned char free_bit[] = { | |
| 14 | − 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/ | |
| 15 | − 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/ | |
| 16 | − 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/ | |
| 17 | − 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/ | |
| 18 | − 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/ | |
| 19 | − 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/ | |
| 20 | − 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/ | |
| 21 | − 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/ | |
| 22 | − 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/ | |
| 23 | − 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/ | |
| 24 | − 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/ | |
| 25 | − 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/ | |
| 26 | − 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/ | |
| 27 | −}; | |
| 28 | − | |
| 29 | −static const unsigned char used_bit[] = { | |
| 30 | − 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/ | |
| 31 | − 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/ | |
| 32 | − 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/ | |
| 33 | − 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/ | |
| 34 | − 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/ | |
| 35 | − 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/ | |
| 36 | − 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/ | |
| 37 | − 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/ | |
| 38 | − 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/ | |
| 39 | − 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/ | |
| 40 | − 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/ | |
| 41 | − 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/ | |
| 42 | − 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/ | |
| 43 | −}; | |
| 14 | +#if BITS_PER_LONG == 32 | |
| 15 | +#define __le_long __le32 | |
| 16 | +#define lel_to_cpu(A) le32_to_cpu(A) | |
| 17 | +#define cpu_to_lel(A) cpu_to_le32(A) | |
| 18 | +#elif BITS_PER_LONG == 64 | |
| 19 | +#define __le_long __le64 | |
| 20 | +#define lel_to_cpu(A) le64_to_cpu(A) | |
| 21 | +#define cpu_to_lel(A) cpu_to_le64(A) | |
| 22 | +#else | |
| 23 | +#error "BITS_PER_LONG not 32 or 64" | |
| 24 | +#endif | |
| 44 | 25 | |
| 45 | 26 | /* |
| 46 | 27 | * Allocation Bitmap Management Functions |
| @@ -200,32 +181,35 @@ unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu) · 153 unmodified lines | ||
| 200 | 181 | { |
| 201 | 182 | unsigned int i, map_i, map_b, ent_idx; |
| 202 | 183 | unsigned int clu_base, clu_free; |
| 203 | − unsigned char k, clu_mask; | |
| 184 | + unsigned long clu_bits, clu_mask; | |
| 204 | 185 | struct exfat_sb_info *sbi = EXFAT_SB(sb); |
| 186 | + __le_long bitval; | |
| 205 | 187 | |
| 206 | 188 | WARN_ON(clu < EXFAT_FIRST_CLUSTER); |
| 207 | − ent_idx = CLUSTER_TO_BITMAP_ENT(clu); | |
| 208 | − clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK)); | |
| 189 | + ent_idx = ALIGN_DOWN(CLUSTER_TO_BITMAP_ENT(clu), BITS_PER_LONG); | |
| 190 | + clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx); | |
| 209 | 191 | clu_mask = IGNORED_BITS_REMAINED(clu, clu_base); |
| 210 | 192 | |
| 211 | 193 | map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); |
| 212 | 194 | map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx); |
| 213 | 195 | |
| 214 | 196 | for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; |
| 215 | − i += BITS_PER_BYTE) { | |
| 216 | − k = *(sbi->vol_amap[map_i]->b_data + map_b); | |
| 197 | + i += BITS_PER_LONG) { | |
| 198 | + bitval = *(__le_long *)(sbi->vol_amap[map_i]->b_data + map_b); | |
| 217 | 199 | if (clu_mask > 0) { |
| 218 | − k |= clu_mask; | |
| 200 | + bitval |= cpu_to_lel(clu_mask); | |
| 219 | 201 | clu_mask = 0; |
| 220 | 202 | } |
| 221 | − if (k < 0xFF) { | |
| 222 | − clu_free = clu_base + free_bit[k]; | |
| 203 | + if (lel_to_cpu(bitval) != ULONG_MAX) { | |
| 204 | + clu_bits = lel_to_cpu(bitval); | |
| 205 | + clu_free = clu_base + ffz(clu_bits); | |
| 223 | 206 | if (clu_free < sbi->num_clusters) |
| 224 | 207 | return clu_free; |
| 225 | 208 | } |
| 226 | − clu_base += BITS_PER_BYTE; | |
| 209 | + clu_base += BITS_PER_LONG; | |
| 210 | + map_b += sizeof(long); | |
| 227 | 211 | |
| 228 | − if (++map_b >= sb->s_blocksize || | |
| 212 | + if (map_b >= sb->s_blocksize || | |
| 229 | 213 | clu_base >= sbi->num_clusters) { |
| 230 | 214 | if (++map_i >= sbi->map_sectors) { |
| 231 | 215 | clu_base = EXFAT_FIRST_CLUSTER; |
| @@ -244,25 +228,24 @@ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count) · 12 unmodified lines | ||
| 244 | 228 | unsigned int count = 0; |
| 245 | 229 | unsigned int i, map_i = 0, map_b = 0; |
| 246 | 230 | unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi); |
| 247 | − unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK; | |
| 248 | − unsigned char clu_bits; | |
| 249 | − const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011, | |
| 250 | − 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111}; | |
| 231 | + unsigned int last_mask = total_clus & (BITS_PER_LONG - 1); | |
| 232 | + unsigned long *bitmap, clu_bits; | |
| 251 | 233 | |
| 252 | 234 | total_clus &= ~last_mask; |
| 253 | − for (i = 0; i < total_clus; i += BITS_PER_BYTE) { | |
| 254 | − clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); | |
| 255 | − count += used_bit[clu_bits]; | |
| 256 | − if (++map_b >= (unsigned int)sb->s_blocksize) { | |
| 235 | + for (i = 0; i < total_clus; i += BITS_PER_LONG) { | |
| 236 | + bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b); | |
| 237 | + count += hweight_long(*bitmap); | |
| 238 | + map_b += sizeof(long); | |
| 239 | + if (map_b >= (unsigned int)sb->s_blocksize) { | |
| 257 | 240 | map_i++; |
| 258 | 241 | map_b = 0; |
| 259 | 242 | } |
| 260 | 243 | } |
| 261 | 244 | |
| 262 | 245 | if (last_mask) { |
| 263 | − clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); | |
| 264 | − clu_bits &= last_bit_mask[last_mask]; | |
| 265 | − count += used_bit[clu_bits]; | |
| 246 | + bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b); | |
| 247 | + clu_bits = lel_to_cpu(*(__le_long *)bitmap); | |
| 248 | + count += hweight_long(clu_bits & BITMAP_LAST_WORD_MASK(last_mask)); | |
| 266 | 249 | } |
| 267 | 250 | |
| 268 | 251 | *ret_count = count; |
| @@ -135,8 +135,7 @@ enum { · 134 unmodified lines | ||
| 135 | 135 | #define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb)) |
| 136 | 136 | #define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \ |
| 137 | 137 | ((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1)) |
| 138 | −#define BITS_PER_BYTE_MASK 0x7 | |
| 139 | −#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1) | |
| 138 | +#define IGNORED_BITS_REMAINED(clu, clu_base) ((1UL << ((clu) - (clu_base))) - 1) | |
| 140 | 139 | |
| 141 | 140 | #define ES_ENTRY_NUM(name_len) (ES_IDX_LAST_FILENAME(name_len) + 1) |
| 142 | 141 | /* 19 entries = 1 file entry + 1 stream entry + 17 filename entries */ |
| @@ -208,6 +207,7 @@ struct exfat_dir_entry { · 65 unmodified lines | ||
| 208 | 207 | unsigned char flags; |
| 209 | 208 | unsigned short attr; |
| 210 | 209 | loff_t size; |
| 210 | + loff_t valid_size; | |
| 211 | 211 | unsigned int num_subdirs; |
| 212 | 212 | struct timespec64 atime; |
| 213 | 213 | struct timespec64 mtime; |
| @@ -317,6 +317,7 @@ struct exfat_inode_info { · 103 unmodified lines | ||
| 317 | 317 | loff_t i_size_aligned; |
| 318 | 318 | /* on-disk position of directory entry or 0 */ |
| 319 | 319 | loff_t i_pos; |
| 320 | + loff_t valid_size; | |
| 320 | 321 | /* hash by i_location */ |
| 321 | 322 | struct hlist_node i_hash_fat; |
| 322 | 323 | /* protect bmap against truncate */ |
| @@ -11,37 +11,76 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/fsnotify.h> |
| 12 | 12 | #include <linux/security.h> |
| 13 | 13 | #include <linux/msdos_fs.h> |
| 14 | +#include <linux/writeback.h> | |
| 14 | 15 | |
| 15 | 16 | #include "exfat_raw.h" |
| 16 | 17 | #include "exfat_fs.h" |
| 17 | 18 | |
| 18 | 19 | static int exfat_cont_expand(struct inode *inode, loff_t size) |
| 19 | 20 | { |
| 20 | − struct address_space *mapping = inode->i_mapping; | |
| 21 | − loff_t start = i_size_read(inode), count = size - i_size_read(inode); | |
| 22 | − int err, err2; | |
| 21 | + int ret; | |
| 22 | + unsigned int num_clusters, new_num_clusters, last_clu; | |
| 23 | + struct exfat_inode_info *ei = EXFAT_I(inode); | |
| 24 | + struct super_block *sb = inode->i_sb; | |
| 25 | + struct exfat_sb_info *sbi = EXFAT_SB(sb); | |
| 26 | + struct exfat_chain clu; | |
| 23 | 27 | |
| 24 | − err = generic_cont_expand_simple(inode, size); | |
| 25 | − if (err) | |
| 26 | − return err; | |
| 28 | + ret = inode_newsize_ok(inode, size); | |
| 29 | + if (ret) | |
| 30 | + return ret; | |
| 31 | + | |
| 32 | + num_clusters = EXFAT_B_TO_CLU_ROUND_UP(ei->i_size_ondisk, sbi); | |
| 33 | + new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi); | |
| 34 | + | |
| 35 | + if (new_num_clusters == num_clusters) | |
| 36 | + goto out; | |
| 37 | + | |
| 38 | + exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags); | |
| 39 | + ret = exfat_find_last_cluster(sb, &clu, &last_clu); | |
| 40 | + if (ret) | |
| 41 | + return ret; | |
| 42 | + | |
| 43 | + clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ? | |
| 44 | + EXFAT_EOF_CLUSTER : last_clu + 1; | |
| 45 | + clu.size = 0; | |
| 46 | + clu.flags = ei->flags; | |
| 47 | + | |
| 48 | + ret = exfat_alloc_cluster(inode, new_num_clusters - num_clusters, | |
| 49 | + &clu, IS_DIRSYNC(inode)); | |
| 50 | + if (ret) | |
| 51 | + return ret; | |
| 52 | + | |
| 53 | + /* Append new clusters to chain */ | |
| 54 | + if (clu.flags != ei->flags) { | |
| 55 | + exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters); | |
| 56 | + ei->flags = ALLOC_FAT_CHAIN; | |
| 57 | + } | |
| 58 | + if (clu.flags == ALLOC_FAT_CHAIN) | |
| 59 | + if (exfat_ent_set(sb, last_clu, clu.dir)) | |
| 60 | + goto free_clu; | |
| 27 | 61 | |
| 62 | + if (num_clusters == 0) | |
| 63 | + ei->start_clu = clu.dir; | |
| 64 | + | |
| 65 | +out: | |
| 28 | 66 | inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); |
| 29 | − mark_inode_dirty(inode); | |
| 67 | + /* Expanded range not zeroed, do not update valid_size */ | |
| 68 | + i_size_write(inode, size); | |
| 30 | 69 | |
| 31 | − if (!IS_SYNC(inode)) | |
| 32 | − return 0; | |
| 70 | + ei->i_size_aligned = round_up(size, sb->s_blocksize); | |
| 71 | + ei->i_size_ondisk = ei->i_size_aligned; | |
| 72 | + inode->i_blocks = round_up(size, sbi->cluster_size) >> 9; | |
| 33 | 73 | |
| 34 | − err = filemap_fdatawrite_range(mapping, start, start + count - 1); | |
| 35 | − err2 = sync_mapping_buffers(mapping); | |
| 36 | − if (!err) | |
| 37 | − err = err2; | |
| 38 | − err2 = write_inode_now(inode, 1); | |
| 39 | − if (!err) | |
| 40 | − err = err2; | |
| 41 | − if (err) | |
| 42 | − return err; | |
| 74 | + if (IS_DIRSYNC(inode)) | |
| 75 | + return write_inode_now(inode, 1); | |
| 76 | + | |
| 77 | + mark_inode_dirty(inode); | |
| 43 | 78 | |
| 44 | − return filemap_fdatawait_range(mapping, start, start + count - 1); | |
| 79 | + return 0; | |
| 80 | + | |
| 81 | +free_clu: | |
| 82 | + exfat_free_cluster(inode, &clu); | |
| 83 | + return -EIO; | |
| 45 | 84 | } |
| 46 | 85 | |
| 47 | 86 | static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) |
| @@ -146,6 +185,9 @@ int __exfat_truncate(struct inode *inode) · 98 unmodified lines | ||
| 146 | 185 | ei->start_clu = EXFAT_EOF_CLUSTER; |
| 147 | 186 | } |
| 148 | 187 | |
| 188 | + if (i_size_read(inode) < ei->valid_size) | |
| 189 | + ei->valid_size = i_size_read(inode); | |
| 190 | + | |
| 149 | 191 | if (ei->type == TYPE_FILE) |
| 150 | 192 | ei->attr |= EXFAT_ATTR_ARCHIVE; |
| 151 | 193 | |
| @@ -474,15 +516,124 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) · 322 unmodified lines | ||
| 474 | 516 | return blkdev_issue_flush(inode->i_sb->s_bdev); |
| 475 | 517 | } |
| 476 | 518 | |
| 519 | +static int exfat_file_zeroed_range(struct file *file, loff_t start, loff_t end) | |
| 520 | +{ | |
| 521 | + int err; | |
| 522 | + struct inode *inode = file_inode(file); | |
| 523 | + struct address_space *mapping = inode->i_mapping; | |
| 524 | + const struct address_space_operations *ops = mapping->a_ops; | |
| 525 | + | |
| 526 | + while (start < end) { | |
| 527 | + u32 zerofrom, len; | |
| 528 | + struct page *page = NULL; | |
| 529 | + | |
| 530 | + zerofrom = start & (PAGE_SIZE - 1); | |
| 531 | + len = PAGE_SIZE - zerofrom; | |
| 532 | + if (start + len > end) | |
| 533 | + len = end - start; | |
| 534 | + | |
| 535 | + err = ops->write_begin(file, mapping, start, len, &page, NULL); | |
| 536 | + if (err) | |
| 537 | + goto out; | |
| 538 | + | |
| 539 | + zero_user_segment(page, zerofrom, zerofrom + len); | |
| 540 | + | |
| 541 | + err = ops->write_end(file, mapping, start, len, len, page, NULL); | |
| 542 | + if (err < 0) | |
| 543 | + goto out; | |
| 544 | + start += len; | |
| 545 | + | |
| 546 | + balance_dirty_pages_ratelimited(mapping); | |
| 547 | + cond_resched(); | |
| 548 | + } | |
| 549 | + | |
| 550 | +out: | |
| 551 | + return err; | |
| 552 | +} | |
| 553 | + | |
| 554 | +static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) | |
| 555 | +{ | |
| 556 | + ssize_t ret; | |
| 557 | + struct file *file = iocb->ki_filp; | |
| 558 | + struct inode *inode = file_inode(file); | |
| 559 | + struct exfat_inode_info *ei = EXFAT_I(inode); | |
| 560 | + loff_t pos = iocb->ki_pos; | |
| 561 | + loff_t valid_size; | |
| 562 | + | |
| 563 | + inode_lock(inode); | |
| 564 | + | |
| 565 | + valid_size = ei->valid_size; | |
| 566 | + | |
| 567 | + ret = generic_write_checks(iocb, iter); | |
| 568 | + if (ret < 0) | |
| 569 | + goto unlock; | |
| 570 | + | |
| 571 | + if (pos > valid_size) { | |
| 572 | + ret = exfat_file_zeroed_range(file, valid_size, pos); | |
| 573 | + if (ret < 0 && ret != -ENOSPC) { | |
| 574 | + exfat_err(inode->i_sb, | |
| 575 | + "write: fail to zero from %llu to %llu(%zd)", | |
| 576 | + valid_size, pos, ret); | |
| 577 | + } | |
| 578 | + if (ret < 0) | |
| 579 | + goto unlock; | |
| 580 | + } | |
| 581 | + | |
| 582 | + ret = __generic_file_write_iter(iocb, iter); | |
| 583 | + if (ret < 0) | |
| 584 | + goto unlock; | |
| 585 | + | |
| 586 | + inode_unlock(inode); | |
| 587 | + | |
| 588 | + if (pos > valid_size) | |
| 589 | + pos = valid_size; | |
| 590 | + | |
| 591 | + if (iocb_is_dsync(iocb) && iocb->ki_pos > pos) { | |
| 592 | + ssize_t err = vfs_fsync_range(file, pos, iocb->ki_pos - 1, | |
| 593 | + iocb->ki_flags & IOCB_SYNC); | |
| 594 | + if (err < 0) | |
| 595 | + return err; | |
| 596 | + } | |
| 597 | + | |
| 598 | + return ret; | |
| 599 | + | |
| 600 | +unlock: | |
| 601 | + inode_unlock(inode); | |
| 602 | + | |
| 603 | + return ret; | |
| 604 | +} | |
| 605 | + | |
| 606 | +static int exfat_file_mmap(struct file *file, struct vm_area_struct *vma) | |
| 607 | +{ | |
| 608 | + int ret; | |
| 609 | + struct inode *inode = file_inode(file); | |
| 610 | + struct exfat_inode_info *ei = EXFAT_I(inode); | |
| 611 | + loff_t start = ((loff_t)vma->vm_pgoff << PAGE_SHIFT); | |
| 612 | + loff_t end = min_t(loff_t, i_size_read(inode), | |
| 613 | + start + vma->vm_end - vma->vm_start); | |
| 614 | + | |
| 615 | + if ((vma->vm_flags & VM_WRITE) && ei->valid_size < end) { | |
| 616 | + ret = exfat_file_zeroed_range(file, ei->valid_size, end); | |
| 617 | + if (ret < 0) { | |
| 618 | + exfat_err(inode->i_sb, | |
| 619 | + "mmap: fail to zero from %llu to %llu(%d)", | |
| 620 | + start, end, ret); | |
| 621 | + return ret; | |
| 622 | + } | |
| 623 | + } | |
| 624 | + | |
| 625 | + return generic_file_mmap(file, vma); | |
| 626 | +} | |
| 627 | + | |
| 477 | 628 | const struct file_operations exfat_file_operations = { |
| 478 | 629 | .llseek = generic_file_llseek, |
| 479 | 630 | .read_iter = generic_file_read_iter, |
| 480 | − .write_iter = generic_file_write_iter, | |
| 631 | + .write_iter = exfat_file_write_iter, | |
| 481 | 632 | .unlocked_ioctl = exfat_ioctl, |
| 482 | 633 | #ifdef CONFIG_COMPAT |
| 483 | 634 | .compat_ioctl = exfat_compat_ioctl, |
| 484 | 635 | #endif |
| 485 | − .mmap = generic_file_mmap, | |
| 636 | + .mmap = exfat_file_mmap, | |
| 486 | 637 | .fsync = exfat_file_fsync, |
| 487 | 638 | .splice_read = filemap_splice_read, |
| 488 | 639 | .splice_write = iter_file_splice_write, |
| @@ -75,8 +75,17 @@ int __exfat_write_inode(struct inode *inode, int sync) · 74 unmodified lines | ||
| 75 | 75 | if (ei->start_clu == EXFAT_EOF_CLUSTER) |
| 76 | 76 | on_disk_size = 0; |
| 77 | 77 | |
| 78 | − ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); | |
| 79 | − ep2->dentry.stream.size = ep2->dentry.stream.valid_size; | |
| 78 | + ep2->dentry.stream.size = cpu_to_le64(on_disk_size); | |
| 79 | + /* | |
| 80 | + * mmap write does not use exfat_write_end(), valid_size may be | |
| 81 | + * extended to the sector-aligned length in exfat_get_block(). | |
| 82 | + * So we need to fixup valid_size to the writren length. | |
| 83 | + */ | |
| 84 | + if (on_disk_size < ei->valid_size) | |
| 85 | + ep2->dentry.stream.valid_size = ep2->dentry.stream.size; | |
| 86 | + else | |
| 87 | + ep2->dentry.stream.valid_size = cpu_to_le64(ei->valid_size); | |
| 88 | + | |
| 80 | 89 | if (on_disk_size) { |
| 81 | 90 | ep2->dentry.stream.flags = ei->flags; |
| 82 | 91 | ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu); |
| @@ -278,6 +287,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, · 195 unmodified lines | ||
| 278 | 287 | unsigned int cluster, sec_offset; |
| 279 | 288 | sector_t last_block; |
| 280 | 289 | sector_t phys = 0; |
| 290 | + sector_t valid_blks; | |
| 281 | 291 | loff_t pos; |
| 282 | 292 | |
| 283 | 293 | mutex_lock(&sbi->s_lock); |
| @@ -306,17 +316,32 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, · 22 unmodified lines | ||
| 306 | 316 | mapped_blocks = sbi->sect_per_clus - sec_offset; |
| 307 | 317 | max_blocks = min(mapped_blocks, max_blocks); |
| 308 | 318 | |
| 309 | − /* Treat newly added block / cluster */ | |
| 310 | − if (iblock < last_block) | |
| 311 | − create = 0; | |
| 312 | − | |
| 313 | − if (create || buffer_delay(bh_result)) { | |
| 314 | − pos = EXFAT_BLK_TO_B((iblock + 1), sb); | |
| 319 | + pos = EXFAT_BLK_TO_B((iblock + 1), sb); | |
| 320 | + if ((create && iblock >= last_block) || buffer_delay(bh_result)) { | |
| 315 | 321 | if (ei->i_size_ondisk < pos) |
| 316 | 322 | ei->i_size_ondisk = pos; |
| 317 | 323 | } |
| 318 | 324 | |
| 325 | + map_bh(bh_result, sb, phys); | |
| 326 | + if (buffer_delay(bh_result)) | |
| 327 | + clear_buffer_delay(bh_result); | |
| 328 | + | |
| 319 | 329 | if (create) { |
| 330 | + valid_blks = EXFAT_B_TO_BLK_ROUND_UP(ei->valid_size, sb); | |
| 331 | + | |
| 332 | + if (iblock + max_blocks < valid_blks) { | |
| 333 | + /* The range has been written, map it */ | |
| 334 | + goto done; | |
| 335 | + } else if (iblock < valid_blks) { | |
| 336 | + /* | |
| 337 | + * The range has been partially written, | |
| 338 | + * map the written part. | |
| 339 | + */ | |
| 340 | + max_blocks = valid_blks - iblock; | |
| 341 | + goto done; | |
| 342 | + } | |
| 343 | + | |
| 344 | + /* The area has not been written, map and mark as new. */ | |
| 320 | 345 | err = exfat_map_new_buffer(ei, bh_result, pos); |
| 321 | 346 | if (err) { |
| 322 | 347 | exfat_fs_error(sb, |
| @@ -324,11 +349,58 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, · 1 unmodified line | ||
| 324 | 349 | pos, ei->i_size_aligned); |
| 325 | 350 | goto unlock_ret; |
| 326 | 351 | } |
| 327 | − } | |
| 328 | 352 | |
| 329 | − if (buffer_delay(bh_result)) | |
| 330 | − clear_buffer_delay(bh_result); | |
| 331 | − map_bh(bh_result, sb, phys); | |
| 353 | + ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb); | |
| 354 | + mark_inode_dirty(inode); | |
| 355 | + } else { | |
| 356 | + valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb); | |
| 357 | + | |
| 358 | + if (iblock + max_blocks < valid_blks) { | |
| 359 | + /* The range has been written, map it */ | |
| 360 | + goto done; | |
| 361 | + } else if (iblock < valid_blks) { | |
| 362 | + /* | |
| 363 | + * The area has been partially written, | |
| 364 | + * map the written part. | |
| 365 | + */ | |
| 366 | + max_blocks = valid_blks - iblock; | |
| 367 | + goto done; | |
| 368 | + } else if (iblock == valid_blks && | |
| 369 | + (ei->valid_size & (sb->s_blocksize - 1))) { | |
| 370 | + /* | |
| 371 | + * The block has been partially written, | |
| 372 | + * zero the unwritten part and map the block. | |
| 373 | + */ | |
| 374 | + loff_t size, off; | |
| 375 | + | |
| 376 | + max_blocks = 1; | |
| 377 | + | |
| 378 | + /* | |
| 379 | + * For direct read, the unwritten part will be zeroed in | |
| 380 | + * exfat_direct_IO() | |
| 381 | + */ | |
| 382 | + if (!bh_result->b_folio) | |
| 383 | + goto done; | |
| 384 | + | |
| 385 | + pos -= sb->s_blocksize; | |
| 386 | + size = ei->valid_size - pos; | |
| 387 | + off = pos & (PAGE_SIZE - 1); | |
| 388 | + | |
| 389 | + folio_set_bh(bh_result, bh_result->b_folio, off); | |
| 390 | + err = bh_read(bh_result, 0); | |
| 391 | + if (err < 0) | |
| 392 | + goto unlock_ret; | |
| 393 | + | |
| 394 | + folio_zero_segment(bh_result->b_folio, off + size, | |
| 395 | + off + sb->s_blocksize); | |
| 396 | + } else { | |
| 397 | + /* | |
| 398 | + * The range has not been written, clear the mapped flag | |
| 399 | + * to only zero the cache and do not read from disk. | |
| 400 | + */ | |
| 401 | + clear_buffer_mapped(bh_result); | |
| 402 | + } | |
| 403 | + } | |
| 332 | 404 | done: |
| 333 | 405 | bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); |
| 334 | 406 | unlock_ret: |
| @@ -343,6 +415,17 @@ static int exfat_read_folio(struct file *file, struct folio *folio) · 8 unmodified lines | ||
| 343 | 415 | |
| 344 | 416 | static void exfat_readahead(struct readahead_control *rac) |
| 345 | 417 | { |
| 418 | + struct address_space *mapping = rac->mapping; | |
| 419 | + struct inode *inode = mapping->host; | |
| 420 | + struct exfat_inode_info *ei = EXFAT_I(inode); | |
| 421 | + loff_t pos = readahead_pos(rac); | |
| 422 | + | |
| 423 | + /* Range cross valid_size, read it page by page. */ | |
| 424 | + if (ei->valid_size < i_size_read(inode) && | |
| 425 | + pos <= ei->valid_size && | |
| 426 | + ei->valid_size < pos + readahead_length(rac)) | |
| 427 | + return; | |
| 428 | + | |
| 346 | 429 | mpage_readahead(rac, exfat_get_block); |
| 347 | 430 | } |
| 348 | 431 | |
| @@ -370,9 +453,7 @@ static int exfat_write_begin(struct file *file, struct address_space *mapping, · 21 unmodified lines | ||
| 370 | 453 | int ret; |
| 371 | 454 | |
| 372 | 455 | *pagep = NULL; |
| 373 | − ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata, | |
| 374 | − exfat_get_block, | |
| 375 | − &EXFAT_I(mapping->host)->i_size_ondisk); | |
| 456 | + ret = block_write_begin(mapping, pos, len, pagep, exfat_get_block); | |
| 376 | 457 | |
| 377 | 458 | if (ret < 0) |
| 378 | 459 | exfat_write_failed(mapping, pos+len); |
| @@ -400,6 +481,11 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, · 21 unmodified lines | ||
| 400 | 481 | if (err < len) |
| 401 | 482 | exfat_write_failed(mapping, pos+len); |
| 402 | 483 | |
| 484 | + if (!(err < 0) && pos + err > ei->valid_size) { | |
| 485 | + ei->valid_size = pos + err; | |
| 486 | + mark_inode_dirty(inode); | |
| 487 | + } | |
| 488 | + | |
| 403 | 489 | if (!(err < 0) && !(ei->attr & EXFAT_ATTR_ARCHIVE)) { |
| 404 | 490 | inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); |
| 405 | 491 | ei->attr |= EXFAT_ATTR_ARCHIVE; |
| @@ -413,6 +499,8 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) · 7 unmodified lines | ||
| 413 | 499 | { |
| 414 | 500 | struct address_space *mapping = iocb->ki_filp->f_mapping; |
| 415 | 501 | struct inode *inode = mapping->host; |
| 502 | + struct exfat_inode_info *ei = EXFAT_I(inode); | |
| 503 | + loff_t pos = iocb->ki_pos; | |
| 416 | 504 | loff_t size = iocb->ki_pos + iov_iter_count(iter); |
| 417 | 505 | int rw = iov_iter_rw(iter); |
| 418 | 506 | ssize_t ret; |
| @@ -436,8 +524,21 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) · 17 unmodified lines | ||
| 436 | 524 | * condition of exfat_get_block() and ->truncate(). |
| 437 | 525 | */ |
| 438 | 526 | ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); |
| 439 | − if (ret < 0 && (rw & WRITE)) | |
| 440 | − exfat_write_failed(mapping, size); | |
| 527 | + if (ret < 0) { | |
| 528 | + if (rw == WRITE) | |
| 529 | + exfat_write_failed(mapping, size); | |
| 530 | + | |
| 531 | + if (ret != -EIOCBQUEUED) | |
| 532 | + return ret; | |
| 533 | + } else | |
| 534 | + size = pos + ret; | |
| 535 | + | |
| 536 | + /* zero the unwritten part in the partially written block */ | |
| 537 | + if (rw == READ && pos < ei->valid_size && ei->valid_size < size) { | |
| 538 | + iov_iter_revert(iter, size - ei->valid_size); | |
| 539 | + iov_iter_zero(size - ei->valid_size, iter); | |
| 540 | + } | |
| 541 | + | |
| 441 | 542 | return ret; |
| 442 | 543 | } |
| 443 | 544 | |
| @@ -537,6 +638,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) · 93 unmodified lines | ||
| 537 | 638 | ei->start_clu = info->start_clu; |
| 538 | 639 | ei->flags = info->flags; |
| 539 | 640 | ei->type = info->type; |
| 641 | + ei->valid_size = info->valid_size; | |
| 540 | 642 | |
| 541 | 643 | ei->version = 0; |
| 542 | 644 | ei->hint_stat.eidx = 0; |
| @@ -406,6 +406,7 @@ static int exfat_find_empty_entry(struct inode *inode, · 405 unmodified lines | ||
| 406 | 406 | i_size_write(inode, size); |
| 407 | 407 | ei->i_size_ondisk += sbi->cluster_size; |
| 408 | 408 | ei->i_size_aligned += sbi->cluster_size; |
| 409 | + ei->valid_size += sbi->cluster_size; | |
| 409 | 410 | ei->flags = p_dir->flags; |
| 410 | 411 | inode->i_blocks += sbi->cluster_size >> 9; |
| 411 | 412 | } |
| @@ -558,6 +559,8 @@ static int exfat_add_entry(struct inode *inode, const char *path, · 146 unmodified lines | ||
| 558 | 559 | info->size = clu_size; |
| 559 | 560 | info->num_subdirs = EXFAT_MIN_SUBDIR; |
| 560 | 561 | } |
| 562 | + info->valid_size = info->size; | |
| 563 | + | |
| 561 | 564 | memset(&info->crtime, 0, sizeof(info->crtime)); |
| 562 | 565 | memset(&info->mtime, 0, sizeof(info->mtime)); |
| 563 | 566 | memset(&info->atime, 0, sizeof(info->atime)); |
| @@ -660,6 +663,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname, · 96 unmodified lines | ||
| 660 | 663 | info->type = exfat_get_entry_type(ep); |
| 661 | 664 | info->attr = le16_to_cpu(ep->dentry.file.attr); |
| 662 | 665 | info->size = le64_to_cpu(ep2->dentry.stream.valid_size); |
| 666 | + info->valid_size = le64_to_cpu(ep2->dentry.stream.valid_size); | |
| 667 | + info->size = le64_to_cpu(ep2->dentry.stream.size); | |
| 663 | 668 | if (info->size == 0) { |
| 664 | 669 | info->flags = ALLOC_NO_FAT_CHAIN; |
| 665 | 670 | info->start_clu = EXFAT_EOF_CLUSTER; |
| @@ -1288,6 +1293,7 @@ static int __exfat_rename(struct inode *old_parent_inode, · 622 unmodified lines | ||
| 1288 | 1293 | } |
| 1289 | 1294 | |
| 1290 | 1295 | i_size_write(new_inode, 0); |
| 1296 | + new_ei->valid_size = 0; | |
| 1291 | 1297 | new_ei->start_clu = EXFAT_EOF_CLUSTER; |
| 1292 | 1298 | new_ei->flags = ALLOC_NO_FAT_CHAIN; |
| 1293 | 1299 | } |