mirror of https://github.com/OpenIPC/firmware.git
197 lines
5.2 KiB
Diff
197 lines
5.2 KiB
Diff
diff -drupN a/fs/fat/file.c b/fs/fat/file.c
|
|
--- a/fs/fat/file.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/fs/fat/file.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -17,6 +17,10 @@
|
|
#include <linux/falloc.h>
|
|
#include "fat.h"
|
|
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+static DEFINE_MUTEX (i_mutex);
|
|
+#endif
|
|
+
|
|
static long fat_fallocate(struct file *file, int mode,
|
|
loff_t offset, loff_t len);
|
|
|
|
@@ -121,6 +125,37 @@ static int fat_ioctl_get_volume_id(struc
|
|
return put_user(sbi->vol_id, user_attr);
|
|
}
|
|
|
|
+static int fat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
|
+{
|
|
+ struct super_block *sb = inode->i_sb;
|
|
+ struct fstrim_range __user *user_range;
|
|
+ struct fstrim_range range;
|
|
+ struct request_queue *q = bdev_get_queue(sb->s_bdev);
|
|
+ int err;
|
|
+
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
+ if (!blk_queue_discard(q))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ user_range = (struct fstrim_range __user *)arg;
|
|
+ if (copy_from_user(&range, user_range, sizeof(range)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ range.minlen = max_t(unsigned int, range.minlen,
|
|
+ q->limits.discard_granularity);
|
|
+
|
|
+ err = fat_trim_fs(inode, &range);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ if (copy_to_user(user_range, &range, sizeof(range)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct inode *inode = file_inode(filp);
|
|
@@ -133,6 +168,8 @@ long fat_generic_ioctl(struct file *filp
|
|
return fat_ioctl_set_attributes(filp, user_attr);
|
|
case FAT_IOCTL_GET_VOLUME_ID:
|
|
return fat_ioctl_get_volume_id(inode, user_attr);
|
|
+ case FITRIM:
|
|
+ return fat_ioctl_fitrim(inode, arg);
|
|
default:
|
|
return -ENOTTY; /* Inappropriate ioctl for device */
|
|
}
|
|
@@ -168,6 +205,17 @@ int fat_file_fsync(struct file *filp, lo
|
|
return res ? res : err;
|
|
}
|
|
|
|
+#ifdef CONFIG_OPTIMIZE_METADATA_REFRESH
|
|
+int fat_file_flush(struct file *file, fl_owner_t id)
|
|
+{
|
|
+ struct address_space *mapping = file->f_mapping;
|
|
+ struct inode *inode = mapping->host;
|
|
+
|
|
+ inode->i_sb->s_op->write_inode(inode, NULL);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
|
|
const struct file_operations fat_file_operations = {
|
|
.llseek = generic_file_llseek,
|
|
@@ -182,6 +230,9 @@ const struct file_operations fat_file_op
|
|
.fsync = fat_file_fsync,
|
|
.splice_read = generic_file_splice_read,
|
|
.fallocate = fat_fallocate,
|
|
+#ifdef CONFIG_OPTIMIZE_METADATA_REFRESH
|
|
+ .flush = fat_file_flush,
|
|
+#endif
|
|
};
|
|
|
|
static int fat_cont_expand(struct inode *inode, loff_t size)
|
|
@@ -246,7 +297,17 @@ static long fat_fallocate(struct file *f
|
|
if (!S_ISREG(inode->i_mode))
|
|
return -EOPNOTSUPP;
|
|
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+ if (check_prealloc(inode)) {
|
|
+ fat_msg(sb, KERN_ERR, "Repeatedly called fat_fallocate");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+#endif
|
|
+
|
|
inode_lock(inode);
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+ mutex_lock(&i_mutex);
|
|
+#endif
|
|
if (mode & FALLOC_FL_KEEP_SIZE) {
|
|
ondisksize = inode->i_blocks << 9;
|
|
if ((offset + len) <= ondisksize)
|
|
@@ -271,7 +332,13 @@ static long fat_fallocate(struct file *f
|
|
err = fat_cont_expand(inode, (offset + len));
|
|
}
|
|
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+ mark_prealloc(inode);
|
|
+#endif
|
|
error:
|
|
+#ifdef CONFIG_PRELLOCATE_FLAG
|
|
+ mutex_unlock(&i_mutex);
|
|
+#endif
|
|
inode_unlock(inode);
|
|
return err;
|
|
}
|
|
@@ -290,14 +357,19 @@ static int fat_free(struct inode *inode,
|
|
wait = IS_DIRSYNC(inode);
|
|
i_start = free_start = MSDOS_I(inode)->i_start;
|
|
i_logstart = MSDOS_I(inode)->i_logstart;
|
|
-
|
|
/* First, we write the new file size. */
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM
|
|
+ if (!skip && (inode->i_nlink == 0 || !check_prealloc(inode))) {
|
|
+#else
|
|
if (!skip) {
|
|
+#endif
|
|
MSDOS_I(inode)->i_start = 0;
|
|
MSDOS_I(inode)->i_logstart = 0;
|
|
}
|
|
+
|
|
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
|
|
inode->i_ctime = inode->i_mtime = current_time(inode);
|
|
+
|
|
if (wait) {
|
|
err = fat_sync_inode(inode);
|
|
if (err) {
|
|
@@ -309,7 +381,11 @@ static int fat_free(struct inode *inode,
|
|
mark_inode_dirty(inode);
|
|
|
|
/* Write a new EOF, and get the remaining cluster chain for freeing. */
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM
|
|
+ if (skip && !check_prealloc(inode)) {
|
|
+#else
|
|
if (skip) {
|
|
+#endif
|
|
struct fat_entry fatent;
|
|
int ret, fclus, dclus;
|
|
|
|
@@ -340,8 +416,17 @@ static int fat_free(struct inode *inode,
|
|
|
|
free_start = ret;
|
|
}
|
|
- inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
|
|
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM
|
|
+ if (check_prealloc(inode) && inode->i_nlink) {
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM_DISCARD
|
|
+ fat_discard_clusters(inode, free_start);
|
|
+#endif
|
|
+ return 0;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
|
|
/* Freeing the remained cluster chain */
|
|
return fat_free_clusters(inode, free_start);
|
|
}
|
|
@@ -468,10 +553,22 @@ int fat_setattr(struct dentry *dentry, s
|
|
inode_dio_wait(inode);
|
|
|
|
if (attr->ia_size > inode->i_size) {
|
|
+#ifdef CONFIG_TRUNCATE_NOMEM_RECLAIM
|
|
+ if (!check_prealloc(inode)) {
|
|
+ error = fat_cont_expand(inode, attr->ia_size);
|
|
+ if (error || attr->ia_valid == ATTR_SIZE)
|
|
+ goto out;
|
|
+ attr->ia_valid &= ~ATTR_SIZE;
|
|
+ } else {
|
|
+ pr_err("FAT ERR: (%s) incorrectly call ftruncate", __func__);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+#else
|
|
error = fat_cont_expand(inode, attr->ia_size);
|
|
if (error || attr->ia_valid == ATTR_SIZE)
|
|
goto out;
|
|
attr->ia_valid &= ~ATTR_SIZE;
|
|
+#endif
|
|
}
|
|
}
|
|
|