Merge branch 'for-kernel-version-from-4.1.0' of https://github.com/namjaejeon/linux-exfat-oot into android13-5.4-lahaina
* 'for-kernel-version-from-4.1.0' of https://github.com/namjaejeon/linux-exfat-oot: exfat: github action: run buiuld and tests on for-kernel-version-from-4.1.0 branch exfat: fix ALIGN_DOWN undefined error exfat: using ffs instead of internal logic exfat: using hweight instead of internal logic exfat: fix ctime is not updated exfat: fix setting uninitialized time to ctime/atime exfat: convert to new timestamp accessors exfat: convert to ctime accessor functions exfat: fs: pass the request_mask to generic_fillattr exfat: convert to simple_rename_timestamp exfat: ensure that ctime is updated whenever the mtime is exfat: fs: add CONFIG_BUFFER_HEAD exfat: use fat ioctls definitions from include/uapi/linux/msdos_fs.h exfat: github action: remove liunx-4.1 source to get more disk space exfat: support create zero-size directory exfat: support handle zero-size directory exfat: add ioctls for accessing attributes exfat: vfs: get rid of old '->iterate' directory operation Change-Id: I7e8add708697faf95952cacdb24bf5f504190fe4
This commit is contained in:
commit
d561bf243b
9
fs/exfat/.github/workflows/c-cpp.yml
vendored
9
fs/exfat/.github/workflows/c-cpp.yml
vendored
@ -2,9 +2,9 @@ name: linux-exfat-oot CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "master" ]
|
branches: [ "for-kernel-version-from-4.1.0" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "master" ]
|
branches: [ "for-kernel-version-from-4.1.0" ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -20,6 +20,7 @@ jobs:
|
|||||||
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.1.36.tar.gz
|
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.1.36.tar.gz
|
||||||
tar xf linux-4.1.36.tar.gz
|
tar xf linux-4.1.36.tar.gz
|
||||||
mv linux-4.1.36 linux-stable
|
mv linux-4.1.36 linux-stable
|
||||||
|
rm -rf linux-4.1.36.tar.gz
|
||||||
- name: Prerequisite for xfstests testing
|
- name: Prerequisite for xfstests testing
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install linux-headers-$(uname -r)
|
sudo apt-get install linux-headers-$(uname -r)
|
||||||
@ -47,7 +48,9 @@ jobs:
|
|||||||
make -j$((`nproc`+1)) fs/exfat/exfat.ko
|
make -j$((`nproc`+1)) fs/exfat/exfat.ko
|
||||||
- name: Run xfstests testsuite
|
- name: Run xfstests testsuite
|
||||||
run: |
|
run: |
|
||||||
cd ../linux-exfat-oot
|
cd ..
|
||||||
|
rm -rf linux-stable
|
||||||
|
cd linux-exfat-oot
|
||||||
make > /dev/null
|
make > /dev/null
|
||||||
sudo make install > /dev/null
|
sudo make install > /dev/null
|
||||||
sudo insmod exfat.ko
|
sudo insmod exfat.ko
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
config EXFAT_FS
|
config EXFAT_FS
|
||||||
tristate "exFAT filesystem support"
|
tristate "exFAT filesystem support"
|
||||||
|
select BUFFER_HEAD
|
||||||
select NLS
|
select NLS
|
||||||
select LEGACY_DIRECT_IO
|
select LEGACY_DIRECT_IO
|
||||||
help
|
help
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
@ -17,37 +18,21 @@
|
|||||||
#include "exfat_raw.h"
|
#include "exfat_raw.h"
|
||||||
#include "exfat_fs.h"
|
#include "exfat_fs.h"
|
||||||
|
|
||||||
static const unsigned char free_bit[] = {
|
#if BITS_PER_LONG == 32
|
||||||
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/
|
#define __le_long __le32
|
||||||
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/
|
#define lel_to_cpu(A) le32_to_cpu(A)
|
||||||
0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/
|
#define cpu_to_lel(A) cpu_to_le32(A)
|
||||||
0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/
|
#elif BITS_PER_LONG == 64
|
||||||
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/
|
#define __le_long __le64
|
||||||
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
|
#define lel_to_cpu(A) le64_to_cpu(A)
|
||||||
0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
|
#define cpu_to_lel(A) cpu_to_le64(A)
|
||||||
0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
|
#else
|
||||||
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
|
#error "BITS_PER_LONG not 32 or 64"
|
||||||
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
|
#endif
|
||||||
0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
|
|
||||||
0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
|
|
||||||
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char used_bit[] = {
|
#ifndef ALIGN_DOWN
|
||||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/
|
#define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a))
|
||||||
2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/
|
#endif
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/
|
|
||||||
4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/
|
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/
|
|
||||||
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
|
|
||||||
4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
|
|
||||||
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
|
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
|
|
||||||
4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
|
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
|
|
||||||
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
|
|
||||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocation Bitmap Management Functions
|
* Allocation Bitmap Management Functions
|
||||||
@ -211,32 +196,35 @@ unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu)
|
|||||||
{
|
{
|
||||||
unsigned int i, map_i, map_b, ent_idx;
|
unsigned int i, map_i, map_b, ent_idx;
|
||||||
unsigned int clu_base, clu_free;
|
unsigned int clu_base, clu_free;
|
||||||
unsigned char k, clu_mask;
|
unsigned long clu_bits, clu_mask;
|
||||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||||
|
__le_long bitval;
|
||||||
|
|
||||||
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
|
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
|
||||||
ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
|
ent_idx = ALIGN_DOWN(CLUSTER_TO_BITMAP_ENT(clu), BITS_PER_LONG);
|
||||||
clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK));
|
clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx);
|
||||||
clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
|
clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
|
||||||
|
|
||||||
map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
|
map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
|
||||||
map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
|
map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
|
||||||
|
|
||||||
for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
|
for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
|
||||||
i += BITS_PER_BYTE) {
|
i += BITS_PER_LONG) {
|
||||||
k = *(sbi->vol_amap[map_i]->b_data + map_b);
|
bitval = *(__le_long *)(sbi->vol_amap[map_i]->b_data + map_b);
|
||||||
if (clu_mask > 0) {
|
if (clu_mask > 0) {
|
||||||
k |= clu_mask;
|
bitval |= cpu_to_lel(clu_mask);
|
||||||
clu_mask = 0;
|
clu_mask = 0;
|
||||||
}
|
}
|
||||||
if (k < 0xFF) {
|
if (lel_to_cpu(bitval) != ULONG_MAX) {
|
||||||
clu_free = clu_base + free_bit[k];
|
clu_bits = lel_to_cpu(bitval);
|
||||||
|
clu_free = clu_base + ffz(clu_bits);
|
||||||
if (clu_free < sbi->num_clusters)
|
if (clu_free < sbi->num_clusters)
|
||||||
return clu_free;
|
return clu_free;
|
||||||
}
|
}
|
||||||
clu_base += BITS_PER_BYTE;
|
clu_base += BITS_PER_LONG;
|
||||||
|
map_b += sizeof(long);
|
||||||
|
|
||||||
if (++map_b >= sb->s_blocksize ||
|
if (map_b >= sb->s_blocksize ||
|
||||||
clu_base >= sbi->num_clusters) {
|
clu_base >= sbi->num_clusters) {
|
||||||
if (++map_i >= sbi->map_sectors) {
|
if (++map_i >= sbi->map_sectors) {
|
||||||
clu_base = EXFAT_FIRST_CLUSTER;
|
clu_base = EXFAT_FIRST_CLUSTER;
|
||||||
@ -255,25 +243,24 @@ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
|
|||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
unsigned int i, map_i = 0, map_b = 0;
|
unsigned int i, map_i = 0, map_b = 0;
|
||||||
unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
|
unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
|
||||||
unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK;
|
unsigned int last_mask = total_clus & (BITS_PER_LONG - 1);
|
||||||
unsigned char clu_bits;
|
unsigned long *bitmap, clu_bits;
|
||||||
const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011,
|
|
||||||
0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111};
|
|
||||||
|
|
||||||
total_clus &= ~last_mask;
|
total_clus &= ~last_mask;
|
||||||
for (i = 0; i < total_clus; i += BITS_PER_BYTE) {
|
for (i = 0; i < total_clus; i += BITS_PER_LONG) {
|
||||||
clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
|
bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b);
|
||||||
count += used_bit[clu_bits];
|
count += hweight_long(*bitmap);
|
||||||
if (++map_b >= (unsigned int)sb->s_blocksize) {
|
map_b += sizeof(long);
|
||||||
|
if (map_b >= (unsigned int)sb->s_blocksize) {
|
||||||
map_i++;
|
map_i++;
|
||||||
map_b = 0;
|
map_b = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_mask) {
|
if (last_mask) {
|
||||||
clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
|
bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b);
|
||||||
clu_bits &= last_bit_mask[last_mask];
|
clu_bits = lel_to_cpu(*(__le_long *)bitmap);
|
||||||
count += used_bit[clu_bits];
|
count += hweight_long(clu_bits & BITMAP_LAST_WORD_MASK(last_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret_count = count;
|
*ret_count = count;
|
||||||
|
@ -288,7 +288,7 @@ get_new:
|
|||||||
|
|
||||||
mutex_unlock(&EXFAT_SB(sb)->s_lock);
|
mutex_unlock(&EXFAT_SB(sb)->s_lock);
|
||||||
if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum,
|
if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum,
|
||||||
(de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG))
|
(de.attr & EXFAT_ATTR_SUBDIR) ? DT_DIR : DT_REG))
|
||||||
goto out;
|
goto out;
|
||||||
ctx->pos = cpos;
|
ctx->pos = cpos;
|
||||||
goto get_new;
|
goto get_new;
|
||||||
@ -307,10 +307,17 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
|
||||||
|
WRAP_DIR_ITER(exfat_iterate) // FIXME!
|
||||||
|
#endif
|
||||||
const struct file_operations exfat_dir_operations = {
|
const struct file_operations exfat_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
|
||||||
|
.iterate_shared = shared_exfat_iterate,
|
||||||
|
#else
|
||||||
.iterate = exfat_iterate,
|
.iterate = exfat_iterate,
|
||||||
|
#endif
|
||||||
.unlocked_ioctl = exfat_ioctl,
|
.unlocked_ioctl = exfat_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = exfat_compat_ioctl,
|
.compat_ioctl = exfat_compat_ioctl,
|
||||||
@ -359,7 +366,7 @@ unsigned int exfat_get_entry_type(struct exfat_dentry *ep)
|
|||||||
if (ep->type == EXFAT_VOLUME)
|
if (ep->type == EXFAT_VOLUME)
|
||||||
return TYPE_VOLUME;
|
return TYPE_VOLUME;
|
||||||
if (ep->type == EXFAT_FILE) {
|
if (ep->type == EXFAT_FILE) {
|
||||||
if (le16_to_cpu(ep->dentry.file.attr) & ATTR_SUBDIR)
|
if (le16_to_cpu(ep->dentry.file.attr) & EXFAT_ATTR_SUBDIR)
|
||||||
return TYPE_DIR;
|
return TYPE_DIR;
|
||||||
return TYPE_FILE;
|
return TYPE_FILE;
|
||||||
}
|
}
|
||||||
@ -410,19 +417,21 @@ static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type)
|
|||||||
ep->type = EXFAT_VOLUME;
|
ep->type = EXFAT_VOLUME;
|
||||||
} else if (type == TYPE_DIR) {
|
} else if (type == TYPE_DIR) {
|
||||||
ep->type = EXFAT_FILE;
|
ep->type = EXFAT_FILE;
|
||||||
ep->dentry.file.attr = cpu_to_le16(ATTR_SUBDIR);
|
ep->dentry.file.attr = cpu_to_le16(EXFAT_ATTR_SUBDIR);
|
||||||
} else if (type == TYPE_FILE) {
|
} else if (type == TYPE_FILE) {
|
||||||
ep->type = EXFAT_FILE;
|
ep->type = EXFAT_FILE;
|
||||||
ep->dentry.file.attr = cpu_to_le16(ATTR_ARCHIVE);
|
ep->dentry.file.attr = cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exfat_init_stream_entry(struct exfat_dentry *ep,
|
static void exfat_init_stream_entry(struct exfat_dentry *ep,
|
||||||
unsigned char flags, unsigned int start_clu,
|
unsigned int start_clu, unsigned long long size)
|
||||||
unsigned long long size)
|
|
||||||
{
|
{
|
||||||
exfat_set_entry_type(ep, TYPE_STREAM);
|
exfat_set_entry_type(ep, TYPE_STREAM);
|
||||||
ep->dentry.stream.flags = flags;
|
if (size == 0)
|
||||||
|
ep->dentry.stream.flags = ALLOC_FAT_CHAIN;
|
||||||
|
else
|
||||||
|
ep->dentry.stream.flags = ALLOC_NO_FAT_CHAIN;
|
||||||
ep->dentry.stream.start_clu = cpu_to_le32(start_clu);
|
ep->dentry.stream.start_clu = cpu_to_le32(start_clu);
|
||||||
ep->dentry.stream.valid_size = cpu_to_le64(size);
|
ep->dentry.stream.valid_size = cpu_to_le64(size);
|
||||||
ep->dentry.stream.size = cpu_to_le64(size);
|
ep->dentry.stream.size = cpu_to_le64(size);
|
||||||
@ -498,9 +507,7 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
|
|||||||
if (!ep)
|
if (!ep)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
exfat_init_stream_entry(ep,
|
exfat_init_stream_entry(ep, start_clu, size);
|
||||||
(type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN,
|
|
||||||
start_clu, size);
|
|
||||||
exfat_update_bh(bh, IS_DIRSYNC(inode));
|
exfat_update_bh(bh, IS_DIRSYNC(inode));
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
|
||||||
|
@ -148,8 +148,7 @@ enum {
|
|||||||
#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb))
|
#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb))
|
||||||
#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \
|
#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \
|
||||||
((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1))
|
((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1))
|
||||||
#define BITS_PER_BYTE_MASK 0x7
|
#define IGNORED_BITS_REMAINED(clu, clu_base) ((1UL << ((clu) - (clu_base))) - 1)
|
||||||
#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1)
|
|
||||||
|
|
||||||
#define ES_ENTRY_NUM(name_len) (ES_IDX_LAST_FILENAME(name_len) + 1)
|
#define ES_ENTRY_NUM(name_len) (ES_IDX_LAST_FILENAME(name_len) + 1)
|
||||||
/* 19 entries = 1 file entry + 1 stream entry + 17 filename entries */
|
/* 19 entries = 1 file entry + 1 stream entry + 17 filename entries */
|
||||||
@ -253,6 +252,8 @@ struct exfat_mount_options {
|
|||||||
discard:1, /* Issue discard requests on deletions */
|
discard:1, /* Issue discard requests on deletions */
|
||||||
keep_last_dots:1; /* Keep trailing periods in paths */
|
keep_last_dots:1; /* Keep trailing periods in paths */
|
||||||
int time_offset; /* Offset of timestamps from UTC (in minutes) */
|
int time_offset; /* Offset of timestamps from UTC (in minutes) */
|
||||||
|
/* Support creating zero-size directory, default: false */
|
||||||
|
bool zero_size_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -382,10 +383,10 @@ static inline int exfat_mode_can_hold_ro(struct inode *inode)
|
|||||||
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
|
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
|
||||||
unsigned short attr, mode_t mode)
|
unsigned short attr, mode_t mode)
|
||||||
{
|
{
|
||||||
if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
|
if ((attr & EXFAT_ATTR_READONLY) && !(attr & EXFAT_ATTR_SUBDIR))
|
||||||
mode &= ~0222;
|
mode &= ~0222;
|
||||||
|
|
||||||
if (attr & ATTR_SUBDIR)
|
if (attr & EXFAT_ATTR_SUBDIR)
|
||||||
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
|
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
|
||||||
|
|
||||||
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
|
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
|
||||||
@ -397,18 +398,18 @@ static inline unsigned short exfat_make_attr(struct inode *inode)
|
|||||||
unsigned short attr = EXFAT_I(inode)->attr;
|
unsigned short attr = EXFAT_I(inode)->attr;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
attr |= ATTR_SUBDIR;
|
attr |= EXFAT_ATTR_SUBDIR;
|
||||||
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
|
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
|
||||||
attr |= ATTR_READONLY;
|
attr |= EXFAT_ATTR_READONLY;
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void exfat_save_attr(struct inode *inode, unsigned short attr)
|
static inline void exfat_save_attr(struct inode *inode, unsigned short attr)
|
||||||
{
|
{
|
||||||
if (exfat_mode_can_hold_ro(inode))
|
if (exfat_mode_can_hold_ro(inode))
|
||||||
EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY);
|
EXFAT_I(inode)->attr = attr & (EXFAT_ATTR_RWMASK | EXFAT_ATTR_READONLY);
|
||||||
else
|
else
|
||||||
EXFAT_I(inode)->attr = attr & ATTR_RWMASK;
|
EXFAT_I(inode)->attr = attr & EXFAT_ATTR_RWMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
|
static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
|
||||||
@ -596,6 +597,9 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
|||||||
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
|
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
|
||||||
u8 tz, __le16 time, __le16 date, u8 time_cs);
|
u8 tz, __le16 time, __le16 date, u8 time_cs);
|
||||||
void exfat_truncate_atime(struct timespec64 *ts);
|
void exfat_truncate_atime(struct timespec64 *ts);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
void exfat_truncate_inode_atime(struct inode *inode);
|
||||||
|
#endif
|
||||||
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
|
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
|
||||||
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
|
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
|
||||||
#else
|
#else
|
||||||
|
@ -64,15 +64,16 @@
|
|||||||
#define CS_DEFAULT 2
|
#define CS_DEFAULT 2
|
||||||
|
|
||||||
/* file attributes */
|
/* file attributes */
|
||||||
#define ATTR_READONLY 0x0001
|
#define EXFAT_ATTR_READONLY 0x0001
|
||||||
#define ATTR_HIDDEN 0x0002
|
#define EXFAT_ATTR_HIDDEN 0x0002
|
||||||
#define ATTR_SYSTEM 0x0004
|
#define EXFAT_ATTR_SYSTEM 0x0004
|
||||||
#define ATTR_VOLUME 0x0008
|
#define EXFAT_ATTR_VOLUME 0x0008
|
||||||
#define ATTR_SUBDIR 0x0010
|
#define EXFAT_ATTR_SUBDIR 0x0010
|
||||||
#define ATTR_ARCHIVE 0x0020
|
#define EXFAT_ATTR_ARCHIVE 0x0020
|
||||||
|
|
||||||
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
|
#define EXFAT_ATTR_RWMASK (EXFAT_ATTR_HIDDEN | EXFAT_ATTR_SYSTEM | \
|
||||||
ATTR_SUBDIR | ATTR_ARCHIVE)
|
EXFAT_ATTR_VOLUME | EXFAT_ATTR_SUBDIR | \
|
||||||
|
EXFAT_ATTR_ARCHIVE)
|
||||||
|
|
||||||
#define BOOTSEC_JUMP_BOOT_LEN 3
|
#define BOOTSEC_JUMP_BOOT_LEN 3
|
||||||
#define BOOTSEC_FS_NAME_LEN 8
|
#define BOOTSEC_FS_NAME_LEN 8
|
||||||
|
161
fs/exfat/file.c
161
fs/exfat/file.c
@ -9,8 +9,12 @@
|
|||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <linux/mount.h>
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/fsnotify.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
#include <linux/msdos_fs.h>
|
||||||
|
|
||||||
#include "exfat_raw.h"
|
#include "exfat_raw.h"
|
||||||
#include "exfat_fs.h"
|
#include "exfat_fs.h"
|
||||||
@ -26,7 +30,15 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode_set_ctime_current(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
inode->i_ctime = inode->i_mtime = current_time(inode);
|
inode->i_ctime = inode->i_mtime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
|
inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
@ -151,7 +163,7 @@ int __exfat_truncate(struct inode *inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ei->type == TYPE_FILE)
|
if (ei->type == TYPE_FILE)
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* update the directory entry
|
* update the directory entry
|
||||||
@ -265,7 +277,11 @@ int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
|||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
|
||||||
|
#else
|
||||||
generic_fillattr(&nop_mnt_idmap, inode, stat);
|
generic_fillattr(&nop_mnt_idmap, inode, stat);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
generic_fillattr(&init_user_ns, inode, stat);
|
generic_fillattr(&init_user_ns, inode, stat);
|
||||||
#endif
|
#endif
|
||||||
@ -355,11 +371,23 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
|
|
||||||
if (attr->ia_valid & ATTR_SIZE)
|
if (attr->ia_valid & ATTR_SIZE)
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode_set_ctime_current(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
setattr_copy(&nop_mnt_idmap, inode, attr);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
|
#else
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
||||||
setattr_copy(&nop_mnt_idmap, inode, attr);
|
setattr_copy(&nop_mnt_idmap, inode, attr);
|
||||||
@ -370,6 +398,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
setattr_copy(inode, attr);
|
setattr_copy(inode, attr);
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (attr->ia_valid & ATTR_SIZE) {
|
if (attr->ia_valid & ATTR_SIZE) {
|
||||||
error = exfat_block_truncate_page(inode, attr->ia_size);
|
error = exfat_block_truncate_page(inode, attr->ia_size);
|
||||||
@ -390,6 +419,131 @@ out:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* modified ioctls from fat/file.c by Welmer Almesberger
|
||||||
|
*/
|
||||||
|
static int exfat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
|
||||||
|
{
|
||||||
|
u32 attr;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||||
|
inode_lock_shared(inode);
|
||||||
|
#else
|
||||||
|
mutex_lock(&inode->i_mutex);
|
||||||
|
#endif
|
||||||
|
attr = exfat_make_attr(inode);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||||
|
inode_unlock_shared(inode);
|
||||||
|
#else
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return put_user(attr, user_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exfat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
|
||||||
|
{
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
|
||||||
|
int is_dir = S_ISDIR(inode->i_mode);
|
||||||
|
u32 attr, oldattr;
|
||||||
|
struct iattr ia;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = get_user(attr, user_attr);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = mnt_want_write_file(file);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||||
|
inode_lock(inode);
|
||||||
|
#else
|
||||||
|
mutex_lock(&inode->i_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
oldattr = exfat_make_attr(inode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mask attributes so we don't set reserved fields.
|
||||||
|
*/
|
||||||
|
attr &= (EXFAT_ATTR_READONLY | EXFAT_ATTR_HIDDEN | EXFAT_ATTR_SYSTEM |
|
||||||
|
EXFAT_ATTR_ARCHIVE);
|
||||||
|
attr |= (is_dir ? EXFAT_ATTR_SUBDIR : 0);
|
||||||
|
|
||||||
|
/* Equivalent to a chmod() */
|
||||||
|
ia.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
||||||
|
ia.ia_ctime = current_time(inode);
|
||||||
|
#else
|
||||||
|
ia.ia_ctime = current_fs_time(inode->i_sb);
|
||||||
|
#endif
|
||||||
|
if (is_dir)
|
||||||
|
ia.ia_mode = exfat_make_mode(sbi, attr, 0777);
|
||||||
|
else
|
||||||
|
ia.ia_mode = exfat_make_mode(sbi, attr, 0666 | (inode->i_mode & 0111));
|
||||||
|
|
||||||
|
/* The root directory has no attributes */
|
||||||
|
if (inode->i_ino == EXFAT_ROOT_INO && attr != EXFAT_ATTR_SUBDIR) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_unlock_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((attr | oldattr) & EXFAT_ATTR_SYSTEM) &&
|
||||||
|
!capable(CAP_LINUX_IMMUTABLE)) {
|
||||||
|
err = -EPERM;
|
||||||
|
goto out_unlock_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The security check is questionable... We single
|
||||||
|
* out the RO attribute for checking by the security
|
||||||
|
* module, just because it maps to a file mode.
|
||||||
|
*/
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
||||||
|
err = security_inode_setattr(file_mnt_idmap(file),
|
||||||
|
file->f_path.dentry, &ia);
|
||||||
|
#else
|
||||||
|
err = security_inode_setattr(file_mnt_user_ns(file),
|
||||||
|
file->f_path.dentry, &ia);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
err = security_inode_setattr(file->f_path.dentry, &ia);
|
||||||
|
#endif
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_inode;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
||||||
|
/* This MUST be done before doing anything irreversible... */
|
||||||
|
err = exfat_setattr(file_mnt_idmap(file), file->f_path.dentry, &ia);
|
||||||
|
#else
|
||||||
|
err = exfat_setattr(file_mnt_user_ns(file), file->f_path.dentry, &ia);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
err = exfat_setattr(file->f_path.dentry, &ia);
|
||||||
|
#endif
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_inode;
|
||||||
|
|
||||||
|
fsnotify_change(file->f_path.dentry, ia.ia_valid);
|
||||||
|
|
||||||
|
exfat_save_attr(inode, attr);
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
out_unlock_inode:
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||||
|
inode_unlock(inode);
|
||||||
|
#else
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
#endif
|
||||||
|
mnt_drop_write_file(file);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
||||||
{
|
{
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
|
||||||
@ -432,8 +586,13 @@ static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
|||||||
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(filp);
|
||||||
|
u32 __user *user_attr = (u32 __user *)arg;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case FAT_IOCTL_GET_ATTRIBUTES:
|
||||||
|
return exfat_ioctl_get_attributes(inode, user_attr);
|
||||||
|
case FAT_IOCTL_SET_ATTRIBUTES:
|
||||||
|
return exfat_ioctl_set_attributes(filp, user_attr);
|
||||||
case FITRIM:
|
case FITRIM:
|
||||||
return exfat_ioctl_fitrim(inode, arg);
|
return exfat_ioctl_fitrim(inode, arg);
|
||||||
default:
|
default:
|
||||||
|
@ -28,6 +28,9 @@ int __exfat_write_inode(struct inode *inode, int sync)
|
|||||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||||
struct exfat_inode_info *ei = EXFAT_I(inode);
|
struct exfat_inode_info *ei = EXFAT_I(inode);
|
||||||
bool is_dir = (ei->type == TYPE_DIR) ? true : false;
|
bool is_dir = (ei->type == TYPE_DIR) ? true : false;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
struct timespec64 ts;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (inode->i_ino == EXFAT_ROOT_INO)
|
if (inode->i_ino == EXFAT_ROOT_INO)
|
||||||
return 0;
|
return 0;
|
||||||
@ -57,6 +60,20 @@ int __exfat_write_inode(struct inode *inode, int sync)
|
|||||||
&ep->dentry.file.create_time,
|
&ep->dentry.file.create_time,
|
||||||
&ep->dentry.file.create_date,
|
&ep->dentry.file.create_date,
|
||||||
&ep->dentry.file.create_time_cs);
|
&ep->dentry.file.create_time_cs);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
ts = inode_get_mtime(inode);
|
||||||
|
exfat_set_entry_time(sbi, &ts,
|
||||||
|
&ep->dentry.file.modify_tz,
|
||||||
|
&ep->dentry.file.modify_time,
|
||||||
|
&ep->dentry.file.modify_date,
|
||||||
|
&ep->dentry.file.modify_time_cs);
|
||||||
|
ts = inode_get_atime(inode);
|
||||||
|
exfat_set_entry_time(sbi, &ts,
|
||||||
|
&ep->dentry.file.access_tz,
|
||||||
|
&ep->dentry.file.access_time,
|
||||||
|
&ep->dentry.file.access_date,
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
exfat_set_entry_time(sbi, &inode->i_mtime,
|
exfat_set_entry_time(sbi, &inode->i_mtime,
|
||||||
&ep->dentry.file.modify_tz,
|
&ep->dentry.file.modify_tz,
|
||||||
&ep->dentry.file.modify_time,
|
&ep->dentry.file.modify_time,
|
||||||
@ -67,6 +84,7 @@ int __exfat_write_inode(struct inode *inode, int sync)
|
|||||||
&ep->dentry.file.access_time,
|
&ep->dentry.file.access_time,
|
||||||
&ep->dentry.file.access_date,
|
&ep->dentry.file.access_date,
|
||||||
NULL);
|
NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* File size should be zero if there is no cluster allocated */
|
/* File size should be zero if there is no cluster allocated */
|
||||||
on_disk_size = i_size_read(inode);
|
on_disk_size = i_size_read(inode);
|
||||||
@ -380,7 +398,15 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to)
|
|||||||
if (to > i_size_read(inode)) {
|
if (to > i_size_read(inode)) {
|
||||||
truncate_pagecache(inode, i_size_read(inode));
|
truncate_pagecache(inode, i_size_read(inode));
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode_set_ctime_current(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
@ -436,13 +462,21 @@ static int exfat_write_end(struct file *file, struct address_space *mapping,
|
|||||||
if (err < len)
|
if (err < len)
|
||||||
exfat_write_failed(mapping, pos+len);
|
exfat_write_failed(mapping, pos+len);
|
||||||
|
|
||||||
if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) {
|
if (!(err < 0) && !(ei->attr & EXFAT_ATTR_ARCHIVE)) {
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode_set_ctime_current(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +663,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
|||||||
inode->i_generation = prandom_u32();
|
inode->i_generation = prandom_u32();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (info->attr & ATTR_SUBDIR) { /* directory */
|
if (info->attr & EXFAT_ATTR_SUBDIR) { /* directory */
|
||||||
inode->i_generation &= ~1;
|
inode->i_generation &= ~1;
|
||||||
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
|
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
|
||||||
inode->i_op = &exfat_dir_inode_operations;
|
inode->i_op = &exfat_dir_inode_operations;
|
||||||
@ -658,10 +692,22 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
|||||||
exfat_save_attr(inode, info->attr);
|
exfat_save_attr(inode, info->attr);
|
||||||
|
|
||||||
inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
|
inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(inode, info->mtime);
|
||||||
|
#else
|
||||||
inode->i_mtime = info->mtime;
|
inode->i_mtime = info->mtime;
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode_set_ctime_to_ts(inode, info->mtime);
|
||||||
|
#else
|
||||||
inode->i_ctime = info->mtime;
|
inode->i_ctime = info->mtime;
|
||||||
|
#endif
|
||||||
ei->i_crtime = info->crtime;
|
ei->i_crtime = info->crtime;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_atime_to_ts(inode, info->atime);
|
||||||
|
#else
|
||||||
inode->i_atime = info->atime;
|
inode->i_atime = info->atime;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,16 @@ void exfat_truncate_atime(struct timespec *ts)
|
|||||||
ts->tv_nsec = 0;
|
ts->tv_nsec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
void exfat_truncate_inode_atime(struct inode *inode)
|
||||||
|
{
|
||||||
|
struct timespec64 atime = inode_get_atime(inode);
|
||||||
|
|
||||||
|
exfat_truncate_atime(&atime);
|
||||||
|
inode_set_atime_to_ts(inode, atime);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type)
|
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
162
fs/exfat/namei.c
162
fs/exfat/namei.c
@ -378,14 +378,20 @@ static int exfat_find_empty_entry(struct inode *inode,
|
|||||||
if (exfat_check_max_dentries(inode))
|
if (exfat_check_max_dentries(inode))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
/* we trust p_dir->size regardless of FAT type */
|
|
||||||
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate new cluster to this directory
|
* Allocate new cluster to this directory
|
||||||
*/
|
*/
|
||||||
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
if (ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
|
/* we trust p_dir->size regardless of FAT type */
|
||||||
|
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
||||||
|
} else {
|
||||||
|
/* This directory is empty */
|
||||||
|
exfat_chain_set(&clu, EXFAT_EOF_CLUSTER, 0,
|
||||||
|
ALLOC_NO_FAT_CHAIN);
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate a cluster */
|
/* allocate a cluster */
|
||||||
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
||||||
@ -395,6 +401,11 @@ static int exfat_find_empty_entry(struct inode *inode,
|
|||||||
if (exfat_zeroed_cluster(inode, clu.dir))
|
if (exfat_zeroed_cluster(inode, clu.dir))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
|
||||||
|
ei->start_clu = clu.dir;
|
||||||
|
p_dir->dir = clu.dir;
|
||||||
|
}
|
||||||
|
|
||||||
/* append to the FAT chain */
|
/* append to the FAT chain */
|
||||||
if (clu.flags != p_dir->flags) {
|
if (clu.flags != p_dir->flags) {
|
||||||
/* no-fat-chain bit is disabled,
|
/* no-fat-chain bit is disabled,
|
||||||
@ -534,7 +545,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == TYPE_DIR) {
|
if (type == TYPE_DIR && !sbi->options.zero_size_dir) {
|
||||||
ret = exfat_alloc_new_dir(inode, &clu);
|
ret = exfat_alloc_new_dir(inode, &clu);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@ -561,13 +572,16 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
|||||||
info->type = type;
|
info->type = type;
|
||||||
|
|
||||||
if (type == TYPE_FILE) {
|
if (type == TYPE_FILE) {
|
||||||
info->attr = ATTR_ARCHIVE;
|
info->attr = EXFAT_ATTR_ARCHIVE;
|
||||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
info->size = 0;
|
info->size = 0;
|
||||||
info->num_subdirs = 0;
|
info->num_subdirs = 0;
|
||||||
} else {
|
} else {
|
||||||
info->attr = ATTR_SUBDIR;
|
info->attr = EXFAT_ATTR_SUBDIR;
|
||||||
info->start_clu = start_clu;
|
if (sbi->options.zero_size_dir)
|
||||||
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
|
else
|
||||||
|
info->start_clu = start_clu;
|
||||||
info->size = clu_size;
|
info->size = clu_size;
|
||||||
info->num_subdirs = EXFAT_MIN_SUBDIR;
|
info->num_subdirs = EXFAT_MIN_SUBDIR;
|
||||||
}
|
}
|
||||||
@ -611,7 +625,15 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||||||
dir->i_version++;
|
dir->i_version++;
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||||
|
#else
|
||||||
|
dir->i_mtime = inode_set_ctime_current(dir);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
dir->i_ctime = dir->i_mtime = current_time(dir);
|
dir->i_ctime = dir->i_mtime = current_time(dir);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
|
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
@ -632,14 +654,23 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||||||
inode->i_version++;
|
inode->i_version++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
EXFAT_I(inode)->i_crtime = simple_inode_init_ts(inode);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
|
#else
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode->i_mtime = inode->i_atime = EXFAT_I(inode)->i_crtime = inode_set_ctime_current(inode);
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||||
EXFAT_I(inode)->i_crtime = current_time(inode);
|
EXFAT_I(inode)->i_crtime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||||
EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC;
|
EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
||||||
|
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
@ -709,7 +740,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
|
|||||||
info->type = exfat_get_entry_type(ep);
|
info->type = exfat_get_entry_type(ep);
|
||||||
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||||
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
||||||
if ((info->type == TYPE_FILE) && (info->size == 0)) {
|
if (info->size == 0) {
|
||||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
} else {
|
} else {
|
||||||
@ -888,24 +919,43 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
|
|||||||
#else
|
#else
|
||||||
dir->i_version++;
|
dir->i_version++;
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
|
||||||
dir->i_mtime = dir->i_atime = current_time(dir);
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
simple_inode_init_ts(dir);
|
||||||
|
exfat_truncate_inode_atime(dir);
|
||||||
#else
|
#else
|
||||||
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
dir->i_mtime = dir->i_atime = inode_set_ctime_current(dir);
|
||||||
|
#else
|
||||||
|
dir->i_mtime = dir->i_atime = dir->i_ctime = current_time(dir);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&dir->i_atime);
|
exfat_truncate_atime(&dir->i_atime);
|
||||||
|
#endif
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
exfat_sync_inode(dir);
|
exfat_sync_inode(dir);
|
||||||
else
|
else
|
||||||
mark_inode_dirty(dir);
|
mark_inode_dirty(dir);
|
||||||
|
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
inode->i_mtime = inode->i_atime = current_time(inode);
|
simple_inode_init_ts(inode);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode->i_atime = dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
exfat_unhash_inode(inode);
|
exfat_unhash_inode(inode);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
exfat_d_version_set(dentry, inode_query_iversion(dir));
|
exfat_d_version_set(dentry, inode_query_iversion(dir));
|
||||||
@ -950,7 +1000,15 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||||
|
#else
|
||||||
|
dir->i_mtime = inode_set_ctime_current(dir);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
dir->i_ctime = dir->i_mtime = current_time(dir);
|
dir->i_ctime = dir->i_mtime = current_time(dir);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
|
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
@ -971,14 +1029,23 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|||||||
#else
|
#else
|
||||||
inode->i_version++;
|
inode->i_version++;
|
||||||
#endif
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
EXFAT_I(inode)->i_crtime = simple_inode_init_ts(inode);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
|
#else
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode->i_mtime = inode->i_atime = EXFAT_I(inode)->i_crtime = inode_set_ctime_current(inode);
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||||
EXFAT_I(inode)->i_crtime = current_time(inode);
|
EXFAT_I(inode)->i_crtime = current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||||
EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC;
|
EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
||||||
|
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
@ -1000,6 +1067,9 @@ static int exfat_check_dir_empty(struct super_block *sb,
|
|||||||
|
|
||||||
dentries_per_clu = sbi->dentries_per_clu;
|
dentries_per_clu = sbi->dentries_per_clu;
|
||||||
|
|
||||||
|
if (p_dir->dir == EXFAT_EOF_CLUSTER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
exfat_chain_dup(&clu, p_dir);
|
exfat_chain_dup(&clu, p_dir);
|
||||||
|
|
||||||
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
||||||
@ -1093,12 +1163,21 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
#else
|
#else
|
||||||
dir->i_version++;
|
dir->i_version++;
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
dir->i_mtime = dir->i_atime = current_time(dir);
|
simple_inode_init_ts(dir);
|
||||||
|
exfat_truncate_inode_atime(dir);
|
||||||
#else
|
#else
|
||||||
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
dir->i_mtime = dir->i_atime = inode_set_ctime_current(dir);
|
||||||
|
#else
|
||||||
|
dir->i_mtime = dir->i_atime = dir->i_ctime = current_time(dir);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
dir->i_mtime = dir->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&dir->i_atime);
|
exfat_truncate_atime(&dir->i_atime);
|
||||||
|
#endif
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
exfat_sync_inode(dir);
|
exfat_sync_inode(dir);
|
||||||
else
|
else
|
||||||
@ -1106,12 +1185,21 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
drop_nlink(dir);
|
drop_nlink(dir);
|
||||||
|
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
inode->i_mtime = inode->i_atime = current_time(inode);
|
simple_inode_init_ts(inode);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
exfat_unhash_inode(inode);
|
exfat_unhash_inode(inode);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
exfat_d_version_set(dentry, inode_query_iversion(dir));
|
exfat_d_version_set(dentry, inode_query_iversion(dir));
|
||||||
@ -1160,8 +1248,8 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
|||||||
|
|
||||||
*epnew = *epold;
|
*epnew = *epold;
|
||||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(new_bh, sync);
|
exfat_update_bh(new_bh, sync);
|
||||||
brelse(old_bh);
|
brelse(old_bh);
|
||||||
@ -1192,8 +1280,8 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
|||||||
ei->entry = newentry;
|
ei->entry = newentry;
|
||||||
} else {
|
} else {
|
||||||
if (exfat_get_entry_type(epold) == TYPE_FILE) {
|
if (exfat_get_entry_type(epold) == TYPE_FILE) {
|
||||||
epold->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epold->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(old_bh, sync);
|
exfat_update_bh(old_bh, sync);
|
||||||
brelse(old_bh);
|
brelse(old_bh);
|
||||||
@ -1241,8 +1329,8 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
|
|||||||
|
|
||||||
*epnew = *epmov;
|
*epnew = *epmov;
|
||||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(new_bh, IS_DIRSYNC(inode));
|
exfat_update_bh(new_bh, IS_DIRSYNC(inode));
|
||||||
brelse(mov_bh);
|
brelse(mov_bh);
|
||||||
@ -1383,7 +1471,8 @@ static int __exfat_rename(struct inode *old_parent_inode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
||||||
if (new_entry_type == TYPE_DIR) {
|
if (new_entry_type == TYPE_DIR &&
|
||||||
|
new_ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
/* new_ei, new_clu_to_free */
|
/* new_ei, new_clu_to_free */
|
||||||
struct exfat_chain new_clu_to_free;
|
struct exfat_chain new_clu_to_free;
|
||||||
|
|
||||||
@ -1463,13 +1552,22 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
new_dir->i_version++;
|
new_dir->i_version++;
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
|
||||||
|
EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
|
||||||
|
#else
|
||||||
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
|
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
|
||||||
EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
|
EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
|
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
|
||||||
EXFAT_I(new_dir)->i_crtime = CURRENT_TIME_SEC;
|
EXFAT_I(new_dir)->i_crtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
exfat_truncate_inode_atime(new_dir);
|
||||||
|
#else
|
||||||
exfat_truncate_atime(&new_dir->i_atime);
|
exfat_truncate_atime(&new_dir->i_atime);
|
||||||
|
#endif
|
||||||
if (IS_DIRSYNC(new_dir))
|
if (IS_DIRSYNC(new_dir))
|
||||||
exfat_sync_inode(new_dir);
|
exfat_sync_inode(new_dir);
|
||||||
else
|
else
|
||||||
@ -1496,7 +1594,9 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
old_dir->i_version++;
|
old_dir->i_version++;
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(6, 6, 0)
|
||||||
old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
|
old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
|
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
@ -1518,8 +1618,12 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
WARN_ON(new_inode->i_nlink == 0);
|
WARN_ON(new_inode->i_nlink == 0);
|
||||||
}
|
}
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
EXFAT_I(new_inode)->i_crtime = current_time(new_inode);
|
||||||
|
#else
|
||||||
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
|
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
|
||||||
current_time(new_inode);
|
current_time(new_inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
|
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
|
||||||
CURRENT_TIME_SEC;
|
CURRENT_TIME_SEC;
|
||||||
|
@ -195,6 +195,8 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
|
|||||||
seq_puts(m, ",sys_tz");
|
seq_puts(m, ",sys_tz");
|
||||||
else if (opts->time_offset)
|
else if (opts->time_offset)
|
||||||
seq_printf(m, ",time_offset=%d", opts->time_offset);
|
seq_printf(m, ",time_offset=%d", opts->time_offset);
|
||||||
|
if (opts->zero_size_dir)
|
||||||
|
seq_puts(m, ",zero_size_dir");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +280,7 @@ enum {
|
|||||||
Opt_keep_last_dots,
|
Opt_keep_last_dots,
|
||||||
Opt_sys_tz,
|
Opt_sys_tz,
|
||||||
Opt_time_offset,
|
Opt_time_offset,
|
||||||
|
Opt_zero_size_dir,
|
||||||
|
|
||||||
/* Deprecated options */
|
/* Deprecated options */
|
||||||
Opt_utf8,
|
Opt_utf8,
|
||||||
@ -323,6 +326,7 @@ static const struct fs_parameter_spec exfat_param_specs[] = {
|
|||||||
fsparam_flag("keep_last_dots", Opt_keep_last_dots),
|
fsparam_flag("keep_last_dots", Opt_keep_last_dots),
|
||||||
fsparam_flag("sys_tz", Opt_sys_tz),
|
fsparam_flag("sys_tz", Opt_sys_tz),
|
||||||
fsparam_s32("time_offset", Opt_time_offset),
|
fsparam_s32("time_offset", Opt_time_offset),
|
||||||
|
fsparam_flag("zero_size_dir", Opt_zero_size_dir),
|
||||||
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
|
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
|
||||||
NULL),
|
NULL),
|
||||||
__fsparam(NULL, "debug", Opt_debug, fs_param_deprecated,
|
__fsparam(NULL, "debug", Opt_debug, fs_param_deprecated,
|
||||||
@ -403,6 +407,9 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
opts->time_offset = result.int_32;
|
opts->time_offset = result.int_32;
|
||||||
break;
|
break;
|
||||||
|
case Opt_zero_size_dir:
|
||||||
|
opts->zero_size_dir = true;
|
||||||
|
break;
|
||||||
case Opt_utf8:
|
case Opt_utf8:
|
||||||
case Opt_debug:
|
case Opt_debug:
|
||||||
case Opt_namecase:
|
case Opt_namecase:
|
||||||
@ -435,6 +442,7 @@ enum {
|
|||||||
Opt_debug,
|
Opt_debug,
|
||||||
Opt_namecase,
|
Opt_namecase,
|
||||||
Opt_codepage,
|
Opt_codepage,
|
||||||
|
Opt_zero_size_dir,
|
||||||
Opt_fs,
|
Opt_fs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -454,6 +462,7 @@ static const match_table_t exfat_tokens = {
|
|||||||
{Opt_namecase, "namecase=%u"},
|
{Opt_namecase, "namecase=%u"},
|
||||||
{Opt_debug, "debug"},
|
{Opt_debug, "debug"},
|
||||||
{Opt_utf8, "utf8"},
|
{Opt_utf8, "utf8"},
|
||||||
|
{Opt_zero_size_dir, "zero_size_dir"},
|
||||||
{Opt_err, NULL}
|
{Opt_err, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -545,6 +554,9 @@ static int parse_options(struct super_block *sb, char *options, int silent,
|
|||||||
case Opt_namecase:
|
case Opt_namecase:
|
||||||
case Opt_codepage:
|
case Opt_codepage:
|
||||||
break;
|
break;
|
||||||
|
case Opt_zero_size_dir:
|
||||||
|
opts->zero_size_dir = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
exfat_err(sb,
|
exfat_err(sb,
|
||||||
@ -628,7 +640,7 @@ static int exfat_read_root(struct inode *inode)
|
|||||||
inode->i_version++;
|
inode->i_version++;
|
||||||
#endif
|
#endif
|
||||||
inode->i_generation = 0;
|
inode->i_generation = 0;
|
||||||
inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777);
|
inode->i_mode = exfat_make_mode(sbi, EXFAT_ATTR_SUBDIR, 0777);
|
||||||
inode->i_op = &exfat_dir_inode_operations;
|
inode->i_op = &exfat_dir_inode_operations;
|
||||||
inode->i_fop = &exfat_dir_operations;
|
inode->i_fop = &exfat_dir_operations;
|
||||||
|
|
||||||
@ -637,15 +649,24 @@ static int exfat_read_root(struct inode *inode)
|
|||||||
ei->i_size_aligned = i_size_read(inode);
|
ei->i_size_aligned = i_size_read(inode);
|
||||||
ei->i_size_ondisk = i_size_read(inode);
|
ei->i_size_ondisk = i_size_read(inode);
|
||||||
|
|
||||||
exfat_save_attr(inode, ATTR_SUBDIR);
|
exfat_save_attr(inode, EXFAT_ATTR_SUBDIR);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
|
||||||
|
ei->i_crtime = simple_inode_init_ts(inode);
|
||||||
|
exfat_truncate_inode_atime(inode);
|
||||||
|
#else
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
inode->i_mtime = inode->i_atime = ei->i_crtime = inode_set_ctime_current(inode);
|
||||||
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
|
||||||
current_time(inode);
|
current_time(inode);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
|
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
|
||||||
CURRENT_TIME_SEC;
|
CURRENT_TIME_SEC;
|
||||||
#endif
|
#endif
|
||||||
exfat_truncate_atime(&inode->i_atime);
|
exfat_truncate_atime(&inode->i_atime);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user