mirror of https://github.com/OpenIPC/firmware.git
238 lines
5.9 KiB
Diff
238 lines
5.9 KiB
Diff
diff -drupN a/fs/fat/fatent.c b/fs/fat/fatent.c
|
|
--- a/fs/fat/fatent.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/fs/fat/fatent.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -380,6 +380,9 @@ static int fat_mirror_bhs(struct super_b
|
|
int err, n, copy;
|
|
|
|
err = 0;
|
|
+#ifdef CONFIG_FAT1_UPDATE_ONLY
|
|
+ return 0;
|
|
+#endif
|
|
for (copy = 1; copy < sbi->fats; copy++) {
|
|
sector_t backup_fat = sbi->fat_length * copy;
|
|
|
|
@@ -458,6 +461,51 @@ static void fat_collect_bhs(struct buffe
|
|
}
|
|
}
|
|
}
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+int fat_caculate_cluster(struct inode *inode)
|
|
+{
|
|
+ struct super_block *sb = inode->i_sb;
|
|
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
+ const struct fatent_operations *ops = sbi->fatent_ops;
|
|
+ struct fat_entry fatent;
|
|
+ unsigned int nr_cluster = 0;
|
|
+ int err = 0, cluster = 0;
|
|
+ fatent_init(&fatent);
|
|
+ fatent_set_entry(&fatent, MSDOS_I(inode)->i_start);
|
|
+ err = fat_ent_read_block(sb, &fatent);
|
|
+ if (err)
|
|
+ goto error;
|
|
+
|
|
+ while (ops->ent_get(&fatent) != FAT_ENT_EOF) {
|
|
+ cluster = ops->ent_get(&fatent);
|
|
+ if (cluster < 0) {
|
|
+ err = cluster;
|
|
+ pr_err("FAT ERR: %s: invalid FAT entry value",
|
|
+ __func__);
|
|
+ goto error;
|
|
+ } else if (cluster == FAT_ENT_FREE) {
|
|
+ pr_err("FAT ERR: %s: deleting FAT entry beyond EOF",
|
|
+ __func__);
|
|
+ err = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+ nr_cluster++;
|
|
+ fatent_set_entry(&fatent, cluster);
|
|
+ err = fat_ent_read_block(sb, &fatent);
|
|
+ if (err)
|
|
+ goto error;
|
|
+ }
|
|
+error:
|
|
+ fatent_brelse(&fatent);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (nr_cluster)
|
|
+ return nr_cluster + 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
|
|
int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
|
|
{
|
|
@@ -468,6 +516,8 @@ int fat_alloc_clusters(struct inode *ino
|
|
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
|
int i, count, err, nr_bhs, idx_clus;
|
|
|
|
+ if (nr_cluster > (MAX_BUF_PER_PAGE / 2))
|
|
+ printk("nr_cluster %d,max nr_cluster %lu\n", nr_cluster, (MAX_BUF_PER_PAGE / 2));
|
|
BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */
|
|
|
|
lock_fat(sbi);
|
|
@@ -547,6 +597,57 @@ out:
|
|
return err;
|
|
}
|
|
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM_DISCARD
|
|
+int fat_discard_clusters(struct inode *inode, int cluster)
|
|
+{
|
|
+ struct super_block *sb = inode->i_sb;
|
|
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
+ struct fat_entry fatent;
|
|
+ int err;
|
|
+ int first_cl = cluster;
|
|
+
|
|
+ fatent_init(&fatent);
|
|
+ lock_fat(sbi);
|
|
+ do {
|
|
+ cluster = fat_ent_read(inode, &fatent, cluster);
|
|
+ if (cluster < 0) {
|
|
+ err = cluster;
|
|
+ goto error;
|
|
+ } else if (cluster == FAT_ENT_FREE) {
|
|
+ fat_fs_error(sb, "%s: deleting FAT entry beyond EOF",
|
|
+ __func__);
|
|
+ err = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (sbi->options.discard) {
|
|
+ /*
|
|
+ * Issue discard for the sectors we no longer
|
|
+ * care about, batching contiguous clusters
|
|
+ * into one request
|
|
+ */
|
|
+ if (cluster != fatent.entry + 1) {
|
|
+ int nr_clus = fatent.entry - first_cl + 1;
|
|
+
|
|
+ sb_issue_discard(sb,
|
|
+ fat_clus_to_blknr(sbi, first_cl),
|
|
+ nr_clus * sbi->sec_per_clus,
|
|
+ GFP_NOFS, 0);
|
|
+
|
|
+ first_cl = cluster;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ } while (cluster != FAT_ENT_EOF);
|
|
+error:
|
|
+ fatent_brelse(&fatent);
|
|
+ unlock_fat(sbi);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(fat_discard_clusters);
|
|
+#endif
|
|
+
|
|
int fat_free_clusters(struct inode *inode, int cluster)
|
|
{
|
|
struct super_block *sb = inode->i_sb;
|
|
@@ -690,3 +791,104 @@ out:
|
|
unlock_fat(sbi);
|
|
return err;
|
|
}
|
|
+
|
|
+static int fat_trim_clusters(struct super_block *sb, u32 clus, u32 nr_clus)
|
|
+{
|
|
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
+ return sb_issue_discard(sb, fat_clus_to_blknr(sbi, clus),
|
|
+ nr_clus * sbi->sec_per_clus, GFP_NOFS, 0);
|
|
+}
|
|
+
|
|
+int fat_trim_fs(struct inode *inode, struct fstrim_range *range)
|
|
+{
|
|
+ struct super_block *sb = inode->i_sb;
|
|
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
+ const struct fatent_operations *ops = sbi->fatent_ops;
|
|
+ struct fat_entry fatent;
|
|
+ u64 ent_start, ent_end, minlen, trimmed = 0;
|
|
+ u32 free = 0;
|
|
+ unsigned long reada_blocks, reada_mask, cur_block = 0;
|
|
+ int err = 0;
|
|
+
|
|
+ /*
|
|
+ * FAT data is organized as clusters, trim at the granulary of cluster.
|
|
+ *
|
|
+ * fstrim_range is in byte, convert vaules to cluster index.
|
|
+ * Treat sectors before data region as all used, not to trim them.
|
|
+ */
|
|
+ ent_start = max_t(u64, range->start>>sbi->cluster_bits, FAT_START_ENT);
|
|
+ ent_end = ent_start + (range->len >> sbi->cluster_bits) - 1;
|
|
+ minlen = range->minlen >> sbi->cluster_bits;
|
|
+
|
|
+ if (ent_start >= sbi->max_cluster || range->len < sbi->cluster_size)
|
|
+ return -EINVAL;
|
|
+ if (ent_end >= sbi->max_cluster)
|
|
+ ent_end = sbi->max_cluster - 1;
|
|
+
|
|
+ reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
|
|
+ reada_mask = reada_blocks - 1;
|
|
+
|
|
+ fatent_init(&fatent);
|
|
+ lock_fat(sbi);
|
|
+ fatent_set_entry(&fatent, ent_start);
|
|
+ while (fatent.entry <= ent_end) {
|
|
+ /* readahead of fat blocks */
|
|
+ if ((cur_block & reada_mask) == 0) {
|
|
+ unsigned long rest = sbi->fat_length - cur_block;
|
|
+ fat_ent_reada(sb, &fatent, min(reada_blocks, rest));
|
|
+ }
|
|
+ cur_block++;
|
|
+
|
|
+ err = fat_ent_read_block(sb, &fatent);
|
|
+ if (err)
|
|
+ goto error;
|
|
+ do {
|
|
+ if (ops->ent_get(&fatent) == FAT_ENT_FREE) {
|
|
+ free++;
|
|
+ } else if (free) {
|
|
+ if (free >= minlen) {
|
|
+ u32 clus = fatent.entry - free;
|
|
+
|
|
+ err = fat_trim_clusters(sb, clus, free);
|
|
+ if (err && err != -EOPNOTSUPP)
|
|
+ goto error;
|
|
+ if (!err)
|
|
+ trimmed += free;
|
|
+ err = 0;
|
|
+ }
|
|
+ free = 0;
|
|
+ }
|
|
+ } while (fat_ent_next(sbi, &fatent) && fatent.entry <= ent_end);
|
|
+
|
|
+ if (fatal_signal_pending(current)) {
|
|
+ err = -ERESTARTSYS;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (need_resched()) {
|
|
+ fatent_brelse(&fatent);
|
|
+ unlock_fat(sbi);
|
|
+ cond_resched();
|
|
+ lock_fat(sbi);
|
|
+ }
|
|
+ }
|
|
+ /* handle scenario when tail entries are all free */
|
|
+ if (free && free >= minlen) {
|
|
+ u32 clus = fatent.entry - free;
|
|
+
|
|
+ err = fat_trim_clusters(sb, clus, free);
|
|
+ if (err && err != -EOPNOTSUPP)
|
|
+ goto error;
|
|
+ if (!err)
|
|
+ trimmed += free;
|
|
+ err = 0;
|
|
+ }
|
|
+
|
|
+error:
|
|
+ fatent_brelse(&fatent);
|
|
+ unlock_fat(sbi);
|
|
+
|
|
+ range->len = trimmed << sbi->cluster_bits;
|
|
+
|
|
+ return err;
|
|
+}
|