Update from SM-G950F_OO_Opensource_kernel
This commit is contained in:
parent
8e7bcf4240
commit
0490ece85e
8
Kconfig
8
Kconfig
|
|
@ -27,6 +27,9 @@ config SDFAT_SUPPORT_DIR_SYNC
|
||||||
bool "Enable supporting dir sync"
|
bool "Enable supporting dir sync"
|
||||||
default n
|
default n
|
||||||
depends on SDFAT_FS
|
depends on SDFAT_FS
|
||||||
|
help
|
||||||
|
If you enable this feature, the modification for directory operation
|
||||||
|
is written to a storage at once.
|
||||||
|
|
||||||
config SDFAT_DEFAULT_CODEPAGE
|
config SDFAT_DEFAULT_CODEPAGE
|
||||||
int "Default codepage for sdFAT"
|
int "Default codepage for sdFAT"
|
||||||
|
|
@ -93,3 +96,8 @@ config SDFAT_DBG_BUGON
|
||||||
bool "enable strict BUG_ON() for debugging"
|
bool "enable strict BUG_ON() for debugging"
|
||||||
depends on SDFAT_FS && SDFAT_DEBUG
|
depends on SDFAT_FS && SDFAT_DEBUG
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config SDFAT_STATISTICS
|
||||||
|
bool "enable statistics for bigdata"
|
||||||
|
depends on SDFAT_FS
|
||||||
|
default y
|
||||||
|
|
|
||||||
5
Makefile
5
Makefile
|
|
@ -5,10 +5,11 @@
|
||||||
obj-$(CONFIG_SDFAT_FS) += sdfat_fs.o
|
obj-$(CONFIG_SDFAT_FS) += sdfat_fs.o
|
||||||
|
|
||||||
sdfat_fs-objs := sdfat.o core.o core_fat.o core_exfat.o api.o blkdev.o \
|
sdfat_fs-objs := sdfat.o core.o core_fat.o core_exfat.o api.o blkdev.o \
|
||||||
fatent.o amap_smart.o cache.o dfr.o nls.o misc.o xattr.o \
|
fatent.o amap_smart.o cache.o dfr.o nls.o misc.o \
|
||||||
mpage.o extent.o
|
mpage.o extent.o
|
||||||
|
|
||||||
|
sdfat_fs-$(CONFIG_SDFAT_VIRTUAL_XATTR) += xattr.o
|
||||||
|
sdfat_fs-$(CONFIG_SDFAT_STATISTICS) += statistics.o
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
|
||||||
359
amap_smart.c
359
amap_smart.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -85,7 +83,7 @@ static inline int amap_remove_from_list(AU_INFO_T *au, struct slist_head *shead)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full-linear serach => Find AU with max. number of fclu */
|
/* Full-linear serach => Find AU with max. number of fclu */
|
||||||
static inline AU_INFO_T* amap_find_hot_au_largest(struct slist_head *shead)
|
static inline AU_INFO_T *amap_find_hot_au_largest(struct slist_head *shead)
|
||||||
{
|
{
|
||||||
struct slist_head *iter;
|
struct slist_head *iter;
|
||||||
uint16_t max_fclu = 0;
|
uint16_t max_fclu = 0;
|
||||||
|
|
@ -111,8 +109,9 @@ static inline AU_INFO_T* amap_find_hot_au_largest(struct slist_head *shead)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find partially used AU with max. number of fclu.
|
/* Find partially used AU with max. number of fclu.
|
||||||
If there is no partial AU available, pick a clean one */
|
* If there is no partial AU available, pick a clean one
|
||||||
static inline AU_INFO_T* amap_find_hot_au_partial(AMAP_T *amap)
|
*/
|
||||||
|
static inline AU_INFO_T *amap_find_hot_au_partial(AMAP_T *amap)
|
||||||
{
|
{
|
||||||
struct slist_head *iter;
|
struct slist_head *iter;
|
||||||
uint16_t max_fclu = 0;
|
uint16_t max_fclu = 0;
|
||||||
|
|
@ -147,13 +146,13 @@ static inline AU_INFO_T* amap_find_hot_au_partial(AMAP_T *amap)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Size-base AU management functions
|
* Size-base AU management functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add au into cold AU MAP
|
* Add au into cold AU MAP
|
||||||
au: an isolated (not in a list) AU data structure
|
* au: an isolated (not in a list) AU data structure
|
||||||
*/
|
*/
|
||||||
int amap_add_cold_au(AMAP_T *amap, AU_INFO_T *au)
|
int amap_add_cold_au(AMAP_T *amap, AU_INFO_T *au)
|
||||||
{
|
{
|
||||||
FCLU_NODE_T *fclu_node = NULL;
|
FCLU_NODE_T *fclu_node = NULL;
|
||||||
|
|
@ -179,9 +178,9 @@ int amap_add_cold_au(AMAP_T *amap, AU_INFO_T *au)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Remove an AU from AU MAP
|
* Remove an AU from AU MAP
|
||||||
*/
|
*/
|
||||||
int amap_remove_cold_au(AMAP_T *amap, AU_INFO_T* au)
|
int amap_remove_cold_au(AMAP_T *amap, AU_INFO_T *au)
|
||||||
{
|
{
|
||||||
struct list_head *prev = au->head.prev;
|
struct list_head *prev = au->head.prev;
|
||||||
|
|
||||||
|
|
@ -198,13 +197,13 @@ int amap_remove_cold_au(AMAP_T *amap, AU_INFO_T* au)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* "Find" best fit AU
|
/* "Find" best fit AU
|
||||||
returns NULL if there is no AU w/ enough free space.
|
* returns NULL if there is no AU w/ enough free space.
|
||||||
|
*
|
||||||
This function doesn't change AU status.
|
* This function doesn't change AU status.
|
||||||
The caller should call amap_remove_cold_au() if needed.
|
* The caller should call amap_remove_cold_au() if needed.
|
||||||
*/
|
*/
|
||||||
AU_INFO_T* amap_find_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
AU_INFO_T *amap_find_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
||||||
{
|
{
|
||||||
AU_INFO_T *au = NULL;
|
AU_INFO_T *au = NULL;
|
||||||
FCLU_NODE_T *fclu_iter;
|
FCLU_NODE_T *fclu_iter;
|
||||||
|
|
@ -243,14 +242,15 @@ AU_INFO_T* amap_find_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* "Pop" best fit AU
|
/* "Pop" best fit AU
|
||||||
returns NULL if there is no AU w/ enough free space.
|
*
|
||||||
The returned AU will not be in the list anymore.
|
* returns NULL if there is no AU w/ enough free space.
|
||||||
*/
|
* The returned AU will not be in the list anymore.
|
||||||
AU_INFO_T* amap_pop_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
*/
|
||||||
|
AU_INFO_T *amap_pop_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
||||||
{
|
{
|
||||||
/* Naive implementation */
|
/* Naive implementation */
|
||||||
AU_INFO_T* au;
|
AU_INFO_T *au;
|
||||||
|
|
||||||
au = amap_find_cold_au_bestfit(amap, free_clusters);
|
au = amap_find_cold_au_bestfit(amap, free_clusters);
|
||||||
if (au)
|
if (au)
|
||||||
|
|
@ -262,15 +262,14 @@ AU_INFO_T* amap_pop_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters)
|
||||||
|
|
||||||
|
|
||||||
/* Pop the AU with the largest free space
|
/* Pop the AU with the largest free space
|
||||||
|
*
|
||||||
search from 'start_fclu' to 0
|
* search from 'start_fclu' to 0
|
||||||
(target freecluster : -1 for each step)
|
* (target freecluster : -1 for each step)
|
||||||
|
* start_fclu = 0 means to search from the max. value
|
||||||
start_fclu = 0 means to search from the max. value
|
*/
|
||||||
*/
|
AU_INFO_T *amap_pop_cold_au_largest(AMAP_T *amap, uint16_t start_fclu)
|
||||||
AU_INFO_T* amap_pop_cold_au_largest(AMAP_T *amap, uint16_t start_fclu)
|
|
||||||
{
|
{
|
||||||
AU_INFO_T* au = NULL;
|
AU_INFO_T *au = NULL;
|
||||||
FCLU_NODE_T *fclu_iter;
|
FCLU_NODE_T *fclu_iter;
|
||||||
|
|
||||||
if (!start_fclu)
|
if (!start_fclu)
|
||||||
|
|
@ -311,10 +310,10 @@ AU_INFO_T* amap_pop_cold_au_largest(AMAP_T *amap, uint16_t start_fclu)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================
|
* ===============================================
|
||||||
Allocation Map related functions
|
* Allocation Map related functions
|
||||||
===============================================
|
* ===============================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Create AMAP related data structure (mount time) */
|
/* Create AMAP related data structure (mount time) */
|
||||||
int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hidden_sect)
|
int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hidden_sect)
|
||||||
|
|
@ -388,8 +387,9 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
amap->n_clean_au = 0;
|
amap->n_clean_au = 0;
|
||||||
amap->n_full_au = 0;
|
amap->n_full_au = 0;
|
||||||
|
|
||||||
/* Reflect block-partition align first,
|
/* Reflect block-partition align first,
|
||||||
then partition-data_start align */
|
* then partition-data_start align
|
||||||
|
*/
|
||||||
amap->clu_align_bias = (misaligned_sect / fsi->sect_per_clus);
|
amap->clu_align_bias = (misaligned_sect / fsi->sect_per_clus);
|
||||||
amap->clu_align_bias += (fsi->data_start_sector >> fsi->sect_per_clus_bits) - CLUS_BASE;
|
amap->clu_align_bias += (fsi->data_start_sector >> fsi->sect_per_clus_bits) - CLUS_BASE;
|
||||||
amap->clusters_per_au = sect_per_au / fsi->sect_per_clus;
|
amap->clusters_per_au = sect_per_au / fsi->sect_per_clus;
|
||||||
|
|
@ -417,7 +417,6 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
/* Allocate AU info table */
|
/* Allocate AU info table */
|
||||||
n_au_table = (amap->n_au + N_AU_PER_TABLE - 1) / N_AU_PER_TABLE;
|
n_au_table = (amap->n_au + N_AU_PER_TABLE - 1) / N_AU_PER_TABLE;
|
||||||
amap->au_table = kmalloc(sizeof(AU_INFO_T *) * n_au_table, GFP_NOIO);
|
amap->au_table = kmalloc(sizeof(AU_INFO_T *) * n_au_table, GFP_NOIO);
|
||||||
|
|
||||||
if (!amap->au_table) {
|
if (!amap->au_table) {
|
||||||
sdfat_msg(sb, KERN_ERR,
|
sdfat_msg(sb, KERN_ERR,
|
||||||
"failed to alloc amap->au_table\n");
|
"failed to alloc amap->au_table\n");
|
||||||
|
|
@ -439,9 +438,9 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
(unsigned long)sizeof(FCLU_NODE_T));
|
(unsigned long)sizeof(FCLU_NODE_T));
|
||||||
|
|
||||||
if (!amap->fclu_order)
|
if (!amap->fclu_order)
|
||||||
amap->fclu_nodes = (FCLU_NODE_T*)get_zeroed_page(GFP_NOIO);
|
amap->fclu_nodes = (FCLU_NODE_T *)get_zeroed_page(GFP_NOIO);
|
||||||
else
|
else
|
||||||
amap->fclu_nodes = (FCLU_NODE_T*)vzalloc(PAGE_SIZE << amap->fclu_order);
|
amap->fclu_nodes = vzalloc(PAGE_SIZE << amap->fclu_order);
|
||||||
|
|
||||||
amap->fclu_hint = amap->clusters_per_au;
|
amap->fclu_hint = amap->clusters_per_au;
|
||||||
|
|
||||||
|
|
@ -468,16 +467,15 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
for (i = 0; i < amap->clusters_per_au; i++)
|
for (i = 0; i < amap->clusters_per_au; i++)
|
||||||
INIT_LIST_HEAD(&amap->fclu_nodes[i].head);
|
INIT_LIST_HEAD(&amap->fclu_nodes[i].head);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Thanks to kzalloc()
|
* Thanks to kzalloc()
|
||||||
amap->entries[i_au].free_clusters = 0;
|
* amap->entries[i_au].free_clusters = 0;
|
||||||
amap->entries[i_au].head.prev = NULL;
|
* amap->entries[i_au].head.prev = NULL;
|
||||||
amap->entries[i_au].head.next = NULL;
|
* amap->entries[i_au].head.next = NULL;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Parse FAT table */
|
/* Parse FAT table */
|
||||||
for (i_clu = CLUS_BASE; i_clu < fsi->num_clusters; i_clu++){
|
for (i_clu = CLUS_BASE; i_clu < fsi->num_clusters; i_clu++) {
|
||||||
u32 clu_data;
|
u32 clu_data;
|
||||||
AU_INFO_T *au;
|
AU_INFO_T *au;
|
||||||
|
|
||||||
|
|
@ -495,7 +493,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build AU list */
|
/* Build AU list */
|
||||||
for (i_au = 0; i_au < amap->n_au; i_au++){
|
for (i_au = 0; i_au < amap->n_au; i_au++) {
|
||||||
AU_INFO_T *au = GET_AU(amap, i_au);
|
AU_INFO_T *au = GET_AU(amap, i_au);
|
||||||
|
|
||||||
au->idx = i_au;
|
au->idx = i_au;
|
||||||
|
|
@ -522,7 +520,6 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid
|
||||||
amap->total_fclu_hot += GET_AU(amap, i_au_root)->free_clusters;
|
amap->total_fclu_hot += GET_AU(amap, i_au_root)->free_clusters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fsi->amap = amap;
|
fsi->amap = amap;
|
||||||
fsi->used_clusters = total_used_clusters;
|
fsi->used_clusters = total_used_clusters;
|
||||||
|
|
||||||
|
|
@ -575,6 +572,7 @@ void amap_destroy(struct super_block *sb)
|
||||||
|
|
||||||
if (amap->au_table) {
|
if (amap->au_table) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < n_au_table; i++)
|
for (i = 0; i < n_au_table; i++)
|
||||||
free_page((unsigned long)amap->au_table[i]);
|
free_page((unsigned long)amap->au_table[i]);
|
||||||
|
|
||||||
|
|
@ -586,16 +584,14 @@ void amap_destroy(struct super_block *sb)
|
||||||
vfree(amap->fclu_nodes);
|
vfree(amap->fclu_nodes);
|
||||||
kfree(amap);
|
kfree(amap);
|
||||||
SDFAT_SB(sb)->fsi.amap = NULL;
|
SDFAT_SB(sb)->fsi.amap = NULL;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check status of FS
|
* Check status of FS
|
||||||
and change destination if needed to disable AU-aligned alloc.
|
* and change destination if needed to disable AU-aligned alloc.
|
||||||
(from ALLOC_COLD_ALIGNED to ALLOC_COLD_SEQ)
|
* (from ALLOC_COLD_ALIGNED to ALLOC_COLD_SEQ)
|
||||||
*/
|
*/
|
||||||
static inline int amap_update_dest(AMAP_T *amap, int ori_dest)
|
static inline int amap_update_dest(AMAP_T *amap, int ori_dest)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(amap->sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(amap->sb)->fsi);
|
||||||
|
|
@ -609,23 +605,22 @@ static inline int amap_update_dest(AMAP_T *amap, int ori_dest)
|
||||||
n_partial_freeclus = fsi->num_clusters - fsi->used_clusters -
|
n_partial_freeclus = fsi->num_clusters - fsi->used_clusters -
|
||||||
amap->clusters_per_au * amap->n_clean_au;
|
amap->clusters_per_au * amap->n_clean_au;
|
||||||
|
|
||||||
/* Status of AUs : Full / Partial / Clean
|
/* Status of AUs : Full / Partial / Clean
|
||||||
If there are many partial (and badly fragmented) AUs,
|
* If there are many partial (and badly fragmented) AUs,
|
||||||
the throughput will decrease extremly.
|
* the throughput will decrease extremly.
|
||||||
|
*
|
||||||
|
* The follow code will treat those worst cases.
|
||||||
|
*/
|
||||||
|
|
||||||
The follow code will treat those worst cases.
|
/* XXX: AMAP heuristics */
|
||||||
*/
|
|
||||||
|
|
||||||
// XXX: AMAP heuristics
|
|
||||||
if ((amap->n_clean_au * 50 <= amap->n_au) &&
|
if ((amap->n_clean_au * 50 <= amap->n_au) &&
|
||||||
(n_partial_freeclus*2) < (n_partial_au*amap->clusters_per_au)) {
|
(n_partial_freeclus*2) < (n_partial_au*amap->clusters_per_au)) {
|
||||||
/* If clean AUs are fewer than 2% of n_au (80 AUs per 16GB)
|
/* If clean AUs are fewer than 2% of n_au (80 AUs per 16GB)
|
||||||
and fragment ratio is more than 2 (AVG free_clusters=half AU)
|
* and fragment ratio is more than 2 (AVG free_clusters=half AU)
|
||||||
|
*
|
||||||
disable clean-first allocation
|
* disable clean-first allocation
|
||||||
enable VFAT-like sequential allocation
|
* enable VFAT-like sequential allocation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return ALLOC_COLD_SEQ;
|
return ALLOC_COLD_SEQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -636,24 +631,23 @@ static inline int amap_update_dest(AMAP_T *amap, int ori_dest)
|
||||||
#define PACKING_SOFTLIMIT (amap->option.packing_ratio)
|
#define PACKING_SOFTLIMIT (amap->option.packing_ratio)
|
||||||
#define PACKING_HARDLIMIT (amap->option.packing_ratio * 4)
|
#define PACKING_HARDLIMIT (amap->option.packing_ratio * 4)
|
||||||
/*
|
/*
|
||||||
Pick a packing AU if needed.
|
* Pick a packing AU if needed.
|
||||||
Otherwise just return NULL
|
* Otherwise just return NULL
|
||||||
|
*
|
||||||
This function includes some heuristics.
|
* This function includes some heuristics.
|
||||||
*/
|
*/
|
||||||
static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_wb, int *clu_to_skip)
|
static inline AU_INFO_T *amap_get_packing_au(AMAP_T *amap, int dest, int num_to_wb, int *clu_to_skip)
|
||||||
{
|
{
|
||||||
AU_INFO_T* au = NULL;
|
AU_INFO_T *au = NULL;
|
||||||
|
|
||||||
if (dest == ALLOC_COLD_PACKING) {
|
if (dest == ALLOC_COLD_PACKING) {
|
||||||
/* ALLOC_COLD_PACKING:
|
/* ALLOC_COLD_PACKING:
|
||||||
Packing-first mode for defrag.
|
* Packing-first mode for defrag.
|
||||||
Optimized to save clean AU
|
* Optimized to save clean AU
|
||||||
|
*
|
||||||
1) best-fit AU
|
* 1) best-fit AU
|
||||||
2) Smallest AU (w/ minimum free clusters)
|
* 2) Smallest AU (w/ minimum free clusters)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (num_to_wb >= amap->clusters_per_au)
|
if (num_to_wb >= amap->clusters_per_au)
|
||||||
num_to_wb = num_to_wb % amap->clusters_per_au;
|
num_to_wb = num_to_wb % amap->clusters_per_au;
|
||||||
|
|
||||||
|
|
@ -662,9 +656,8 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_
|
||||||
num_to_wb = 1; // Don't use clean AUs
|
num_to_wb = 1; // Don't use clean AUs
|
||||||
|
|
||||||
au = amap_find_cold_au_bestfit(amap, num_to_wb);
|
au = amap_find_cold_au_bestfit(amap, num_to_wb);
|
||||||
|
|
||||||
if (au && au->free_clusters == amap->clusters_per_au && num_to_wb > 1) {
|
if (au && au->free_clusters == amap->clusters_per_au && num_to_wb > 1) {
|
||||||
// if au is clean then get a new partial one
|
/* if au is clean then get a new partial one */
|
||||||
au = amap_find_cold_au_bestfit(amap, 1);
|
au = amap_find_cold_au_bestfit(amap, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -676,28 +669,27 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Heuristic packing:
|
/* Heuristic packing:
|
||||||
This will improve QoS greatly.
|
* This will improve QoS greatly.
|
||||||
|
*
|
||||||
Count # of AU_ALLIGNED allocation.
|
* Count # of AU_ALIGNED allocation.
|
||||||
If the number exceeds the specific threshold,
|
* If the number exceeds the specific threshold,
|
||||||
allocate on a partial AU or generate random I/O.
|
* allocate on a partial AU or generate random I/O.
|
||||||
*/
|
*/
|
||||||
if ((PACKING_SOFTLIMIT > 0) && \
|
if ((PACKING_SOFTLIMIT > 0) &&
|
||||||
(amap->n_need_packing >= PACKING_SOFTLIMIT) && \
|
(amap->n_need_packing >= PACKING_SOFTLIMIT) &&
|
||||||
(num_to_wb < (int)amap->clusters_per_au) ){
|
(num_to_wb < (int)amap->clusters_per_au)) {
|
||||||
/* Best-fit packing:
|
/* Best-fit packing:
|
||||||
If num_to_wb (expected number to be allocated) is smaller than AU_SIZE,
|
* If num_to_wb (expected number to be allocated) is smaller
|
||||||
find a best-fit AU.
|
* than AU_SIZE, find a best-fit AU.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Back margin (heuristics)
|
/* Back margin (heuristics) */
|
||||||
if (num_to_wb < amap->clusters_per_au / 4)
|
if (num_to_wb < amap->clusters_per_au / 4)
|
||||||
num_to_wb = amap->clusters_per_au / 4;
|
num_to_wb = amap->clusters_per_au / 4;
|
||||||
|
|
||||||
au = amap_find_cold_au_bestfit(amap, num_to_wb);
|
au = amap_find_cold_au_bestfit(amap, num_to_wb);
|
||||||
|
if (au != NULL) {
|
||||||
if ((au != NULL)) {
|
|
||||||
amap_remove_cold_au(amap, au);
|
amap_remove_cold_au(amap, au);
|
||||||
|
|
||||||
MMSG("AMAP: packing (cnt: %d) / softlimit, "
|
MMSG("AMAP: packing (cnt: %d) / softlimit, "
|
||||||
|
|
@ -713,15 +705,13 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PACKING_HARDLIMIT != 0 && \
|
if ((PACKING_HARDLIMIT) && amap->n_need_packing >= PACKING_HARDLIMIT) {
|
||||||
amap->n_need_packing >= PACKING_HARDLIMIT) {
|
|
||||||
/* Compulsory SLC flushing:
|
/* Compulsory SLC flushing:
|
||||||
If there was no chance to do best-fit packing
|
* If there was no chance to do best-fit packing
|
||||||
and the # of AU-aligned allocation exceeds HARD threshold,
|
* and the # of AU-aligned allocation exceeds HARD threshold,
|
||||||
then pick a clean AU and generate a compulsory random I/O.
|
* then pick a clean AU and generate a compulsory random I/O.
|
||||||
*/
|
*/
|
||||||
au = amap_pop_cold_au_largest(amap, amap->clusters_per_au);
|
au = amap_pop_cold_au_largest(amap, amap->clusters_per_au);
|
||||||
|
|
||||||
if (au) {
|
if (au) {
|
||||||
MMSG("AMAP: packing (cnt: %d) / hard-limit, largest)\n",
|
MMSG("AMAP: packing (cnt: %d) / hard-limit, largest)\n",
|
||||||
amap->n_need_packing);
|
amap->n_need_packing);
|
||||||
|
|
@ -741,9 +731,10 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Pick a target AU
|
/* Pick a target AU:
|
||||||
- This function should be called only if there are one or more free clusters in the bdev.
|
* This function should be called
|
||||||
*/
|
* only if there are one or more free clusters in the bdev.
|
||||||
|
*/
|
||||||
TARGET_AU_T *amap_get_target_au(AMAP_T *amap, int dest, int num_to_wb)
|
TARGET_AU_T *amap_get_target_au(AMAP_T *amap, int dest, int num_to_wb)
|
||||||
{
|
{
|
||||||
int loop_count = 0;
|
int loop_count = 0;
|
||||||
|
|
@ -751,10 +742,9 @@ TARGET_AU_T *amap_get_target_au(AMAP_T *amap, int dest, int num_to_wb)
|
||||||
retry:
|
retry:
|
||||||
if (++loop_count >= 3) {
|
if (++loop_count >= 3) {
|
||||||
/* No space available (or AMAP consistency error)
|
/* No space available (or AMAP consistency error)
|
||||||
This could happen because of the ignored AUs
|
* This could happen because of the ignored AUs but not likely
|
||||||
but not likely
|
* (because the defrag daemon will not work if there is no enough space)
|
||||||
(because the defrag daemon will not work if there is no enough space)
|
*/
|
||||||
*/
|
|
||||||
BUG_ON(amap->slist_ignored.next == NULL);
|
BUG_ON(amap->slist_ignored.next == NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -787,13 +777,12 @@ retry:
|
||||||
return &amap->cur_hot;
|
return &amap->cur_hot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Cold allocation:
|
/* Cold allocation:
|
||||||
If amap->cur_cold.au has one or more free cluster(s),
|
* If amap->cur_cold.au has one or more free cluster(s),
|
||||||
then just return amap->cur_cold
|
* then just return amap->cur_cold
|
||||||
*/
|
*/
|
||||||
if ( (!amap->cur_cold.au) \
|
if ((!amap->cur_cold.au)
|
||||||
|| (amap->cur_cold.idx == amap->clusters_per_au) \
|
|| (amap->cur_cold.idx == amap->clusters_per_au)
|
||||||
|| (amap->cur_cold.au->free_clusters == 0)) {
|
|| (amap->cur_cold.au->free_clusters == 0)) {
|
||||||
|
|
||||||
AU_INFO_T *au = NULL;
|
AU_INFO_T *au = NULL;
|
||||||
|
|
@ -802,20 +791,21 @@ retry:
|
||||||
|
|
||||||
if (old_au) {
|
if (old_au) {
|
||||||
ASSERT(!IS_AU_WORKING(old_au, amap));
|
ASSERT(!IS_AU_WORKING(old_au, amap));
|
||||||
// must be NOT WORKING AU. (only for information gathering)
|
/* must be NOT WORKING AU.
|
||||||
|
* (only for information gathering)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next target AU is needed:
|
/* Next target AU is needed:
|
||||||
There are 3 possible ALLOC options for cold AU
|
* There are 3 possible ALLOC options for cold AU
|
||||||
|
*
|
||||||
ALLOC_COLD_ALGINED: Clean AU first, but heuristic packing is ON
|
* ALLOC_COLD_ALIGNED: Clean AU first, but heuristic packing is ON
|
||||||
ALLOC_COLD_PACKING: Packing AU first (usually for defrag)
|
* ALLOC_COLD_PACKING: Packing AU first (usually for defrag)
|
||||||
ALLOC_COLD_SEQ : Sequential AU allocation (VFAT-like)
|
* ALLOC_COLD_SEQ : Sequential AU allocation (VFAT-like)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Experimental: Modify allocation destination if needed (ALIGNED => SEQ) */
|
/* Experimental: Modify allocation destination if needed (ALIGNED => SEQ) */
|
||||||
// dest = amap_update_dest(amap, dest);
|
// dest = amap_update_dest(amap, dest);
|
||||||
|
|
||||||
if ((dest == ALLOC_COLD_SEQ) && old_au) {
|
if ((dest == ALLOC_COLD_SEQ) && old_au) {
|
||||||
int i_au = old_au->idx + 1;
|
int i_au = old_au->idx + 1;
|
||||||
|
|
@ -826,7 +816,6 @@ retry:
|
||||||
if ((au->free_clusters > 0) &&
|
if ((au->free_clusters > 0) &&
|
||||||
!IS_AU_HOT(au, amap) &&
|
!IS_AU_HOT(au, amap) &&
|
||||||
!IS_AU_IGNORED(au, amap)) {
|
!IS_AU_IGNORED(au, amap)) {
|
||||||
|
|
||||||
MMSG("AMAP: new cold AU(%d) with %d "
|
MMSG("AMAP: new cold AU(%d) with %d "
|
||||||
"clusters (seq)\n",
|
"clusters (seq)\n",
|
||||||
au->idx, au->free_clusters);
|
au->idx, au->free_clusters);
|
||||||
|
|
@ -860,7 +849,6 @@ retry:
|
||||||
/* Check if the adjacent AU is clean */
|
/* Check if the adjacent AU is clean */
|
||||||
if (old_au && ((old_au->idx + 1) < amap->n_au)) {
|
if (old_au && ((old_au->idx + 1) < amap->n_au)) {
|
||||||
au = GET_AU(amap, old_au->idx + 1);
|
au = GET_AU(amap, old_au->idx + 1);
|
||||||
|
|
||||||
if ((au->free_clusters == amap->clusters_per_au) &&
|
if ((au->free_clusters == amap->clusters_per_au) &&
|
||||||
!IS_AU_HOT(au, amap) &&
|
!IS_AU_HOT(au, amap) &&
|
||||||
!IS_AU_IGNORED(au, amap)) {
|
!IS_AU_IGNORED(au, amap)) {
|
||||||
|
|
@ -879,7 +867,7 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMSG("AMAP: New cold AU (%d) with %d clusters\n", \
|
MMSG("AMAP: New cold AU (%d) with %d clusters\n",
|
||||||
au->idx, au->free_clusters);
|
au->idx, au->free_clusters);
|
||||||
|
|
||||||
ret_new_cold:
|
ret_new_cold:
|
||||||
|
|
@ -897,15 +885,15 @@ ret_new_cold:
|
||||||
void amap_put_target_au(AMAP_T *amap, TARGET_AU_T *cur, int num_allocated)
|
void amap_put_target_au(AMAP_T *amap, TARGET_AU_T *cur, int num_allocated)
|
||||||
{
|
{
|
||||||
/* Update AMAP info vars. */
|
/* Update AMAP info vars. */
|
||||||
if (num_allocated > 0 && \
|
if (num_allocated > 0 &&
|
||||||
(cur->au->free_clusters + num_allocated) == amap->clusters_per_au)
|
(cur->au->free_clusters + num_allocated) == amap->clusters_per_au) {
|
||||||
// if the target AU was a clean AU before this allocation ...
|
/* if the target AU was a clean AU before this allocation ... */
|
||||||
amap->n_clean_au--;
|
amap->n_clean_au--;
|
||||||
if (num_allocated > 0 && \
|
}
|
||||||
|
if (num_allocated > 0 &&
|
||||||
cur->au->free_clusters == 0)
|
cur->au->free_clusters == 0)
|
||||||
amap->n_full_au++;
|
amap->n_full_au++;
|
||||||
|
|
||||||
|
|
||||||
if (IS_AU_HOT(cur->au, amap)) {
|
if (IS_AU_HOT(cur->au, amap)) {
|
||||||
/* Hot AU */
|
/* Hot AU */
|
||||||
MMSG("AMAP: hot allocation at AU %d\n", cur->au->idx);
|
MMSG("AMAP: hot allocation at AU %d\n", cur->au->idx);
|
||||||
|
|
@ -936,11 +924,9 @@ void amap_put_target_au(AMAP_T *amap, TARGET_AU_T *cur, int num_allocated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Reposition target->idx for packing
|
/* Reposition target->idx for packing (Heuristics):
|
||||||
(Heuristics)
|
* Skip (num_to_skip) free clusters in (cur->au)
|
||||||
|
*/
|
||||||
Skip (num_to_skip) free clusters in (cur->au)
|
|
||||||
*/
|
|
||||||
static inline int amap_skip_cluster(struct super_block *sb, TARGET_AU_T *cur, int num_to_skip)
|
static inline int amap_skip_cluster(struct super_block *sb, TARGET_AU_T *cur, int num_to_skip)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
|
|
@ -953,7 +939,6 @@ static inline int amap_skip_cluster(struct super_block *sb, TARGET_AU_T *cur, in
|
||||||
}
|
}
|
||||||
|
|
||||||
clu = CLU_of_i_AU(amap, cur->au->idx, cur->idx);
|
clu = CLU_of_i_AU(amap, cur->au->idx, cur->idx);
|
||||||
|
|
||||||
while (num_to_skip > 0) {
|
while (num_to_skip > 0) {
|
||||||
if (clu >= CLUS_BASE) {
|
if (clu >= CLUS_BASE) {
|
||||||
/* Cf.
|
/* Cf.
|
||||||
|
|
@ -980,7 +965,7 @@ static inline int amap_skip_cluster(struct super_block *sb, TARGET_AU_T *cur, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MMSG("AMAP: Skip_clusters (%d skipped => %d, among %d free clus)\n",\
|
MMSG("AMAP: Skip_clusters (%d skipped => %d, among %d free clus)\n",
|
||||||
num_to_skip_orig, cur->idx, cur->au->free_clusters);
|
num_to_skip_orig, cur->idx, cur->au->free_clusters);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1005,7 +990,8 @@ s32 amap_fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_cha
|
||||||
|
|
||||||
if ((fsi->used_clusters + num_alloc) > (fsi->num_clusters - CLUS_BASE)) {
|
if ((fsi->used_clusters + num_alloc) > (fsi->num_clusters - CLUS_BASE)) {
|
||||||
/* Reserved count management error
|
/* Reserved count management error
|
||||||
or called by dir. management function on fully filled disk */
|
* or called by dir. management function on fully filled disk
|
||||||
|
*/
|
||||||
num_alloc = fsi->num_clusters - fsi->used_clusters - CLUS_BASE;
|
num_alloc = fsi->num_clusters - fsi->used_clusters - CLUS_BASE;
|
||||||
|
|
||||||
if (unlikely(num_alloc < 0)) {
|
if (unlikely(num_alloc < 0)) {
|
||||||
|
|
@ -1041,12 +1027,10 @@ retry_alloc:
|
||||||
|
|
||||||
target_au = cur->au;
|
target_au = cur->au;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cur->au : target AU info pointer
|
* cur->au : target AU info pointer
|
||||||
* cur->idx : the intra-cluster idx in the AU to start from
|
* cur->idx : the intra-cluster idx in the AU to start from
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BUG_ON(!cur->au);
|
BUG_ON(!cur->au);
|
||||||
BUG_ON(!cur->au->free_clusters);
|
BUG_ON(!cur->au->free_clusters);
|
||||||
BUG_ON(cur->idx >= amap->clusters_per_au);
|
BUG_ON(cur->idx >= amap->clusters_per_au);
|
||||||
|
|
@ -1075,7 +1059,6 @@ retry_alloc:
|
||||||
else
|
else
|
||||||
if (fat_ent_set(sb, last_clu, new_clu))
|
if (fat_ent_set(sb, last_clu, new_clu))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
last_clu = new_clu;
|
last_clu = new_clu;
|
||||||
|
|
||||||
/* Update au info */
|
/* Update au info */
|
||||||
|
|
@ -1090,8 +1073,7 @@ retry_alloc:
|
||||||
/* End of the AU */
|
/* End of the AU */
|
||||||
if ((cur->idx >= amap->clusters_per_au) || !(target_au->free_clusters))
|
if ((cur->idx >= amap->clusters_per_au) || !(target_au->free_clusters))
|
||||||
break;
|
break;
|
||||||
} while(num_allocated_each < num_alloc);
|
} while (num_allocated_each < num_alloc);
|
||||||
|
|
||||||
|
|
||||||
/* Update strategy info */
|
/* Update strategy info */
|
||||||
amap_put_target_au(amap, cur, num_allocated_each);
|
amap_put_target_au(amap, cur, num_allocated_each);
|
||||||
|
|
@ -1118,9 +1100,9 @@ s32 amap_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is called by fat_free_cluster()
|
* This is called by fat_free_cluster()
|
||||||
to update AMAP info.
|
* to update AMAP info.
|
||||||
*/
|
*/
|
||||||
s32 amap_release_cluster(struct super_block *sb, u32 clu)
|
s32 amap_release_cluster(struct super_block *sb, u32 clu)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
|
|
@ -1133,7 +1115,12 @@ s32 amap_release_cluster(struct super_block *sb, u32 clu)
|
||||||
i_au = i_AU_of_CLU(amap, clu);
|
i_au = i_AU_of_CLU(amap, clu);
|
||||||
BUG_ON(i_au >= amap->n_au);
|
BUG_ON(i_au >= amap->n_au);
|
||||||
au = GET_AU(amap, i_au);
|
au = GET_AU(amap, i_au);
|
||||||
BUG_ON(au->free_clusters >= amap->clusters_per_au);
|
if (au->free_clusters >= amap->clusters_per_au) {
|
||||||
|
sdfat_fs_error(sb, "%s, au->free_clusters(%hd) is "
|
||||||
|
"greater than or equal to amap->clusters_per_au(%hd)"
|
||||||
|
, __func__, au->free_clusters, amap->clusters_per_au);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_AU_HOT(au, amap)) {
|
if (IS_AU_HOT(au, amap)) {
|
||||||
MMSG("AMAP: Hot cluster freed\n");
|
MMSG("AMAP: Hot cluster freed\n");
|
||||||
|
|
@ -1141,7 +1128,7 @@ s32 amap_release_cluster(struct super_block *sb, u32 clu)
|
||||||
amap->total_fclu_hot++;
|
amap->total_fclu_hot++;
|
||||||
} else if (!IS_AU_WORKING(au, amap) && !IS_AU_IGNORED(au, amap)) {
|
} else if (!IS_AU_WORKING(au, amap) && !IS_AU_IGNORED(au, amap)) {
|
||||||
/* Ordinary AU - update AU tree */
|
/* Ordinary AU - update AU tree */
|
||||||
// Can be optimized by implmenting amap_update_au
|
// Can be optimized by implementing amap_update_au
|
||||||
amap_remove_cold_au(amap, au);
|
amap_remove_cold_au(amap, au);
|
||||||
au->free_clusters++;
|
au->free_clusters++;
|
||||||
amap_add_cold_au(amap, au);
|
amap_add_cold_au(amap, au);
|
||||||
|
|
@ -1161,57 +1148,51 @@ s32 amap_release_cluster(struct super_block *sb, u32 clu)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if the cluster is in a working AU
|
* Check if the cluster is in a working AU
|
||||||
The caller should hold sb lock.
|
* The caller should hold sb lock.
|
||||||
This func. should be used only if smart allocation is on
|
* This func. should be used only if smart allocation is on
|
||||||
*/
|
*/
|
||||||
s32 amap_check_working(struct super_block *sb, u32 clu)
|
s32 amap_check_working(struct super_block *sb, u32 clu)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
AU_INFO_T *au;
|
AU_INFO_T *au;
|
||||||
|
|
||||||
BUG_ON(!amap);
|
BUG_ON(!amap);
|
||||||
|
|
||||||
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
||||||
|
return IS_AU_WORKING(au, amap);
|
||||||
return (IS_AU_WORKING(au, amap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return the # of free clusters in that AU
|
* Return the # of free clusters in that AU
|
||||||
*/
|
*/
|
||||||
s32 amap_get_freeclus(struct super_block *sb, u32 clu)
|
s32 amap_get_freeclus(struct super_block *sb, u32 clu)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
AU_INFO_T *au;
|
AU_INFO_T *au;
|
||||||
|
|
||||||
BUG_ON(!amap);
|
BUG_ON(!amap);
|
||||||
|
|
||||||
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
||||||
|
return (s32)au->free_clusters;
|
||||||
return ((s32)au->free_clusters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add the AU containing 'clu' to the ignored AU list.
|
* Add the AU containing 'clu' to the ignored AU list.
|
||||||
The AU will not be used by the allocator.
|
* The AU will not be used by the allocator.
|
||||||
|
*
|
||||||
XXX: Ignored counter needed
|
* XXX: Ignored counter needed
|
||||||
*/
|
*/
|
||||||
s32 amap_mark_ignore(struct super_block *sb, u32 clu)
|
s32 amap_mark_ignore(struct super_block *sb, u32 clu)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
AU_INFO_T *au;
|
AU_INFO_T *au;
|
||||||
|
|
||||||
BUG_ON(!amap);
|
BUG_ON(!amap);
|
||||||
|
|
||||||
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
au = GET_AU(amap, i_AU_of_CLU(amap, clu));
|
||||||
|
|
||||||
|
|
||||||
if (IS_AU_HOT(au, amap)) {
|
if (IS_AU_HOT(au, amap)) {
|
||||||
// Doesn't work with hot AUs
|
/* Doesn't work with hot AUs */
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
} else if (IS_AU_WORKING(au, amap)) {
|
} else if (IS_AU_WORKING(au, amap)) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
@ -1227,17 +1208,15 @@ s32 amap_mark_ignore(struct super_block *sb, u32 clu)
|
||||||
BUG_ON(!IS_AU_IGNORED(au, amap));
|
BUG_ON(!IS_AU_IGNORED(au, amap));
|
||||||
|
|
||||||
//INC_IGN_CNT(au);
|
//INC_IGN_CNT(au);
|
||||||
|
|
||||||
MMSG("AMAP: Mark ignored AU (%d)\n", au->idx);
|
MMSG("AMAP: Mark ignored AU (%d)\n", au->idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This function could be used only on IGNORED AUs.
|
* This function could be used only on IGNORED AUs.
|
||||||
The caller should care whether it's ignored or not before using this func.
|
* The caller should care whether it's ignored or not before using this func.
|
||||||
*/
|
*/
|
||||||
s32 amap_unmark_ignore(struct super_block *sb, u32 clu)
|
s32 amap_unmark_ignore(struct super_block *sb, u32 clu)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
|
|
@ -1263,9 +1242,9 @@ s32 amap_unmark_ignore(struct super_block *sb, u32 clu)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmark all ignored AU
|
* Unmark all ignored AU
|
||||||
This will return # of unmarked AUs
|
* This will return # of unmarked AUs
|
||||||
*/
|
*/
|
||||||
s32 amap_unmark_ignore_all(struct super_block *sb)
|
s32 amap_unmark_ignore_all(struct super_block *sb)
|
||||||
{
|
{
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
|
|
@ -1274,7 +1253,6 @@ s32 amap_unmark_ignore_all(struct super_block *sb)
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
BUG_ON(!amap);
|
BUG_ON(!amap);
|
||||||
|
|
||||||
entry = amap->slist_ignored.next;
|
entry = amap->slist_ignored.next;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
au = list_entry(entry, AU_INFO_T, shead);
|
au = list_entry(entry, AU_INFO_T, shead);
|
||||||
|
|
@ -1283,7 +1261,6 @@ s32 amap_unmark_ignore_all(struct super_block *sb)
|
||||||
BUG_ON(!IS_AU_IGNORED(au, amap));
|
BUG_ON(!IS_AU_IGNORED(au, amap));
|
||||||
|
|
||||||
//CLEAR_IGN_CNT(au);
|
//CLEAR_IGN_CNT(au);
|
||||||
|
|
||||||
amap_remove_from_list(au, &amap->slist_ignored);
|
amap_remove_from_list(au, &amap->slist_ignored);
|
||||||
amap_add_cold_au(amap, au);
|
amap_add_cold_au(amap, au);
|
||||||
|
|
||||||
|
|
|
||||||
72
amap_smart.h
72
amap_smart.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_AMAP_H
|
#ifndef _SDFAT_AMAP_H
|
||||||
|
|
@ -25,16 +23,19 @@
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
|
|
||||||
/* AMAP Configuration Variable */
|
/* AMAP Configuration Variable */
|
||||||
#define SMART_ALLOC_N_HOT_AU 5
|
#define SMART_ALLOC_N_HOT_AU (5)
|
||||||
|
|
||||||
|
/* Allocating Destination (for smart allocator):
|
||||||
/* Allocating Destination (for smart allocator) */
|
* moved to sdfat.h
|
||||||
#define ALLOC_COLD_ALIGNED 1
|
*/
|
||||||
#define ALLOC_COLD_PACKING 2
|
/*
|
||||||
#define ALLOC_COLD_SEQ 4
|
* #define ALLOC_COLD_ALIGNED (1)
|
||||||
|
* #define ALLOC_COLD_PACKING (2)
|
||||||
|
* #define ALLOC_COLD_SEQ (4)
|
||||||
|
*/
|
||||||
|
|
||||||
/* Minimum sectors for support AMAP create */
|
/* Minimum sectors for support AMAP create */
|
||||||
#define AMAP_MIN_SUPPORT_SECTORS 1048576
|
#define AMAP_MIN_SUPPORT_SECTORS (1048576)
|
||||||
|
|
||||||
#define amap_add_hot_au(amap, au) amap_insert_to_list(au, &amap->slist_hot)
|
#define amap_add_hot_au(amap, au) amap_insert_to_list(au, &amap->slist_hot)
|
||||||
|
|
||||||
|
|
@ -45,20 +46,20 @@ struct slist_head {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* AU entry type */
|
/* AU entry type */
|
||||||
typedef struct __AU_INFO_T{
|
typedef struct __AU_INFO_T {
|
||||||
uint16_t idx; /* the index of the AU (0, 1, 2, ... ) */
|
uint16_t idx; /* the index of the AU (0, 1, 2, ... ) */
|
||||||
uint16_t free_clusters; /* # of available cluster */
|
uint16_t free_clusters; /* # of available cluster */
|
||||||
union {
|
union {
|
||||||
struct list_head head;
|
struct list_head head;
|
||||||
struct slist_head shead; /* singly linked list head for hot list */
|
struct slist_head shead;/* singly linked list head for hot list */
|
||||||
};
|
};
|
||||||
} AU_INFO_T;
|
} AU_INFO_T;
|
||||||
|
|
||||||
|
|
||||||
/* Allocation Target AU */
|
/* Allocation Target AU */
|
||||||
typedef struct __TARGET_AU_T{
|
typedef struct __TARGET_AU_T {
|
||||||
AU_INFO_T *au; /* Working AU */
|
AU_INFO_T *au; /* Working AU */
|
||||||
uint16_t idx; /* Intra-AU cluster index */
|
uint16_t idx; /* Intra-AU cluster index */
|
||||||
uint16_t clu_to_skip; /* Clusters to skip */
|
uint16_t clu_to_skip; /* Clusters to skip */
|
||||||
} TARGET_AU_T;
|
} TARGET_AU_T;
|
||||||
|
|
||||||
|
|
@ -71,29 +72,29 @@ typedef struct {
|
||||||
|
|
||||||
/* AMAP options */
|
/* AMAP options */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int packing_ratio; /* Tunable packing ratio */
|
unsigned int packing_ratio; /* Tunable packing ratio */
|
||||||
unsigned int au_size; /* AU size in sectors */
|
unsigned int au_size; /* AU size in sectors */
|
||||||
unsigned int au_align_factor; /* Hidden sectors % au_size */
|
unsigned int au_align_factor; /* Hidden sectors % au_size */
|
||||||
} AMAP_OPT_T;
|
} AMAP_OPT_T;
|
||||||
|
|
||||||
typedef struct __AMAP_T{
|
typedef struct __AMAP_T {
|
||||||
spinlock_t amap_lock; // obsolete
|
spinlock_t amap_lock; /* obsolete */
|
||||||
struct super_block *sb;
|
struct super_block *sb;
|
||||||
|
|
||||||
int n_au;
|
int n_au;
|
||||||
int n_clean_au, n_full_au;
|
int n_clean_au, n_full_au;
|
||||||
int clu_align_bias;
|
int clu_align_bias;
|
||||||
uint16_t clusters_per_au;
|
uint16_t clusters_per_au;
|
||||||
AU_INFO_T **au_table; /* An array of AU_INFO entries */
|
AU_INFO_T **au_table; /* An array of AU_INFO entries */
|
||||||
AMAP_OPT_T option;
|
AMAP_OPT_T option;
|
||||||
|
|
||||||
/* Size-based AU management pool (cold) */
|
/* Size-based AU management pool (cold) */
|
||||||
FCLU_NODE_T *fclu_nodes; /* An array of listheads */
|
FCLU_NODE_T *fclu_nodes; /* An array of listheads */
|
||||||
int fclu_order; /* Page order that fclu_nodes needs */
|
int fclu_order; /* Page order that fclu_nodes needs */
|
||||||
int fclu_hint; /* maximum # of free clusters in an AU */
|
int fclu_hint; /* maximum # of free clusters in an AU */
|
||||||
|
|
||||||
/* Hot AU list */
|
/* Hot AU list */
|
||||||
int total_fclu_hot; /* Free clusters in hot list */
|
int total_fclu_hot; /* Free clusters in hot list */
|
||||||
struct slist_head slist_hot; /* Hot AU list */
|
struct slist_head slist_hot; /* Hot AU list */
|
||||||
|
|
||||||
/* Ignored AU list */
|
/* Ignored AU list */
|
||||||
|
|
@ -113,20 +114,21 @@ typedef struct __AMAP_T{
|
||||||
#define MAX_CLU_PER_AU (1024)
|
#define MAX_CLU_PER_AU (1024)
|
||||||
|
|
||||||
/* Cold AU bucket <-> # of freeclusters */
|
/* Cold AU bucket <-> # of freeclusters */
|
||||||
#define NODE_CLEAN(amap) &amap->fclu_nodes[amap->clusters_per_au - 1]
|
#define NODE_CLEAN(amap) (&amap->fclu_nodes[amap->clusters_per_au - 1])
|
||||||
#define NODE(fclu, amap) &amap->fclu_nodes[fclu - 1]
|
#define NODE(fclu, amap) (&amap->fclu_nodes[fclu - 1])
|
||||||
#define FREE_CLUSTERS(node, amap) ((int)(node - amap->fclu_nodes) + 1)
|
#define FREE_CLUSTERS(node, amap) ((int)(node - amap->fclu_nodes) + 1)
|
||||||
|
|
||||||
/* AU status */
|
/* AU status */
|
||||||
#define MAGIC_WORKING (struct slist_head*)0xFFFF5091
|
#define MAGIC_WORKING ((struct slist_head *)0xFFFF5091)
|
||||||
#define IS_AU_HOT(au, amap) (au->shead.head == &amap->slist_hot)
|
#define IS_AU_HOT(au, amap) (au->shead.head == &amap->slist_hot)
|
||||||
#define IS_AU_IGNORED(au, amap) (au->shead.head == &amap->slist_ignored)
|
#define IS_AU_IGNORED(au, amap) (au->shead.head == &amap->slist_ignored)
|
||||||
#define IS_AU_WORKING(au, amap) (au->shead.head == MAGIC_WORKING)
|
#define IS_AU_WORKING(au, amap) (au->shead.head == MAGIC_WORKING)
|
||||||
#define SET_AU_WORKING(au) (au->shead.head = MAGIC_WORKING)
|
#define SET_AU_WORKING(au) (au->shead.head = MAGIC_WORKING)
|
||||||
|
|
||||||
/* AU <-> cluster */
|
/* AU <-> cluster */
|
||||||
#define i_AU_of_CLU(amap, clu) ((amap->clu_align_bias + clu) / amap->clusters_per_au)
|
#define i_AU_of_CLU(amap, clu) ((amap->clu_align_bias + clu) / amap->clusters_per_au)
|
||||||
#define CLU_of_i_AU(amap, i_au, idx) ((uint32_t)(i_au) * (uint32_t)amap->clusters_per_au + (idx) - amap->clu_align_bias)
|
#define CLU_of_i_AU(amap, i_au, idx) \
|
||||||
|
((uint32_t)(i_au) * (uint32_t)amap->clusters_per_au + (idx) - amap->clu_align_bias)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE : AMAP internal functions are moved to core.h
|
* NOTE : AMAP internal functions are moved to core.h
|
||||||
|
|
|
||||||
34
api.c
34
api.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -136,6 +134,7 @@ s32 fsapi_statfs(struct super_block *sb, VOL_INFO_T *info)
|
||||||
|
|
||||||
if (fsi->used_clusters == (u32) ~0) {
|
if (fsi->used_clusters == (u32) ~0) {
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
err = fscore_statfs(sb, info);
|
err = fscore_statfs(sb, info);
|
||||||
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -156,6 +155,7 @@ EXPORT_SYMBOL(fsapi_statfs);
|
||||||
s32 fsapi_sync_fs(struct super_block *sb, s32 do_sync)
|
s32 fsapi_sync_fs(struct super_block *sb, s32 do_sync)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
err = fscore_sync_fs(sb, do_sync);
|
err = fscore_sync_fs(sb, do_sync);
|
||||||
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -166,6 +166,7 @@ EXPORT_SYMBOL(fsapi_sync_fs);
|
||||||
s32 fsapi_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync)
|
s32 fsapi_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
err = fscore_set_vol_flags(sb, new_flag, always_sync);
|
err = fscore_set_vol_flags(sb, new_flag, always_sync);
|
||||||
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -263,7 +264,8 @@ s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
EXPORT_SYMBOL(fsapi_truncate);
|
EXPORT_SYMBOL(fsapi_truncate);
|
||||||
|
|
||||||
/* rename or move a old file into a new file */
|
/* rename or move a old file into a new file */
|
||||||
s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry)
|
s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid,
|
||||||
|
struct inode *new_parent_inode, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
struct super_block *sb = old_parent_inode->i_sb;
|
struct super_block *sb = old_parent_inode->i_sb;
|
||||||
|
|
@ -415,7 +417,8 @@ s32 fsapi_rmdir(struct inode *inode, FILE_ID_T *fid)
|
||||||
EXPORT_SYMBOL(fsapi_rmdir);
|
EXPORT_SYMBOL(fsapi_rmdir);
|
||||||
|
|
||||||
/* unlink a file.
|
/* unlink a file.
|
||||||
* that is, remove an entry from a directory. BUT don't truncate */
|
* that is, remove an entry from a directory. BUT don't truncate
|
||||||
|
*/
|
||||||
s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid)
|
s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
@ -441,7 +444,6 @@ s32 fsapi_cache_flush(struct super_block *sb, int do_sync)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_cache_flush);
|
EXPORT_SYMBOL(fsapi_cache_flush);
|
||||||
|
|
||||||
|
|
||||||
/* release FAT & buf cache */
|
/* release FAT & buf cache */
|
||||||
s32 fsapi_cache_release(struct super_block *sb)
|
s32 fsapi_cache_release(struct super_block *sb)
|
||||||
{
|
{
|
||||||
|
|
@ -457,7 +459,6 @@ s32 fsapi_cache_release(struct super_block *sb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_cache_release);
|
EXPORT_SYMBOL(fsapi_cache_release);
|
||||||
|
|
||||||
|
|
||||||
u32 fsapi_get_au_stat(struct super_block *sb, s32 mode)
|
u32 fsapi_get_au_stat(struct super_block *sb, s32 mode)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
@ -490,7 +491,6 @@ s32 fsapi_dfr_get_info(struct super_block *sb, void *arg)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_get_info);
|
EXPORT_SYMBOL(fsapi_dfr_get_info);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args)
|
s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
@ -505,23 +505,23 @@ s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_scan_dir);
|
EXPORT_SYMBOL(fsapi_dfr_scan_dir);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev)
|
s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
|
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
err = defrag_validate_cluster(inode,
|
err = defrag_validate_cluster(inode,
|
||||||
(struct defrag_chunk_info *)chunk, skip_prev);
|
(struct defrag_chunk_info *)chunk, skip_prev);
|
||||||
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
return(err);
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_validate_clus);
|
EXPORT_SYMBOL(fsapi_dfr_validate_clus);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus)
|
s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
err = defrag_reserve_clusters(sb, nr_clus);
|
err = defrag_reserve_clusters(sb, nr_clus);
|
||||||
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_unlock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -529,7 +529,6 @@ s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_reserve_clus);
|
EXPORT_SYMBOL(fsapi_dfr_reserve_clus);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus)
|
s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
@ -537,7 +536,6 @@ s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_mark_ignore);
|
EXPORT_SYMBOL(fsapi_dfr_mark_ignore);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_unmark_ignore_all(struct super_block *sb)
|
void fsapi_dfr_unmark_ignore_all(struct super_block *sb)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
@ -545,7 +543,6 @@ void fsapi_dfr_unmark_ignore_all(struct super_block *sb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_unmark_ignore_all);
|
EXPORT_SYMBOL(fsapi_dfr_unmark_ignore_all);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu)
|
s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu)
|
||||||
{
|
{
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
@ -562,7 +559,6 @@ s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_map_clus);
|
EXPORT_SYMBOL(fsapi_dfr_map_clus);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_writepage_endio(struct page *page)
|
void fsapi_dfr_writepage_endio(struct page *page)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
@ -570,7 +566,6 @@ void fsapi_dfr_writepage_endio(struct page *page)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_writepage_endio);
|
EXPORT_SYMBOL(fsapi_dfr_writepage_endio);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_update_fat_prev(struct super_block *sb, int force)
|
void fsapi_dfr_update_fat_prev(struct super_block *sb, int force)
|
||||||
{
|
{
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -579,7 +574,6 @@ void fsapi_dfr_update_fat_prev(struct super_block *sb, int force)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_update_fat_prev);
|
EXPORT_SYMBOL(fsapi_dfr_update_fat_prev);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_update_fat_next(struct super_block *sb)
|
void fsapi_dfr_update_fat_next(struct super_block *sb)
|
||||||
{
|
{
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -588,7 +582,6 @@ void fsapi_dfr_update_fat_next(struct super_block *sb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_update_fat_next);
|
EXPORT_SYMBOL(fsapi_dfr_update_fat_next);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_check_discard(struct super_block *sb)
|
void fsapi_dfr_check_discard(struct super_block *sb)
|
||||||
{
|
{
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -597,7 +590,6 @@ void fsapi_dfr_check_discard(struct super_block *sb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_check_discard);
|
EXPORT_SYMBOL(fsapi_dfr_check_discard);
|
||||||
|
|
||||||
|
|
||||||
void fsapi_dfr_free_clus(struct super_block *sb, u32 clus)
|
void fsapi_dfr_free_clus(struct super_block *sb, u32 clus)
|
||||||
{
|
{
|
||||||
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
mutex_lock(&(SDFAT_SB(sb)->s_vlock));
|
||||||
|
|
@ -606,7 +598,6 @@ void fsapi_dfr_free_clus(struct super_block *sb, u32 clus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_free_clus);
|
EXPORT_SYMBOL(fsapi_dfr_free_clus);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau)
|
s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
@ -614,7 +605,6 @@ s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *clea
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fsapi_dfr_check_dfr_required);
|
EXPORT_SYMBOL(fsapi_dfr_check_dfr_required);
|
||||||
|
|
||||||
|
|
||||||
s32 fsapi_dfr_check_dfr_on(struct inode *inode, loff_t start, loff_t end, s32 cancel, const char *caller)
|
s32 fsapi_dfr_check_dfr_on(struct inode *inode, loff_t start, loff_t end, s32 cancel, const char *caller)
|
||||||
{
|
{
|
||||||
/* volume lock is not required */
|
/* volume lock is not required */
|
||||||
|
|
|
||||||
63
api.h
63
api.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_API_H
|
#ifndef _SDFAT_API_H
|
||||||
|
|
@ -83,13 +81,13 @@ extern "C" {
|
||||||
/* NLS Type Definitions */
|
/* NLS Type Definitions */
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* DOS name stucture */
|
/* DOS name structure */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 name[DOS_NAME_LENGTH];
|
u8 name[DOS_NAME_LENGTH];
|
||||||
u8 name_case;
|
u8 name_case;
|
||||||
} DOS_NAME_T;
|
} DOS_NAME_T;
|
||||||
|
|
||||||
/* unicode name stucture */
|
/* unicode name structure */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u16 name[MAX_NAME_LENGTH+3]; /* +3 for null and for converting */
|
u16 name[MAX_NAME_LENGTH+3]; /* +3 for null and for converting */
|
||||||
u16 name_hash;
|
u16 name_hash;
|
||||||
|
|
@ -187,8 +185,8 @@ typedef struct {
|
||||||
} FILE_ID_T;
|
} FILE_ID_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
s8* lfn;
|
s8 *lfn;
|
||||||
s8* sfn;
|
s8 *sfn;
|
||||||
s32 lfnbuf_len; //usally MAX_UNINAME_BUF_SIZE
|
s32 lfnbuf_len; //usally MAX_UNINAME_BUF_SIZE
|
||||||
s32 sfnbuf_len; //usally MAX_DOSNAME_BUF_SIZE, used only for vfat, not for exfat
|
s32 sfnbuf_len; //usally MAX_DOSNAME_BUF_SIZE, used only for vfat, not for exfat
|
||||||
} DENTRY_NAMEBUF_T;
|
} DENTRY_NAMEBUF_T;
|
||||||
|
|
@ -225,32 +223,32 @@ typedef struct __FATENT_OPS_T {
|
||||||
} FATENT_OPS_T;
|
} FATENT_OPS_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain, int dest);
|
s32 (*alloc_cluster)(struct super_block *, s32, CHAIN_T *, int);
|
||||||
s32 (*free_cluster)(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse);
|
s32 (*free_cluster)(struct super_block *, CHAIN_T *, s32);
|
||||||
s32 (*count_used_clusters)(struct super_block *sb, u32* ret_count);
|
s32 (*count_used_clusters)(struct super_block *, u32 *);
|
||||||
s32 (*init_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type,u32 start_clu, u64 size);
|
s32 (*init_dir_entry)(struct super_block *, CHAIN_T *, s32, u32, u32, u64);
|
||||||
s32 (*init_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname);
|
s32 (*init_ext_entry)(struct super_block *, CHAIN_T *, s32, s32, UNI_NAME_T *, DOS_NAME_T *);
|
||||||
s32 (*find_dir_entry)(struct super_block *sb, FILE_ID_T *fid, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type);
|
s32 (*find_dir_entry)(struct super_block *, FILE_ID_T *, CHAIN_T *, UNI_NAME_T *, s32, DOS_NAME_T *, u32);
|
||||||
s32 (*delete_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 offset, s32 num_entries);
|
s32 (*delete_dir_entry)(struct super_block *, CHAIN_T *, s32, s32, s32);
|
||||||
void (*get_uniname_from_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname);
|
void (*get_uniname_from_ext_entry)(struct super_block *, CHAIN_T *, s32, u16 *);
|
||||||
s32 (*count_ext_entries)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry);
|
s32 (*count_ext_entries)(struct super_block *, CHAIN_T *, s32, DENTRY_T *);
|
||||||
s32 (*calc_num_entries)(UNI_NAME_T *p_uniname);
|
s32 (*calc_num_entries)(UNI_NAME_T *);
|
||||||
u32 (*get_entry_type)(DENTRY_T *p_entry);
|
s32 (*check_max_dentries)(FILE_ID_T *);
|
||||||
void (*set_entry_type)(DENTRY_T *p_entry, u32 type);
|
u32 (*get_entry_type)(DENTRY_T *);
|
||||||
u32 (*get_entry_attr)(DENTRY_T *p_entry);
|
void (*set_entry_type)(DENTRY_T *, u32);
|
||||||
void (*set_entry_attr)(DENTRY_T *p_entry, u32 attr);
|
u32 (*get_entry_attr)(DENTRY_T *);
|
||||||
u8 (*get_entry_flag)(DENTRY_T *p_entry);
|
void (*set_entry_attr)(DENTRY_T *, u32);
|
||||||
void (*set_entry_flag)(DENTRY_T *p_entry, u8 flag);
|
u8 (*get_entry_flag)(DENTRY_T *);
|
||||||
u32 (*get_entry_clu0)(DENTRY_T *p_entry);
|
void (*set_entry_flag)(DENTRY_T *, u8);
|
||||||
void (*set_entry_clu0)(DENTRY_T *p_entry, u32 clu0);
|
u32 (*get_entry_clu0)(DENTRY_T *);
|
||||||
u64 (*get_entry_size)(DENTRY_T *p_entry);
|
void (*set_entry_clu0)(DENTRY_T *, u32);
|
||||||
void (*set_entry_size)(DENTRY_T *p_entry, u64 size);
|
u64 (*get_entry_size)(DENTRY_T *);
|
||||||
void (*get_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode);
|
void (*set_entry_size)(DENTRY_T *, u64);
|
||||||
void (*set_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode);
|
void (*get_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8);
|
||||||
u32 (*get_au_stat)(struct super_block *sb, s32 mode);
|
void (*set_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8);
|
||||||
|
u32 (*get_au_stat)(struct super_block *, s32);
|
||||||
} FS_FUNC_T;
|
} FS_FUNC_T;
|
||||||
|
|
||||||
|
|
||||||
typedef struct __FS_INFO_T {
|
typedef struct __FS_INFO_T {
|
||||||
s32 bd_opened; // opened or not
|
s32 bd_opened; // opened or not
|
||||||
u32 vol_type; // volume FAT type
|
u32 vol_type; // volume FAT type
|
||||||
|
|
@ -334,7 +332,8 @@ s32 fsapi_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count
|
||||||
s32 fsapi_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount);
|
s32 fsapi_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount);
|
||||||
s32 fsapi_remove(struct inode *inode, FILE_ID_T *fid); /* unlink and truncate */
|
s32 fsapi_remove(struct inode *inode, FILE_ID_T *fid); /* unlink and truncate */
|
||||||
s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size);
|
s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size);
|
||||||
s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry);
|
s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid,
|
||||||
|
struct inode *new_parent_inode, struct dentry *new_dentry);
|
||||||
s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid);
|
s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid);
|
||||||
s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info);
|
s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info);
|
||||||
s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync);
|
s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync);
|
||||||
|
|
|
||||||
77
blkdev.c
77
blkdev.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -50,14 +48,14 @@
|
||||||
/* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY */
|
/* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
|
||||||
/* EMPTY */
|
/* EMPTY */
|
||||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) */
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) */
|
||||||
static struct backing_dev_info *inode_to_bdi(struct inode *bd_inode)
|
static struct backing_dev_info *inode_to_bdi(struct inode *bd_inode)
|
||||||
{
|
{
|
||||||
return bd_inode->i_mapping->backing_dev_info;
|
return bd_inode->i_mapping->backing_dev_info;
|
||||||
}
|
}
|
||||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) */
|
#endif
|
||||||
|
|
||||||
/*======================================================================*/
|
/*======================================================================*/
|
||||||
/* Function Definitions */
|
/* Function Definitions */
|
||||||
|
|
@ -86,12 +84,13 @@ static inline s32 block_device_ejected(struct super_block *sb)
|
||||||
struct inode *bd_inode = sb->s_bdev->bd_inode;
|
struct inode *bd_inode = sb->s_bdev->bd_inode;
|
||||||
struct backing_dev_info *bdi = inode_to_bdi(bd_inode);
|
struct backing_dev_info *bdi = inode_to_bdi(bd_inode);
|
||||||
|
|
||||||
return bdi->dev == NULL;
|
return (bdi->dev == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 bdev_check_bdi_valid(struct super_block *sb)
|
s32 bdev_check_bdi_valid(struct super_block *sb)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
if (block_device_ejected(sb)) {
|
if (block_device_ejected(sb)) {
|
||||||
if (!(fsi->prev_eio & SDFAT_EIO_BDI)) {
|
if (!(fsi->prev_eio & SDFAT_EIO_BDI)) {
|
||||||
fsi->prev_eio |= SDFAT_EIO_BDI;
|
fsi->prev_eio |= SDFAT_EIO_BDI;
|
||||||
|
|
@ -101,6 +100,7 @@ s32 bdev_check_bdi_valid(struct super_block *sb)
|
||||||
}
|
}
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,14 +156,13 @@ s32 bdev_mread(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 n
|
||||||
/*
|
/*
|
||||||
* patch 1.2.4 : reset ONCE warning message per volume.
|
* patch 1.2.4 : reset ONCE warning message per volume.
|
||||||
*/
|
*/
|
||||||
if(!(fsi->prev_eio & SDFAT_EIO_READ)) {
|
if (!(fsi->prev_eio & SDFAT_EIO_READ)) {
|
||||||
fsi->prev_eio |= SDFAT_EIO_READ;
|
fsi->prev_eio |= SDFAT_EIO_READ;
|
||||||
sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
|
sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
|
||||||
sdfat_debug_warn_on(1);
|
sdfat_debug_warn_on(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync)
|
s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync)
|
||||||
|
|
@ -206,14 +205,12 @@ s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 n
|
||||||
}
|
}
|
||||||
__brelse(bh2);
|
__brelse(bh2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
no_bh:
|
no_bh:
|
||||||
/*
|
/*
|
||||||
* patch 1.2.4 : reset ONCE warning message per volume.
|
* patch 1.2.4 : reset ONCE warning message per volume.
|
||||||
*/
|
*/
|
||||||
if(!(fsi->prev_eio & SDFAT_EIO_WRITE)) {
|
if (!(fsi->prev_eio & SDFAT_EIO_WRITE)) {
|
||||||
fsi->prev_eio |= SDFAT_EIO_WRITE;
|
fsi->prev_eio |= SDFAT_EIO_WRITE;
|
||||||
sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
|
sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
|
||||||
sdfat_debug_warn_on(1);
|
sdfat_debug_warn_on(1);
|
||||||
|
|
@ -245,85 +242,83 @@ s32 bdev_sync_all(struct super_block *sb)
|
||||||
s32 read_sect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 read)
|
s32 read_sect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 read)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
BUG_ON(!bh);
|
|
||||||
|
|
||||||
if ( (sec >= fsi->num_sectors)
|
BUG_ON(!bh);
|
||||||
&& (fsi->num_sectors > 0) ) {
|
if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: out of range (sect:%u)",
|
sdfat_fs_error_ratelimit(sb,
|
||||||
__func__, sec);
|
"%s: out of range (sect:%u)", __func__, sec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdev_mread(sb, sec, bh, 1, read)) {
|
if (bdev_mread(sb, sec, bh, 1, read)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)",
|
sdfat_fs_error_ratelimit(sb,
|
||||||
__func__, sec);
|
"%s: I/O error (sect:%u)", __func__, sec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of read_sect */
|
}
|
||||||
|
|
||||||
s32 write_sect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync)
|
s32 write_sect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
BUG_ON(!bh);
|
|
||||||
|
|
||||||
if ( (sec >= fsi->num_sectors)
|
BUG_ON(!bh);
|
||||||
&& (fsi->num_sectors > 0) ) {
|
if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: out of range (sect:%u)",
|
sdfat_fs_error_ratelimit(sb,
|
||||||
__func__, sec);
|
"%s: out of range (sect:%u)", __func__, sec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdev_mwrite(sb, sec, bh, 1, sync)) {
|
if (bdev_mwrite(sb, sec, bh, 1, sync)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)",
|
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)",
|
||||||
__func__, sec);
|
__func__, sec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of write_sect */
|
}
|
||||||
|
|
||||||
s32 read_msect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 num_secs, s32 read)
|
s32 read_msect(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 num_secs, s32 read)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
BUG_ON(!bh);
|
|
||||||
|
|
||||||
if ( ((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0) ) {
|
BUG_ON(!bh);
|
||||||
|
if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
||||||
__func__ ,sec, num_secs);
|
__func__, sec, num_secs);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdev_mread(sb, sec, bh, num_secs, read)) {
|
if (bdev_mread(sb, sec, bh, num_secs, read)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
|
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
|
||||||
__func__,sec, num_secs);
|
__func__, sec, num_secs);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of read_msect */
|
}
|
||||||
|
|
||||||
s32 write_msect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 num_secs, s32 sync)
|
s32 write_msect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 num_secs, s32 sync)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
BUG_ON(!bh);
|
|
||||||
|
|
||||||
if ( ((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0) ) {
|
BUG_ON(!bh);
|
||||||
|
if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
||||||
__func__ ,sec, num_secs);
|
__func__, sec, num_secs);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (bdev_mwrite(sb, sec, bh, num_secs, sync)) {
|
if (bdev_mwrite(sb, sec, bh, num_secs, sync)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
|
sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)",
|
||||||
__func__,sec, num_secs);
|
__func__, sec, num_secs);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of write_msect */
|
}
|
||||||
|
|
||||||
static inline void __blkdev_write_bhs(struct buffer_head **bhs, s32 nr_bhs)
|
static inline void __blkdev_write_bhs(struct buffer_head **bhs, s32 nr_bhs)
|
||||||
{
|
{
|
||||||
|
|
@ -347,8 +342,6 @@ static inline s32 __blkdev_sync_bhs(struct buffer_head **bhs, s32 nr_bhs)
|
||||||
|
|
||||||
static inline s32 __buffer_zeroed(struct super_block *sb, u32 blknr, s32 num_secs)
|
static inline s32 __buffer_zeroed(struct super_block *sb, u32 blknr, s32 num_secs)
|
||||||
{
|
{
|
||||||
#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
|
|
||||||
|
|
||||||
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
||||||
s32 nr_bhs = MAX_BUF_PER_PAGE;
|
s32 nr_bhs = MAX_BUF_PER_PAGE;
|
||||||
u32 last_blknr = blknr + num_secs;
|
u32 last_blknr = blknr + num_secs;
|
||||||
|
|
@ -407,14 +400,14 @@ s32 write_msect_zero(struct super_block *sb, u32 sec, s32 num_secs)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
if ( ((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0) ) {
|
if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
|
||||||
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%u len:%d)",
|
||||||
__func__ ,sec, num_secs);
|
__func__, sec, num_secs);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just return -EAGAIN if it is failed */
|
/* Just return -EAGAIN if it is failed */
|
||||||
if ( __buffer_zeroed(sb, sec, num_secs))
|
if (__buffer_zeroed(sb, sec, num_secs))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
133
cache.c
133
cache.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -48,9 +46,9 @@
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
/* Local Variable Definitions */
|
/* Local Variable Definitions */
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
#define LOCKBIT 0x01
|
#define LOCKBIT (0x01)
|
||||||
#define DIRTYBIT 0x02
|
#define DIRTYBIT (0x02)
|
||||||
#define KEEPBIT 0x04
|
#define KEEPBIT (0x04)
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
/* Cache handling function declarations */
|
/* Cache handling function declarations */
|
||||||
|
|
@ -74,7 +72,7 @@ static void push_to_mru(cache_ent_t *bp, cache_ent_t *list)
|
||||||
bp->prev = list;
|
bp->prev = list;
|
||||||
list->next->prev = bp;
|
list->next->prev = bp;
|
||||||
list->next = bp;
|
list->next = bp;
|
||||||
} /* end of __dcache_push_to_mru */
|
}
|
||||||
|
|
||||||
static void push_to_lru(cache_ent_t *bp, cache_ent_t *list)
|
static void push_to_lru(cache_ent_t *bp, cache_ent_t *list)
|
||||||
{
|
{
|
||||||
|
|
@ -82,31 +80,31 @@ static void push_to_lru(cache_ent_t *bp, cache_ent_t *list)
|
||||||
bp->next = list;
|
bp->next = list;
|
||||||
list->prev->next = bp;
|
list->prev->next = bp;
|
||||||
list->prev = bp;
|
list->prev = bp;
|
||||||
} /* end of __dcache_push_to_lru */
|
}
|
||||||
|
|
||||||
static void move_to_mru(cache_ent_t *bp, cache_ent_t *list)
|
static void move_to_mru(cache_ent_t *bp, cache_ent_t *list)
|
||||||
{
|
{
|
||||||
bp->prev->next = bp->next;
|
bp->prev->next = bp->next;
|
||||||
bp->next->prev = bp->prev;
|
bp->next->prev = bp->prev;
|
||||||
push_to_mru(bp, list);
|
push_to_mru(bp, list);
|
||||||
} /* end of __dcache_move_to_mru */
|
}
|
||||||
|
|
||||||
static void move_to_lru(cache_ent_t *bp, cache_ent_t *list)
|
static void move_to_lru(cache_ent_t *bp, cache_ent_t *list)
|
||||||
{
|
{
|
||||||
bp->prev->next = bp->next;
|
bp->prev->next = bp->next;
|
||||||
bp->next->prev = bp->prev;
|
bp->next->prev = bp->prev;
|
||||||
push_to_lru(bp, list);
|
push_to_lru(bp, list);
|
||||||
} /* end of __dcache_move_to_lru */
|
}
|
||||||
|
|
||||||
static inline s32 __check_hash_valid(cache_ent_t *bp)
|
static inline s32 __check_hash_valid(cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_HASH_LIST
|
#ifdef DEBUG_HASH_LIST
|
||||||
if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) ||
|
if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) ||
|
||||||
(bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) {
|
(bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ( (bp->hash.next == bp) || (bp->hash.prev == bp) )
|
if ((bp->hash.next == bp) || (bp->hash.prev == bp))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -119,15 +117,15 @@ static inline void __remove_from_hash(cache_ent_t *bp)
|
||||||
bp->hash.next = bp;
|
bp->hash.next = bp;
|
||||||
bp->hash.prev = bp;
|
bp->hash.prev = bp;
|
||||||
#ifdef DEBUG_HASH_LIST
|
#ifdef DEBUG_HASH_LIST
|
||||||
bp->hash.next = (cache_ent_t*)DEBUG_HASH_NEXT;
|
bp->hash.next = (cache_ent_t *)DEBUG_HASH_NEXT;
|
||||||
bp->hash.prev = (cache_ent_t*)DEBUG_HASH_PREV;
|
bp->hash.prev = (cache_ent_t *)DEBUG_HASH_PREV;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do FAT mirroring (don't sync)
|
/* Do FAT mirroring (don't sync)
|
||||||
sec: sector No. in FAT1
|
* sec: sector No. in FAT1
|
||||||
bh: bh of sec.
|
* bh: bh of sec.
|
||||||
*/
|
*/
|
||||||
static inline s32 __fat_copy(struct super_block *sb, u32 sec, struct buffer_head *bh, int sync)
|
static inline s32 __fat_copy(struct super_block *sb, u32 sec, struct buffer_head *bh, int sync)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SDFAT_FAT_MIRRORING
|
#ifdef CONFIG_SDFAT_FAT_MIRRORING
|
||||||
|
|
@ -176,11 +174,12 @@ static s32 __fcache_ent_flush(struct super_block *sb, cache_ent_t *bp, u32 sync)
|
||||||
static s32 __fcache_ent_discard(struct super_block *sb, cache_ent_t *bp)
|
static s32 __fcache_ent_discard(struct super_block *sb, cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
__fcache_remove_hash(bp);
|
__fcache_remove_hash(bp);
|
||||||
bp->sec = ~0;
|
bp->sec = ~0;
|
||||||
bp->flag = 0;
|
bp->flag = 0;
|
||||||
|
|
||||||
if(bp->bh) {
|
if (bp->bh) {
|
||||||
__brelse(bp->bh);
|
__brelse(bp->bh);
|
||||||
bp->bh = NULL;
|
bp->bh = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -202,11 +201,10 @@ u8 *fcache_getblk(struct super_block *sb, u32 sec)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
move_to_mru(bp, &fsi->fcache.lru_list);
|
move_to_mru(bp, &fsi->fcache.lru_list);
|
||||||
return(bp->bh->b_data);
|
return bp->bh->b_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bp = __fcache_get(sb, sec);
|
bp = __fcache_get(sb, sec);
|
||||||
|
|
||||||
if (!__check_hash_valid(bp))
|
if (!__check_hash_valid(bp))
|
||||||
__fcache_remove_hash(bp);
|
__fcache_remove_hash(bp);
|
||||||
|
|
||||||
|
|
@ -236,6 +234,7 @@ static inline int __mark_delayed_dirty(struct super_block *sb, cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
if (fsi->vol_type == EXFAT)
|
if (fsi->vol_type == EXFAT)
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
|
@ -253,8 +252,10 @@ s32 fcache_modify(struct super_block *sb, u32 sec)
|
||||||
cache_ent_t *bp;
|
cache_ent_t *bp;
|
||||||
|
|
||||||
bp = __fcache_find(sb, sec);
|
bp = __fcache_find(sb, sec);
|
||||||
if (!bp)
|
if (!bp) {
|
||||||
|
sdfat_fs_error(sb, "Can`t find fcache (sec 0x%08x)", sec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (!__mark_delayed_dirty(sb, bp))
|
if (!__mark_delayed_dirty(sb, bp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -346,6 +347,7 @@ s32 fcache_release_all(struct super_block *sb)
|
||||||
bp = fsi->fcache.lru_list.next;
|
bp = fsi->fcache.lru_list.next;
|
||||||
while (bp != &fsi->fcache.lru_list) {
|
while (bp != &fsi->fcache.lru_list) {
|
||||||
s32 ret_tmp = __fcache_ent_flush(sb, bp, 0);
|
s32 ret_tmp = __fcache_ent_flush(sb, bp, 0);
|
||||||
|
|
||||||
if (ret_tmp < 0)
|
if (ret_tmp < 0)
|
||||||
ret = ret_tmp;
|
ret = ret_tmp;
|
||||||
else
|
else
|
||||||
|
|
@ -354,7 +356,7 @@ s32 fcache_release_all(struct super_block *sb)
|
||||||
bp->sec = ~0;
|
bp->sec = ~0;
|
||||||
bp->flag = 0;
|
bp->flag = 0;
|
||||||
|
|
||||||
if(bp->bh) {
|
if (bp->bh) {
|
||||||
__brelse(bp->bh);
|
__brelse(bp->bh);
|
||||||
bp->bh = NULL;
|
bp->bh = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -395,11 +397,9 @@ static cache_ent_t *__fcache_find(struct super_block *sb, u32 sec)
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
off = (sec + (sec >> fsi->sect_per_clus_bits)) & (FAT_CACHE_HASH_SIZE - 1);
|
off = (sec + (sec >> fsi->sect_per_clus_bits)) & (FAT_CACHE_HASH_SIZE - 1);
|
||||||
|
|
||||||
hp = &(fsi->fcache.hash_list[off]);
|
hp = &(fsi->fcache.hash_list[off]);
|
||||||
for (bp = hp->hash.next; bp != hp; bp = bp->hash.next) {
|
for (bp = hp->hash.next; bp != hp; bp = bp->hash.next) {
|
||||||
if (bp->sec == sec) {
|
if (bp->sec == sec) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* patch 1.2.4 : for debugging
|
* patch 1.2.4 : for debugging
|
||||||
*/
|
*/
|
||||||
|
|
@ -407,11 +407,11 @@ static cache_ent_t *__fcache_find(struct super_block *sb, u32 sec)
|
||||||
"It will make system panic.\n");
|
"It will make system panic.\n");
|
||||||
|
|
||||||
touch_buffer(bp->bh);
|
touch_buffer(bp->bh);
|
||||||
return(bp);
|
return bp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(NULL);
|
return NULL;
|
||||||
} /* end of __fcache_find */
|
}
|
||||||
|
|
||||||
static cache_ent_t *__fcache_get(struct super_block *sb, u32 sec)
|
static cache_ent_t *__fcache_get(struct super_block *sb, u32 sec)
|
||||||
{
|
{
|
||||||
|
|
@ -419,7 +419,6 @@ static cache_ent_t *__fcache_get(struct super_block *sb, u32 sec)
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
bp = fsi->fcache.lru_list.prev;
|
bp = fsi->fcache.lru_list.prev;
|
||||||
|
|
||||||
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
||||||
while (bp->flag & DIRTYBIT) {
|
while (bp->flag & DIRTYBIT) {
|
||||||
cache_ent_t *bp_prev = bp->prev;
|
cache_ent_t *bp_prev = bp->prev;
|
||||||
|
|
@ -436,8 +435,8 @@ static cache_ent_t *__fcache_get(struct super_block *sb, u32 sec)
|
||||||
// sync_dirty_buffer(bp->bh);
|
// sync_dirty_buffer(bp->bh);
|
||||||
|
|
||||||
move_to_mru(bp, &fsi->fcache.lru_list);
|
move_to_mru(bp, &fsi->fcache.lru_list);
|
||||||
return(bp);
|
return bp;
|
||||||
} /* end of __fcache_get */
|
}
|
||||||
|
|
||||||
static void __fcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
static void __fcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
|
|
@ -453,14 +452,14 @@ static void __fcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
||||||
bp->hash.prev = hp;
|
bp->hash.prev = hp;
|
||||||
hp->hash.next->hash.prev = bp;
|
hp->hash.next->hash.prev = bp;
|
||||||
hp->hash.next = bp;
|
hp->hash.next = bp;
|
||||||
} /* end of __fcache_insert_hash */
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __fcache_remove_hash(cache_ent_t *bp)
|
static void __fcache_remove_hash(cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_HASH_LIST
|
#ifdef DEBUG_HASH_LIST
|
||||||
if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) ||
|
if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) ||
|
||||||
(bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) {
|
(bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) {
|
||||||
EMSG("%s: FATAL: tried to remove already-removed-cache-entry"
|
EMSG("%s: FATAL: tried to remove already-removed-cache-entry"
|
||||||
"(bp:%p)\n", __func__, bp);
|
"(bp:%p)\n", __func__, bp);
|
||||||
return;
|
return;
|
||||||
|
|
@ -468,7 +467,7 @@ static void __fcache_remove_hash(cache_ent_t *bp)
|
||||||
#endif
|
#endif
|
||||||
WARN_ON(bp->flag & DIRTYBIT);
|
WARN_ON(bp->flag & DIRTYBIT);
|
||||||
__remove_from_hash(bp);
|
__remove_from_hash(bp);
|
||||||
} /* end of __fcache_remove_hash */
|
}
|
||||||
|
|
||||||
/*======================================================================*/
|
/*======================================================================*/
|
||||||
/* Buffer Read/Write Functions */
|
/* Buffer Read/Write Functions */
|
||||||
|
|
@ -541,7 +540,7 @@ static s32 __dcache_ent_discard(struct super_block *sb, cache_ent_t *bp)
|
||||||
bp->sec = ~0;
|
bp->sec = ~0;
|
||||||
bp->flag = 0;
|
bp->flag = 0;
|
||||||
|
|
||||||
if(bp->bh) {
|
if (bp->bh) {
|
||||||
__brelse(bp->bh);
|
__brelse(bp->bh);
|
||||||
bp->bh = NULL;
|
bp->bh = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -568,7 +567,7 @@ u8 *dcache_getblk(struct super_block *sb, u32 sec)
|
||||||
if (!(bp->flag & KEEPBIT)) // already in keep list
|
if (!(bp->flag & KEEPBIT)) // already in keep list
|
||||||
move_to_mru(bp, &fsi->dcache.lru_list);
|
move_to_mru(bp, &fsi->dcache.lru_list);
|
||||||
|
|
||||||
return(bp->bh->b_data);
|
return bp->bh->b_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bp = __dcache_get(sb, sec);
|
bp = __dcache_get(sb, sec);
|
||||||
|
|
@ -597,20 +596,21 @@ s32 dcache_modify(struct super_block *sb, u32 sec)
|
||||||
set_sb_dirty(sb);
|
set_sb_dirty(sb);
|
||||||
|
|
||||||
bp = __dcache_find(sb, sec);
|
bp = __dcache_find(sb, sec);
|
||||||
if (likely(bp)) {
|
if (unlikely(!bp)) {
|
||||||
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
sdfat_fs_error(sb, "Can`t find dcache (sec 0x%08x)", sec);
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
return -EIO;
|
||||||
if (fsi->vol_type != EXFAT) {
|
|
||||||
bp->flag |= DIRTYBIT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ret = write_sect(sb, sec, bp->bh, 0);
|
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY
|
||||||
|
if (SDFAT_SB(sb)->fsi.vol_type != EXFAT) {
|
||||||
|
bp->flag |= DIRTYBIT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ret = write_sect(sb, sec, bp->bh, 0);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DMSG("%s : failed to modify buffer(err:%d, sec:%u, bp:0x%p)\n",
|
DMSG("%s : failed to modify buffer(err:%d, sec:%u, bp:0x%p)\n",
|
||||||
__func__, ret, sec, bp);
|
__func__, ret, sec, bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -662,7 +662,7 @@ s32 dcache_release(struct super_block *sb, u32 sec)
|
||||||
bp->sec = ~0;
|
bp->sec = ~0;
|
||||||
bp->flag = 0;
|
bp->flag = 0;
|
||||||
|
|
||||||
if(bp->bh) {
|
if (bp->bh) {
|
||||||
__brelse(bp->bh);
|
__brelse(bp->bh);
|
||||||
bp->bh = NULL;
|
bp->bh = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -678,9 +678,10 @@ s32 dcache_release_all(struct super_block *sb)
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
s32 dirtycnt = 0;
|
s32 dirtycnt = 0;
|
||||||
|
|
||||||
/* Connect list elements */
|
/* Connect list elements:
|
||||||
/* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) */
|
* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last)
|
||||||
while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list){
|
*/
|
||||||
|
while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list) {
|
||||||
cache_ent_t *bp_keep = fsi->dcache.keep_list.prev;
|
cache_ent_t *bp_keep = fsi->dcache.keep_list.prev;
|
||||||
// bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later
|
// bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later
|
||||||
move_to_mru(bp_keep, &fsi->dcache.lru_list);
|
move_to_mru(bp_keep, &fsi->dcache.lru_list);
|
||||||
|
|
@ -695,11 +696,10 @@ s32 dcache_release_all(struct super_block *sb)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bp->sec = ~0;
|
bp->sec = ~0;
|
||||||
bp->flag = 0;
|
bp->flag = 0;
|
||||||
|
|
||||||
if(bp->bh) {
|
if (bp->bh) {
|
||||||
__brelse(bp->bh);
|
__brelse(bp->bh);
|
||||||
bp->bh = NULL;
|
bp->bh = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -719,14 +719,14 @@ s32 dcache_flush(struct super_block *sb, u32 sync)
|
||||||
s32 dirtycnt = 0;
|
s32 dirtycnt = 0;
|
||||||
s32 keepcnt = 0;
|
s32 keepcnt = 0;
|
||||||
|
|
||||||
/* Connect list elements */
|
/* Connect list elements:
|
||||||
/* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) */
|
* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last)
|
||||||
// XXX: optimization
|
*/
|
||||||
while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list){
|
while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list) {
|
||||||
cache_ent_t *bp_keep = fsi->dcache.keep_list.prev;
|
cache_ent_t *bp_keep = fsi->dcache.keep_list.prev;
|
||||||
|
|
||||||
bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later
|
bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later
|
||||||
move_to_mru(bp_keep, &fsi->dcache.lru_list);
|
move_to_mru(bp_keep, &fsi->dcache.lru_list);
|
||||||
|
|
||||||
keepcnt++;
|
keepcnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -767,11 +767,11 @@ static cache_ent_t *__dcache_find(struct super_block *sb, u32 sec)
|
||||||
for (bp = hp->hash.next; bp != hp; bp = bp->hash.next) {
|
for (bp = hp->hash.next; bp != hp; bp = bp->hash.next) {
|
||||||
if (bp->sec == sec) {
|
if (bp->sec == sec) {
|
||||||
touch_buffer(bp->bh);
|
touch_buffer(bp->bh);
|
||||||
return(bp);
|
return bp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
} /* end of __dcache_find */
|
}
|
||||||
|
|
||||||
static cache_ent_t *__dcache_get(struct super_block *sb, u32 sec)
|
static cache_ent_t *__dcache_get(struct super_block *sb, u32 sec)
|
||||||
{
|
{
|
||||||
|
|
@ -788,7 +788,6 @@ static cache_ent_t *__dcache_get(struct super_block *sb, u32 sec)
|
||||||
bp->flag |= KEEPBIT;
|
bp->flag |= KEEPBIT;
|
||||||
move_to_mru(bp, &fsi->dcache.keep_list);
|
move_to_mru(bp, &fsi->dcache.keep_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
bp = bp_prev;
|
bp = bp_prev;
|
||||||
|
|
||||||
/* If all dcaches are dirty */
|
/* If all dcaches are dirty */
|
||||||
|
|
@ -806,8 +805,8 @@ static cache_ent_t *__dcache_get(struct super_block *sb, u32 sec)
|
||||||
// sync_dirty_buffer(bp->bh);
|
// sync_dirty_buffer(bp->bh);
|
||||||
|
|
||||||
move_to_mru(bp, &fsi->dcache.lru_list);
|
move_to_mru(bp, &fsi->dcache.lru_list);
|
||||||
return(bp);
|
return bp;
|
||||||
} /* end of __dcache_get */
|
}
|
||||||
|
|
||||||
static void __dcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
static void __dcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
|
|
@ -823,13 +822,13 @@ static void __dcache_insert_hash(struct super_block *sb, cache_ent_t *bp)
|
||||||
bp->hash.prev = hp;
|
bp->hash.prev = hp;
|
||||||
hp->hash.next->hash.prev = bp;
|
hp->hash.next->hash.prev = bp;
|
||||||
hp->hash.next = bp;
|
hp->hash.next = bp;
|
||||||
} /* end of __dcache_insert_hash */
|
}
|
||||||
|
|
||||||
static void __dcache_remove_hash(cache_ent_t *bp)
|
static void __dcache_remove_hash(cache_ent_t *bp)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_HASH_LIST
|
#ifdef DEBUG_HASH_LIST
|
||||||
if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) ||
|
if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) ||
|
||||||
(bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) {
|
(bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) {
|
||||||
EMSG("%s: FATAL: tried to remove already-removed-cache-entry"
|
EMSG("%s: FATAL: tried to remove already-removed-cache-entry"
|
||||||
"(bp:%p)\n", __func__, bp);
|
"(bp:%p)\n", __func__, bp);
|
||||||
return;
|
return;
|
||||||
|
|
@ -837,7 +836,7 @@ static void __dcache_remove_hash(cache_ent_t *bp)
|
||||||
#endif
|
#endif
|
||||||
WARN_ON(bp->flag & DIRTYBIT);
|
WARN_ON(bp->flag & DIRTYBIT);
|
||||||
__remove_from_hash(bp);
|
__remove_from_hash(bp);
|
||||||
} /* end of __dcache_remove_hash */
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end of cache.c */
|
/* end of cache.c */
|
||||||
|
|
|
||||||
6
config.h
6
config.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_CONFIG_H
|
#ifndef _SDFAT_CONFIG_H
|
||||||
|
|
@ -101,7 +99,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SDFAT_VIRTUAL_XATTR
|
#ifndef CONFIG_SDFAT_VIRTUAL_XATTR
|
||||||
#define CONFIG_SDFAT_VIRTUAL_XATTR
|
//#define CONFIG_SDFAT_VIRTUAL_XATTR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SDFAT_SUPPORT_STLOG
|
#ifndef CONFIG_SDFAT_SUPPORT_STLOG
|
||||||
|
|
|
||||||
356
core.c
356
core.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -46,18 +44,19 @@
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
static inline void __set_sb_dirty(struct super_block *sb)
|
static inline void __set_sb_dirty(struct super_block *sb)
|
||||||
{
|
{
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
|
||||||
sb->s_dirt = 1;
|
sb->s_dirt = 1;
|
||||||
#else
|
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */
|
||||||
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
||||||
sbi->s_dirt = 1; // XXX: really needed?
|
|
||||||
|
|
||||||
|
sbi->s_dirt = 1;
|
||||||
/* Insert work */
|
/* Insert work */
|
||||||
spin_lock(&sbi->work_lock);
|
spin_lock(&sbi->work_lock);
|
||||||
if (!sbi->write_super_queued) {
|
if (!sbi->write_super_queued) {
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
|
|
||||||
delay = msecs_to_jiffies(CONFIG_SDFAT_WRITE_SB_INTERVAL_CSECS * 10);
|
delay = msecs_to_jiffies(CONFIG_SDFAT_WRITE_SB_INTERVAL_CSECS * 10);
|
||||||
queue_delayed_work(system_long_wq , &sbi->write_super_work, delay);
|
queue_delayed_work(system_long_wq, &sbi->write_super_work, delay);
|
||||||
sbi->write_super_queued = 1;
|
sbi->write_super_queued = 1;
|
||||||
}
|
}
|
||||||
spin_unlock(&sbi->work_lock);
|
spin_unlock(&sbi->work_lock);
|
||||||
|
|
@ -99,41 +98,32 @@ static s8 *reserved_names[] = {
|
||||||
static s32 check_type_size(void)
|
static s32 check_type_size(void)
|
||||||
{
|
{
|
||||||
/* critical check for system requirement on size of DENTRY_T structure */
|
/* critical check for system requirement on size of DENTRY_T structure */
|
||||||
if (sizeof(DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) {
|
if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +141,8 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s
|
||||||
fsi->vol_flag = new_flag;
|
fsi->vol_flag = new_flag;
|
||||||
|
|
||||||
/* skip updating volume dirty flag,
|
/* skip updating volume dirty flag,
|
||||||
* if this volume has been mounted with read-only */
|
* if this volume has been mounted with read-only
|
||||||
|
*/
|
||||||
if (sb->s_flags & MS_RDONLY)
|
if (sb->s_flags & MS_RDONLY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -164,12 +155,12 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsi->vol_type == EXFAT) {
|
if (fsi->vol_type == EXFAT) {
|
||||||
pbr64_t *bpb = (pbr64_t *) fsi->pbr_bh->b_data;
|
pbr64_t *bpb = (pbr64_t *)fsi->pbr_bh->b_data;
|
||||||
bpb->bsx.vol_flags = cpu_to_le16(new_flag);
|
bpb->bsx.vol_flags = cpu_to_le16(new_flag);
|
||||||
} else if (fsi->vol_type == FAT32) {
|
} else if (fsi->vol_type == FAT32) {
|
||||||
pbr32_t *bpb = (pbr32_t *) fsi->pbr_bh->b_data;
|
pbr32_t *bpb = (pbr32_t *)fsi->pbr_bh->b_data;
|
||||||
bpb->bsx.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00;
|
bpb->bsx.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00;
|
||||||
} else {
|
} else { /* FAT16/12 */
|
||||||
pbr16_t *bpb = (pbr16_t *) fsi->pbr_bh->b_data;
|
pbr16_t *bpb = (pbr16_t *) fsi->pbr_bh->b_data;
|
||||||
bpb->bpb.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00;
|
bpb->bpb.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00;
|
||||||
}
|
}
|
||||||
|
|
@ -280,12 +271,12 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
} /* end of __clear_cluster */
|
} /* end of __clear_cluster */
|
||||||
|
|
||||||
static s32 __find_last_cluster(struct super_block *sb, CHAIN_T *p_chain, u32* ret_clu)
|
static s32 __find_last_cluster(struct super_block *sb, CHAIN_T *p_chain, u32 *ret_clu)
|
||||||
{
|
{
|
||||||
u32 clu, next;
|
u32 clu, next;
|
||||||
s32 count = 0;
|
s32 count = 0;
|
||||||
next = p_chain->dir;
|
|
||||||
|
|
||||||
|
next = p_chain->dir;
|
||||||
if (p_chain->flags == 0x03) {
|
if (p_chain->flags == 0x03) {
|
||||||
*ret_clu = next + p_chain->size - 1;
|
*ret_clu = next + p_chain->size - 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -311,7 +302,7 @@ static s32 __find_last_cluster(struct super_block *sb, CHAIN_T *p_chain, u32* re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static s32 __count_num_clusters(struct super_block *sb, CHAIN_T *p_chain, s32* ret_count)
|
static s32 __count_num_clusters(struct super_block *sb, CHAIN_T *p_chain, s32 *ret_count)
|
||||||
{
|
{
|
||||||
s32 i, count;
|
s32 i, count;
|
||||||
u32 clu;
|
u32 clu;
|
||||||
|
|
@ -351,15 +342,15 @@ static void free_upcase_table(struct super_block *sb)
|
||||||
u16 **upcase_table;
|
u16 **upcase_table;
|
||||||
|
|
||||||
upcase_table = fsi->vol_utbl;
|
upcase_table = fsi->vol_utbl;
|
||||||
for(i = 0 ; i < UTBL_COL_COUNT ; i ++) {
|
for (i = 0 ; i < UTBL_COL_COUNT ; i++) {
|
||||||
if (upcase_table[i])
|
/* kfree(NULL) is safe */
|
||||||
kfree(upcase_table[i]);
|
kfree(upcase_table[i]);
|
||||||
|
upcase_table[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsi->vol_utbl) {
|
/* kfree(NULL) is safe */
|
||||||
kfree(fsi->vol_utbl);
|
kfree(fsi->vol_utbl);
|
||||||
fsi->vol_utbl = NULL;
|
fsi->vol_utbl = NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_sectors, u32 utbl_checksum)
|
static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_sectors, u32 utbl_checksum)
|
||||||
|
|
@ -373,8 +364,9 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
u8 skip = false;
|
u8 skip = false;
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
u32 checksum = 0;
|
u32 checksum = 0;
|
||||||
u16 **upcase_table = (u16 **)kzalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL);
|
u16 **upcase_table = kzalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL);
|
||||||
if(!upcase_table)
|
|
||||||
|
if (!upcase_table)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
/* thanks for kzalloc
|
/* thanks for kzalloc
|
||||||
* memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
|
* memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
|
||||||
|
|
@ -383,7 +375,7 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
fsi->vol_utbl = upcase_table;
|
fsi->vol_utbl = upcase_table;
|
||||||
num_sectors += sector;
|
num_sectors += sector;
|
||||||
|
|
||||||
while(sector < num_sectors) {
|
while (sector < num_sectors) {
|
||||||
ret = read_sect(sb, sector, &tmp_bh, 1);
|
ret = read_sect(sb, sector, &tmp_bh, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
EMSG("%s: failed to read sector(0x%x)\n",
|
EMSG("%s: failed to read sector(0x%x)\n",
|
||||||
|
|
@ -392,19 +384,19 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
}
|
}
|
||||||
sector++;
|
sector++;
|
||||||
|
|
||||||
for(i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
|
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
|
||||||
/* FIXME : is __le16 ok? */
|
/* FIXME : is __le16 ok? */
|
||||||
//u16 uni = le16_to_cpu(((__le16*)(tmp_bh->b_data))[i]);
|
//u16 uni = le16_to_cpu(((__le16*)(tmp_bh->b_data))[i]);
|
||||||
u16 uni = get_unaligned_le16((u8*)tmp_bh->b_data+i);
|
u16 uni = get_unaligned_le16((u8 *)tmp_bh->b_data+i);
|
||||||
|
|
||||||
checksum = ((checksum & 1) ? 0x80000000 : 0 ) +
|
checksum = ((checksum & 1) ? 0x80000000 : 0) +
|
||||||
(checksum >> 1) + *(((u8*)tmp_bh->b_data)+i);
|
(checksum >> 1) + *(((u8 *)tmp_bh->b_data)+i);
|
||||||
checksum = ((checksum & 1) ? 0x80000000 : 0 ) +
|
checksum = ((checksum & 1) ? 0x80000000 : 0) +
|
||||||
(checksum >> 1) + *(((u8*)tmp_bh->b_data)+(i+1));
|
(checksum >> 1) + *(((u8 *)tmp_bh->b_data)+(i+1));
|
||||||
|
|
||||||
if (skip) {
|
if (skip) {
|
||||||
MMSG("skip from 0x%X to 0x%X(amount of 0x%X)\n",
|
MMSG("skip from 0x%X to 0x%X(amount of 0x%X)\n",
|
||||||
index, index+uni, uni);
|
index, index+uni, uni);
|
||||||
index += uni;
|
index += uni;
|
||||||
skip = false;
|
skip = false;
|
||||||
} else if (uni == index) {
|
} else if (uni == index) {
|
||||||
|
|
@ -413,8 +405,10 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
skip = true;
|
skip = true;
|
||||||
} else { /* uni != index , uni != 0xFFFF */
|
} else { /* uni != index , uni != 0xFFFF */
|
||||||
u16 col_index = get_col_index(index);
|
u16 col_index = get_col_index(index);
|
||||||
|
|
||||||
if (!upcase_table[col_index]) {
|
if (!upcase_table[col_index]) {
|
||||||
upcase_table[col_index] = (u16 *)kmalloc((UTBL_ROW_COUNT * sizeof(u16)), GFP_KERNEL);
|
upcase_table[col_index] =
|
||||||
|
kmalloc((UTBL_ROW_COUNT * sizeof(u16)), GFP_KERNEL);
|
||||||
if (!upcase_table[col_index]) {
|
if (!upcase_table[col_index]) {
|
||||||
EMSG("failed to allocate memory"
|
EMSG("failed to allocate memory"
|
||||||
" for column 0x%X\n",
|
" for column 0x%X\n",
|
||||||
|
|
@ -423,7 +417,7 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(j = 0 ; j < UTBL_ROW_COUNT ; j++)
|
for (j = 0; j < UTBL_ROW_COUNT; j++)
|
||||||
upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
|
upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,9 +428,9 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
}
|
}
|
||||||
if (index >= 0xFFFF && utbl_checksum == checksum) {
|
if (index >= 0xFFFF && utbl_checksum == checksum) {
|
||||||
DMSG("%s: load upcase table successfully"
|
DMSG("%s: load upcase table successfully"
|
||||||
"(idx:0x%08x, utbl_chksum:0x%08x)\n",
|
"(idx:0x%08x, utbl_chksum:0x%08x)\n",
|
||||||
__func__, index, utbl_checksum);
|
__func__, index, utbl_checksum);
|
||||||
if(tmp_bh)
|
if (tmp_bh)
|
||||||
brelse(tmp_bh);
|
brelse(tmp_bh);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -447,9 +441,9 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
error:
|
error:
|
||||||
if(tmp_bh)
|
if (tmp_bh)
|
||||||
brelse(tmp_bh);
|
brelse(tmp_bh);
|
||||||
free_upcase_table(sb);
|
free_upcase_table(sb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -459,36 +453,36 @@ static s32 __load_default_upcase_table(struct super_block *sb)
|
||||||
u32 j;
|
u32 j;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
u8 skip = false;
|
u8 skip = false;
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
u16 uni = 0;
|
u16 uni = 0;
|
||||||
u16 **upcase_table;
|
u16 **upcase_table;
|
||||||
|
|
||||||
upcase_table = (u16 **) kmalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL);
|
upcase_table = kmalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL);
|
||||||
if(!upcase_table)
|
if (!upcase_table)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
fsi->vol_utbl = upcase_table;
|
fsi->vol_utbl = upcase_table;
|
||||||
memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
|
memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
|
||||||
|
|
||||||
for(i = 0; index <= 0xFFFF && i < SDFAT_NUM_UPCASE*2; i += 2) {
|
for (i = 0; index <= 0xFFFF && i < SDFAT_NUM_UPCASE*2; i += 2) {
|
||||||
/* FIXME : is __le16 ok? */
|
/* FIXME : is __le16 ok? */
|
||||||
//uni = le16_to_cpu(((__le16*)uni_def_upcase)[i>>1]);
|
//uni = le16_to_cpu(((__le16*)uni_def_upcase)[i>>1]);
|
||||||
uni = get_unaligned_le16((u8*)uni_def_upcase+i);
|
uni = get_unaligned_le16((u8 *)uni_def_upcase+i);
|
||||||
if(skip) {
|
if (skip) {
|
||||||
MMSG("skip from 0x%x ", index);
|
MMSG("skip from 0x%x ", index);
|
||||||
index += uni;
|
index += uni;
|
||||||
MMSG("to 0x%x (amount of 0x%x)\n", index, uni);
|
MMSG("to 0x%x (amount of 0x%x)\n", index, uni);
|
||||||
skip = false;
|
skip = false;
|
||||||
} else if(uni == index)
|
} else if (uni == index) {
|
||||||
index++;
|
index++;
|
||||||
else if(uni == 0xFFFF)
|
} else if (uni == 0xFFFF) {
|
||||||
skip = true;
|
skip = true;
|
||||||
else { /* uni != index , uni != 0xFFFF */
|
} else { /* uni != index , uni != 0xFFFF */
|
||||||
u16 col_index = get_col_index(index);
|
u16 col_index = get_col_index(index);
|
||||||
|
|
||||||
if (!upcase_table[col_index]) {
|
if (!upcase_table[col_index]) {
|
||||||
upcase_table[col_index] = (u16 *) kmalloc((UTBL_ROW_COUNT * sizeof(u16)), GFP_KERNEL);
|
upcase_table[col_index] = kmalloc((UTBL_ROW_COUNT * sizeof(u16)), GFP_KERNEL);
|
||||||
if (!upcase_table[col_index]) {
|
if (!upcase_table[col_index]) {
|
||||||
EMSG("failed to allocate memory for "
|
EMSG("failed to allocate memory for "
|
||||||
"new column 0x%x\n", col_index);
|
"new column 0x%x\n", col_index);
|
||||||
|
|
@ -496,21 +490,21 @@ static s32 __load_default_upcase_table(struct super_block *sb)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(j = 0 ; j < UTBL_ROW_COUNT ; j++)
|
for (j = 0; j < UTBL_ROW_COUNT; j++)
|
||||||
upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
|
upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
|
||||||
}
|
}
|
||||||
|
|
||||||
upcase_table[col_index][get_row_index(index)] = uni;
|
upcase_table[col_index][get_row_index(index)] = uni;
|
||||||
index ++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(index >= 0xFFFF)
|
if (index >= 0xFFFF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
/* FATAL error: default upcase table has error */
|
/* FATAL error: default upcase table has error */
|
||||||
free_upcase_table(sb);
|
free_upcase_table(sb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,7 +615,7 @@ static s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret =walk_fat_chain(sb, p_dir, off, &clu);
|
ret = walk_fat_chain(sb, p_dir, off, &clu);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
@ -832,10 +826,8 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries
|
||||||
if (dentry == -EIO)
|
if (dentry == -EIO)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((fid->size >> DENTRY_SIZE_BITS) >= MAX_FAT_DENTRIES) {
|
if (fsi->fs_func->check_max_dentries(fid))
|
||||||
/* FAT spec allows a dir to grow upto 65536 dentries */
|
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
|
||||||
|
|
||||||
/* we trust p_dir->size regardless of FAT type */
|
/* we trust p_dir->size regardless of FAT type */
|
||||||
if (__find_last_cluster(sb, p_dir, &last_clu))
|
if (__find_last_cluster(sb, p_dir, &last_clu))
|
||||||
|
|
@ -849,8 +841,9 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries
|
||||||
clu.flags = p_dir->flags;
|
clu.flags = p_dir->flags;
|
||||||
|
|
||||||
/* (0) check if there are reserved clusters
|
/* (0) check if there are reserved clusters
|
||||||
(create_dir 의 주석 참고) */
|
* (create_dir 의 주석 참고)
|
||||||
if (!IS_CLUS_EOF(fsi->used_clusters) && \
|
*/
|
||||||
|
if (!IS_CLUS_EOF(fsi->used_clusters) &&
|
||||||
((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2)))
|
((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2)))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
|
|
@ -873,6 +866,7 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries
|
||||||
p_dir->flags = 0x01;
|
p_dir->flags = 0x01;
|
||||||
hint_femp.cur.flags = 0x01;
|
hint_femp.cur.flags = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clu.flags == 0x01)
|
if (clu.flags == 0x01)
|
||||||
if (fat_ent_set(sb, last_clu, clu.dir))
|
if (fat_ent_set(sb, last_clu, clu.dir))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -881,7 +875,6 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries
|
||||||
/* the special case that new dentry
|
/* the special case that new dentry
|
||||||
* should be allocated from the start of new cluster
|
* should be allocated from the start of new cluster
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hint_femp.eidx = p_dir->size <<
|
hint_femp.eidx = p_dir->size <<
|
||||||
(fsi->cluster_size_bits - DENTRY_SIZE_BITS);
|
(fsi->cluster_size_bits - DENTRY_SIZE_BITS);
|
||||||
hint_femp.count = fsi->dentries_per_clu;
|
hint_femp.count = fsi->dentries_per_clu;
|
||||||
|
|
@ -921,11 +914,10 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries
|
||||||
return dentry;
|
return dentry;
|
||||||
} /* end of find_empty_entry */
|
} /* end of find_empty_entry */
|
||||||
|
|
||||||
|
|
||||||
#define SDFAT_MIN_SUBDIR (2)
|
#define SDFAT_MIN_SUBDIR (2)
|
||||||
static const char * dot_name[SDFAT_MIN_SUBDIR] = { DOS_CUR_DIR_NAME, DOS_PAR_DIR_NAME };
|
static const char *dot_name[SDFAT_MIN_SUBDIR] = { DOS_CUR_DIR_NAME, DOS_PAR_DIR_NAME };
|
||||||
|
|
||||||
static s32 __count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type, u32* dotcnt)
|
static s32 __count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type, u32 *dotcnt)
|
||||||
{
|
{
|
||||||
s32 i, count = 0, check_dot = 0;
|
s32 i, count = 0, check_dot = 0;
|
||||||
s32 dentries_per_clu;
|
s32 dentries_per_clu;
|
||||||
|
|
@ -1022,17 +1014,19 @@ s32 check_dir_empty(struct super_block *sb, CHAIN_T *p_dir)
|
||||||
|
|
||||||
if (type == TYPE_UNUSED)
|
if (type == TYPE_UNUSED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((type != TYPE_FILE) && (type != TYPE_DIR))
|
if ((type != TYPE_FILE) && (type != TYPE_DIR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IS_CLUS_FREE(p_dir->dir)) { /* FAT16 root_dir */
|
/* FAT16 root_dir */
|
||||||
|
if (IS_CLUS_FREE(p_dir->dir))
|
||||||
|
return -ENOTEMPTY;
|
||||||
|
|
||||||
|
if (fsi->vol_type == EXFAT)
|
||||||
|
return -ENOTEMPTY;
|
||||||
|
|
||||||
|
if ((p_dir->dir == fsi->root_dir) || (++count > 2))
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
} else {
|
|
||||||
if (fsi->vol_type == EXFAT)
|
|
||||||
return -ENOTEMPTY;
|
|
||||||
if ((p_dir->dir == fsi->root_dir) || ((++count) > 2))
|
|
||||||
return -ENOTEMPTY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FAT16 root_dir */
|
/* FAT16 root_dir */
|
||||||
|
|
@ -1102,8 +1096,11 @@ static inline void preprocess_ext_only_sfn(s32 lookup, u16 first_char, DOS_NAME_
|
||||||
}
|
}
|
||||||
|
|
||||||
/* input : dir, uni_name
|
/* input : dir, uni_name
|
||||||
output : num_of_entry, dos_name(format : aaaaaa~1.bbb) */
|
* output : num_of_entry, dos_name(format : aaaaaa~1.bbb)
|
||||||
static s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname, s32 lookup)
|
*/
|
||||||
|
static s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir,
|
||||||
|
UNI_NAME_T *p_uniname, s32 *entries,
|
||||||
|
DOS_NAME_T *p_dosname, s32 lookup)
|
||||||
{
|
{
|
||||||
s32 ret, num_entries, lossy = NLS_NAME_NO_LOSSY;
|
s32 ret, num_entries, lossy = NLS_NAME_NO_LOSSY;
|
||||||
s8 **r;
|
s8 **r;
|
||||||
|
|
@ -1221,14 +1218,16 @@ static s32 __resolve_path(struct inode *inode, const u8 *path, CHAIN_T *p_dir, U
|
||||||
p_dir->flags = fid->flags;
|
p_dir->flags = fid->flags;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of resolve_path */
|
|
||||||
|
|
||||||
static inline s32 resolve_path(struct inode *inode, const u8 *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) {
|
|
||||||
return __resolve_path(inode, path, p_dir, p_uniname, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline s32 resolve_path_for_lookup(struct inode *inode, const u8 *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) {
|
static inline s32 resolve_path(struct inode *inode, const u8 *path, CHAIN_T *dir, UNI_NAME_T *uni)
|
||||||
return __resolve_path(inode, path, p_dir, p_uniname, 1);
|
{
|
||||||
|
return __resolve_path(inode, path, dir, uni, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline s32 resolve_path_for_lookup(struct inode *inode, const u8 *path, CHAIN_T *dir, UNI_NAME_T *uni)
|
||||||
|
{
|
||||||
|
return __resolve_path(inode, path, dir, uni, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
|
static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
|
||||||
|
|
@ -1254,7 +1253,7 @@ static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname
|
||||||
clu.flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01;
|
clu.flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01;
|
||||||
|
|
||||||
/* (0) Check if there are reserved clusters up to max. */
|
/* (0) Check if there are reserved clusters up to max. */
|
||||||
if ((fsi->used_clusters != (u32) ~0) && \
|
if ((fsi->used_clusters != (u32) ~0) &&
|
||||||
((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2)))
|
((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2)))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
|
|
@ -1274,8 +1273,9 @@ static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname
|
||||||
size = fsi->cluster_size;
|
size = fsi->cluster_size;
|
||||||
if (fsi->vol_type != EXFAT) {
|
if (fsi->vol_type != EXFAT) {
|
||||||
/* initialize the . and .. entry
|
/* initialize the . and .. entry
|
||||||
Information for . points to itself
|
* Information for . points to itself
|
||||||
Information for .. points to parent dir */
|
* Information for .. points to parent dir
|
||||||
|
*/
|
||||||
|
|
||||||
dot_name.name_case = 0x0;
|
dot_name.name_case = 0x0;
|
||||||
memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH);
|
memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH);
|
||||||
|
|
@ -1323,7 +1323,7 @@ static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname
|
||||||
fid->size = size;
|
fid->size = size;
|
||||||
fid->start_clu = clu.dir;
|
fid->start_clu = clu.dir;
|
||||||
|
|
||||||
fid->type= TYPE_DIR;
|
fid->type = TYPE_DIR;
|
||||||
fid->rwoffset = 0;
|
fid->rwoffset = 0;
|
||||||
fid->hint_bmap.off = -1;
|
fid->hint_bmap.off = -1;
|
||||||
|
|
||||||
|
|
@ -1354,7 +1354,8 @@ static s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uninam
|
||||||
|
|
||||||
/* (1) update the directory entry */
|
/* (1) update the directory entry */
|
||||||
/* fill the dos name directory entry information of the created file.
|
/* fill the dos name directory entry information of the created file.
|
||||||
the first cluster is not determined yet. (0) */
|
* the first cluster is not determined yet. (0)
|
||||||
|
*/
|
||||||
ret = fsi->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUS_FREE, 0);
|
ret = fsi->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUS_FREE, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -1373,7 +1374,7 @@ static s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uninam
|
||||||
fid->size = 0;
|
fid->size = 0;
|
||||||
fid->start_clu = CLUS_EOF;
|
fid->start_clu = CLUS_EOF;
|
||||||
|
|
||||||
fid->type= TYPE_FILE;
|
fid->type = TYPE_FILE;
|
||||||
fid->rwoffset = 0;
|
fid->rwoffset = 0;
|
||||||
fid->hint_bmap.off = -1;
|
fid->hint_bmap.off = -1;
|
||||||
|
|
||||||
|
|
@ -1503,7 +1504,8 @@ static s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 oldentry, UNI_NA
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of rename_file */
|
} /* end of rename_file */
|
||||||
|
|
||||||
static s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
|
static s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry,
|
||||||
|
CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
|
||||||
{
|
{
|
||||||
s32 ret, newentry, num_new_entries, num_old_entries;
|
s32 ret, newentry, num_new_entries, num_old_entries;
|
||||||
u32 sector_mov, sector_new;
|
u32 sector_mov, sector_new;
|
||||||
|
|
@ -1627,10 +1629,11 @@ s32 fscore_shutdown(void)
|
||||||
static bool is_exfat(pbr_t *pbr)
|
static bool is_exfat(pbr_t *pbr)
|
||||||
{
|
{
|
||||||
int i = 53;
|
int i = 53;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (pbr->bpb.f64.res_zero[i-1])
|
if (pbr->bpb.f64.res_zero[i-1])
|
||||||
break;
|
break;
|
||||||
} while(--i);
|
} while (--i);
|
||||||
return i ? false : true;
|
return i ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1704,6 +1707,7 @@ s32 fscore_mount(struct super_block *sb)
|
||||||
s32 ret;
|
s32 ret;
|
||||||
pbr_t *p_pbr;
|
pbr_t *p_pbr;
|
||||||
struct buffer_head *tmp_bh = NULL;
|
struct buffer_head *tmp_bh = NULL;
|
||||||
|
struct gendisk *disk = sb->s_bdev->bd_disk;
|
||||||
struct sdfat_mount_options *opts = &(SDFAT_SB(sb)->options);
|
struct sdfat_mount_options *opts = &(SDFAT_SB(sb)->options);
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
|
|
@ -1746,7 +1750,7 @@ s32 fscore_mount(struct super_block *sb)
|
||||||
|
|
||||||
/* fill fs_struct */
|
/* fill fs_struct */
|
||||||
if (is_exfat(p_pbr)) {
|
if (is_exfat(p_pbr)) {
|
||||||
if(opts->fs_type && opts->fs_type != FS_TYPE_EXFAT) {
|
if (opts->fs_type && opts->fs_type != FS_TYPE_EXFAT) {
|
||||||
sdfat_log_msg(sb, KERN_ERR,
|
sdfat_log_msg(sb, KERN_ERR,
|
||||||
"not specified filesystem type "
|
"not specified filesystem type "
|
||||||
"(media:exfat, opts:%s)",
|
"(media:exfat, opts:%s)",
|
||||||
|
|
@ -1759,8 +1763,8 @@ s32 fscore_mount(struct super_block *sb)
|
||||||
opts->improved_allocation = 0;
|
opts->improved_allocation = 0;
|
||||||
opts->defrag = 0;
|
opts->defrag = 0;
|
||||||
ret = mount_exfat(sb, p_pbr);
|
ret = mount_exfat(sb, p_pbr);
|
||||||
} else if(is_fat32(p_pbr)) {
|
} else if (is_fat32(p_pbr)) {
|
||||||
if(opts->fs_type && opts->fs_type != FS_TYPE_VFAT) {
|
if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) {
|
||||||
sdfat_log_msg(sb, KERN_ERR,
|
sdfat_log_msg(sb, KERN_ERR,
|
||||||
"not specified filesystem type "
|
"not specified filesystem type "
|
||||||
"(media:vfat, opts:%s)",
|
"(media:vfat, opts:%s)",
|
||||||
|
|
@ -1772,7 +1776,7 @@ s32 fscore_mount(struct super_block *sb)
|
||||||
sb->s_maxbytes = 0xffffffff;
|
sb->s_maxbytes = 0xffffffff;
|
||||||
ret = mount_fat32(sb, p_pbr);
|
ret = mount_fat32(sb, p_pbr);
|
||||||
} else {
|
} else {
|
||||||
if(opts->fs_type && opts->fs_type != FS_TYPE_VFAT) {
|
if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) {
|
||||||
sdfat_log_msg(sb, KERN_ERR,
|
sdfat_log_msg(sb, KERN_ERR,
|
||||||
"not specified filesystem type "
|
"not specified filesystem type "
|
||||||
"(media:vfat, opts:%s)",
|
"(media:vfat, opts:%s)",
|
||||||
|
|
@ -1802,8 +1806,13 @@ free_bh:
|
||||||
(fsi->data_start_sector & (fsi->sect_per_clus - 1)) ?
|
(fsi->data_start_sector & (fsi->sect_per_clus - 1)) ?
|
||||||
"misaligned" : "aligned");
|
"misaligned" : "aligned");
|
||||||
|
|
||||||
ret = load_upcase_table(sb);
|
sdfat_log_msg(sb, KERN_INFO,
|
||||||
if (ret) {
|
"detected volume size : %u MB (disk_size : %llu MB)",
|
||||||
|
fsi->num_sectors >> 11,
|
||||||
|
disk ? (u64)((disk->part0.nr_sects) >> 11) : 0);
|
||||||
|
|
||||||
|
ret = load_upcase_table(sb);
|
||||||
|
if (ret) {
|
||||||
sdfat_log_msg(sb, KERN_ERR, "failed to load upcase table");
|
sdfat_log_msg(sb, KERN_ERR, "failed to load upcase table");
|
||||||
goto bd_close;
|
goto bd_close;
|
||||||
}
|
}
|
||||||
|
|
@ -1894,6 +1903,7 @@ s32 fscore_sync_fs(struct super_block *sb, s32 do_sync)
|
||||||
u32 fscore_get_au_stat(struct super_block *sb, s32 mode)
|
u32 fscore_get_au_stat(struct super_block *sb, s32 mode)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
if (fsi->fs_func->get_au_stat)
|
if (fsi->fs_func->get_au_stat)
|
||||||
return fsi->fs_func->get_au_stat(sb, mode);
|
return fsi->fs_func->get_au_stat(sb, mode);
|
||||||
|
|
||||||
|
|
@ -1913,7 +1923,7 @@ s32 fscore_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid)
|
||||||
UNI_NAME_T uni_name;
|
UNI_NAME_T uni_name;
|
||||||
DOS_NAME_T dos_name;
|
DOS_NAME_T dos_name;
|
||||||
DENTRY_T *ep, *ep2;
|
DENTRY_T *ep, *ep2;
|
||||||
ENTRY_SET_CACHE_T *es=NULL;
|
ENTRY_SET_CACHE_T *es = NULL;
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
FILE_ID_T *dir_fid = &(SDFAT_I(inode)->fid);
|
FILE_ID_T *dir_fid = &(SDFAT_I(inode)->fid);
|
||||||
|
|
@ -2275,9 +2285,9 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
memcpy( ((s8 *) tmp_bh->b_data),
|
memcpy(((s8 *)tmp_bh->b_data),
|
||||||
((s8 *) buffer)+write_bytes,
|
((s8 *)buffer)+write_bytes,
|
||||||
(s32) oneblkwrite);
|
(s32)oneblkwrite);
|
||||||
|
|
||||||
ret = write_sect(sb, LogSector, tmp_bh, 0);
|
ret = write_sect(sb, LogSector, tmp_bh, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
@ -2387,7 +2397,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
||||||
ENTRY_SET_CACHE_T *es=NULL;
|
ENTRY_SET_CACHE_T *es = NULL;
|
||||||
s32 evict = (fid->dir.dir == DIR_DELETED) ? 1 : 0;
|
s32 evict = (fid->dir.dir == DIR_DELETED) ? 1 : 0;
|
||||||
|
|
||||||
/* check if the given file ID is opened */
|
/* check if the given file ID is opened */
|
||||||
|
|
@ -2403,7 +2413,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
/* It can be when write failed */
|
/* It can be when write failed */
|
||||||
#if 0
|
#if 0
|
||||||
if (fid->size != old_size) {
|
if (fid->size != old_size) {
|
||||||
DMSG( "%s: inode(%p) size-mismatch(old:%lld != fid:%lld)\n",
|
DMSG("%s: inode(%p) size-mismatch(old:%lld != fid:%lld)\n",
|
||||||
__func__, inode, old_size, fid->size);
|
__func__, inode, old_size, fid->size);
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
}
|
}
|
||||||
|
|
@ -2429,13 +2439,13 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
/* for debugging (FIXME: is okay on no-da case?) */
|
/* for debugging (FIXME: is okay on no-da case?) */
|
||||||
BUG_ON(num_clusters_da < num_clusters_phys);
|
BUG_ON(num_clusters_da < num_clusters_phys);
|
||||||
|
|
||||||
if ( (num_clusters_da != num_clusters_phys) &&
|
if ((num_clusters_da != num_clusters_phys) &&
|
||||||
(num_clusters_new < num_clusters_da) ) {
|
(num_clusters_new < num_clusters_da)) {
|
||||||
/* Decrement reserved clusters
|
/* Decrement reserved clusters
|
||||||
* n_reserved = num_clusters_da - max(new,phys)
|
* n_reserved = num_clusters_da - max(new,phys)
|
||||||
*/
|
*/
|
||||||
int n_reserved = (num_clusters_new > num_clusters_phys) ? \
|
int n_reserved = (num_clusters_new > num_clusters_phys) ?
|
||||||
(num_clusters_da - num_clusters_new) : \
|
(num_clusters_da - num_clusters_new) :
|
||||||
(num_clusters_da - num_clusters_phys);
|
(num_clusters_da - num_clusters_phys);
|
||||||
|
|
||||||
fsi->reserved_clusters -= n_reserved;
|
fsi->reserved_clusters -= n_reserved;
|
||||||
|
|
@ -2449,17 +2459,19 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
clu.size = num_clusters_phys;
|
clu.size = num_clusters_phys;
|
||||||
clu.flags = fid->flags;
|
clu.flags = fid->flags;
|
||||||
|
|
||||||
|
/* For bigdata */
|
||||||
|
sdfat_statistics_set_trunc(clu.flags, &clu);
|
||||||
|
|
||||||
if (new_size > 0) {
|
if (new_size > 0) {
|
||||||
/* Truncate FAT chain num_clusters after the first cluster
|
/* Truncate FAT chain num_clusters after the first cluster
|
||||||
* num_clusters = min(new, phys);
|
* num_clusters = min(new, phys);
|
||||||
*/
|
*/
|
||||||
s32 num_clusters = (num_clusters_new < num_clusters_phys) ? \
|
s32 num_clusters = (num_clusters_new < num_clusters_phys) ?
|
||||||
num_clusters_new : num_clusters_phys;
|
num_clusters_new : num_clusters_phys;
|
||||||
|
|
||||||
/* Follow FAT chain
|
/* Follow FAT chain
|
||||||
(defensive coding - works fine even with corrupted FAT table
|
* (defensive coding - works fine even with corrupted FAT table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (clu.flags == 0x03) {
|
if (clu.flags == 0x03) {
|
||||||
clu.dir += num_clusters;
|
clu.dir += num_clusters;
|
||||||
clu.size -= num_clusters;
|
clu.size -= num_clusters;
|
||||||
|
|
@ -2478,7 +2490,8 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
if ((num_clusters > 1) && (last_clu == fid->start_clu)) {
|
if ((num_clusters > 1) && (last_clu == fid->start_clu)) {
|
||||||
s32 fclus_tmp = 0;
|
s32 fclus_tmp = 0;
|
||||||
u32 temp = 0;
|
u32 temp = 0;
|
||||||
err = extent_get_clus(inode, num_clusters -1,
|
|
||||||
|
err = extent_get_clus(inode, num_clusters - 1,
|
||||||
&fclus_tmp, &last_clu, &temp, 0);
|
&fclus_tmp, &last_clu, &temp, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -2499,12 +2512,10 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Optimization avialable: */
|
||||||
Optimization avialable
|
#if 0
|
||||||
|
|
||||||
if (num_clusters_new < num_clusters) {
|
if (num_clusters_new < num_clusters) {
|
||||||
<loop>
|
< loop >
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// num_clusters_new >= num_clusters_phys
|
// num_clusters_new >= num_clusters_phys
|
||||||
// FAT truncation is not necessary
|
// FAT truncation is not necessary
|
||||||
|
|
@ -2512,7 +2523,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
clu.dir = CLUS_EOF;
|
clu.dir = CLUS_EOF;
|
||||||
clu.size = 0;
|
clu.size = 0;
|
||||||
}
|
}
|
||||||
*/
|
#endif
|
||||||
} else if (new_size == 0) {
|
} else if (new_size == 0) {
|
||||||
fid->flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01;
|
fid->flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01;
|
||||||
fid->start_clu = CLUS_EOF;
|
fid->start_clu = CLUS_EOF;
|
||||||
|
|
@ -2524,11 +2535,10 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
fid->attr |= ATTR_ARCHIVE;
|
fid->attr |= ATTR_ARCHIVE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
clu.dir: free from
|
* clu.dir: free from
|
||||||
clu.size: # of clusters to free (exFAT, 0x03 only)
|
* clu.size: # of clusters to free (exFAT, 0x03 only), no fat_free if 0
|
||||||
if 0, no fat_free
|
* clu.flags: fid->flags (exFAT only)
|
||||||
clu.flags: fid->flags (exFAT only)
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
/* (1) update the directory entry */
|
/* (1) update the directory entry */
|
||||||
if (!evict) {
|
if (!evict) {
|
||||||
|
|
@ -2548,8 +2558,10 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY);
|
fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY);
|
||||||
fsi->fs_func->set_entry_attr(ep, fid->attr);
|
fsi->fs_func->set_entry_attr(ep, fid->attr);
|
||||||
|
|
||||||
/* if (fsi->vol_type != EXFAT)
|
/*
|
||||||
dcache_modify(sb, sector); */
|
* if (fsi->vol_type != EXFAT)
|
||||||
|
* dcache_modify(sb, sector);
|
||||||
|
*/
|
||||||
|
|
||||||
/* File size should be zero if there is no cluster allocated */
|
/* File size should be zero if there is no cluster allocated */
|
||||||
if (IS_CLUS_EOF(fid->start_clu))
|
if (IS_CLUS_EOF(fid->start_clu))
|
||||||
|
|
@ -2579,8 +2591,8 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
/* (2) cut off from the FAT chain */
|
/* (2) cut off from the FAT chain */
|
||||||
if ((fid->flags == 0x01) &&
|
if ((fid->flags == 0x01) &&
|
||||||
(!IS_CLUS_FREE(last_clu)) && (!IS_CLUS_EOF(last_clu))) {
|
(!IS_CLUS_FREE(last_clu)) && (!IS_CLUS_EOF(last_clu))) {
|
||||||
if (fat_ent_set(sb, last_clu, CLUS_EOF))
|
if (fat_ent_set(sb, last_clu, CLUS_EOF))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) invalidate cache and free the clusters */
|
/* (3) invalidate cache and free the clusters */
|
||||||
|
|
@ -2608,9 +2620,9 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size)
|
||||||
return 0;
|
return 0;
|
||||||
} /* end of fscore_truncate */
|
} /* end of fscore_truncate */
|
||||||
|
|
||||||
static void update_parent_info( FILE_ID_T *fid, struct inode *parent_inode)
|
static void update_parent_info(FILE_ID_T *fid, struct inode *parent_inode)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(parent_inode->i_sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(parent_inode->i_sb)->fsi);
|
||||||
FILE_ID_T *parent_fid = &(SDFAT_I(parent_inode)->fid);
|
FILE_ID_T *parent_fid = &(SDFAT_I(parent_inode)->fid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -2631,12 +2643,13 @@ static void update_parent_info( FILE_ID_T *fid, struct inode *parent_inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rename or move a old file into a new file */
|
/* rename or move a old file into a new file */
|
||||||
s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry)
|
s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid,
|
||||||
|
struct inode *new_parent_inode, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
s32 ret;
|
s32 ret;
|
||||||
s32 dentry;
|
s32 dentry;
|
||||||
CHAIN_T olddir, newdir;
|
CHAIN_T olddir, newdir;
|
||||||
CHAIN_T *p_dir=NULL;
|
CHAIN_T *p_dir = NULL;
|
||||||
UNI_NAME_T uni_name;
|
UNI_NAME_T uni_name;
|
||||||
DENTRY_T *ep;
|
DENTRY_T *ep;
|
||||||
struct super_block *sb = old_parent_inode->i_sb;
|
struct super_block *sb = old_parent_inode->i_sb;
|
||||||
|
|
@ -2646,7 +2659,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *
|
||||||
int num_entries;
|
int num_entries;
|
||||||
FILE_ID_T *new_fid = NULL;
|
FILE_ID_T *new_fid = NULL;
|
||||||
u32 new_entry_type = TYPE_UNUSED;
|
u32 new_entry_type = TYPE_UNUSED;
|
||||||
s32 new_entry=0;
|
s32 new_entry = 0;
|
||||||
|
|
||||||
/* check the validity of pointer parameters */
|
/* check the validity of pointer parameters */
|
||||||
if ((new_path == NULL) || (strlen(new_path) == 0))
|
if ((new_path == NULL) || (strlen(new_path) == 0))
|
||||||
|
|
@ -2711,6 +2724,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *
|
||||||
|
|
||||||
if (new_entry_type == TYPE_DIR) {
|
if (new_entry_type == TYPE_DIR) {
|
||||||
CHAIN_T new_clu;
|
CHAIN_T new_clu;
|
||||||
|
|
||||||
new_clu.dir = new_fid->start_clu;
|
new_clu.dir = new_fid->start_clu;
|
||||||
new_clu.size = (s32)((new_fid->size-1) >> fsi->cluster_size_bits) + 1;
|
new_clu.size = (s32)((new_fid->size-1) >> fsi->cluster_size_bits) + 1;
|
||||||
new_clu.flags = new_fid->flags;
|
new_clu.flags = new_fid->flags;
|
||||||
|
|
@ -2757,6 +2771,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *
|
||||||
if (new_entry_type == TYPE_DIR) {
|
if (new_entry_type == TYPE_DIR) {
|
||||||
/* new_fid, new_clu_to_free */
|
/* new_fid, new_clu_to_free */
|
||||||
CHAIN_T new_clu_to_free;
|
CHAIN_T new_clu_to_free;
|
||||||
|
|
||||||
new_clu_to_free.dir = new_fid->start_clu;
|
new_clu_to_free.dir = new_fid->start_clu;
|
||||||
new_clu_to_free.size = (s32)((new_fid->size-1) >> fsi->cluster_size_bits) + 1;
|
new_clu_to_free.size = (s32)((new_fid->size-1) >> fsi->cluster_size_bits) + 1;
|
||||||
new_clu_to_free.flags = new_fid->flags;
|
new_clu_to_free.flags = new_fid->flags;
|
||||||
|
|
@ -2836,7 +2851,7 @@ s32 fscore_remove(struct inode *inode, FILE_ID_T *fid)
|
||||||
/* (3) update FILE_ID_T */
|
/* (3) update FILE_ID_T */
|
||||||
fid->size = 0;
|
fid->size = 0;
|
||||||
fid->start_clu = CLUS_EOF;
|
fid->start_clu = CLUS_EOF;
|
||||||
fid->flags = (fsi->vol_type == EXFAT)? 0x03: 0x01;
|
fid->flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01;
|
||||||
fid->dir.dir = DIR_DELETED;
|
fid->dir.dir = DIR_DELETED;
|
||||||
|
|
||||||
fs_sync(sb, 0);
|
fs_sync(sb, 0);
|
||||||
|
|
@ -2864,7 +2879,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
||||||
ENTRY_SET_CACHE_T *es=NULL;
|
ENTRY_SET_CACHE_T *es = NULL;
|
||||||
u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
|
u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
|
||||||
|
|
||||||
TMSG("%s entered\n", __func__);
|
TMSG("%s entered\n", __func__);
|
||||||
|
|
@ -2872,7 +2887,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
|
||||||
extent_cache_init_inode(inode);
|
extent_cache_init_inode(inode);
|
||||||
|
|
||||||
/* if root directory */
|
/* if root directory */
|
||||||
if ( is_dir && (fid->dir.dir == fsi->root_dir) && (fid->entry == -1) ) {
|
if (is_dir && (fid->dir.dir == fsi->root_dir) && (fid->entry == -1)) {
|
||||||
info->Attr = ATTR_SUBDIR;
|
info->Attr = ATTR_SUBDIR;
|
||||||
memset((s8 *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T));
|
memset((s8 *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T));
|
||||||
memset((s8 *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T));
|
memset((s8 *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T));
|
||||||
|
|
@ -2889,6 +2904,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
|
||||||
info->Size = fsi->dentries_in_root << DENTRY_SIZE_BITS;
|
info->Size = fsi->dentries_in_root << DENTRY_SIZE_BITS;
|
||||||
} else {
|
} else {
|
||||||
s32 num_clu;
|
s32 num_clu;
|
||||||
|
|
||||||
if (__count_num_clusters(sb, &dir, &num_clu))
|
if (__count_num_clusters(sb, &dir, &num_clu))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
info->Size = (u64)num_clu << fsi->cluster_size_bits;
|
info->Size = (u64)num_clu << fsi->cluster_size_bits;
|
||||||
|
|
@ -2951,6 +2967,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
|
||||||
|
|
||||||
if (is_dir) {
|
if (is_dir) {
|
||||||
u32 dotcnt = 0;
|
u32 dotcnt = 0;
|
||||||
|
|
||||||
dir.dir = fid->start_clu;
|
dir.dir = fid->start_clu;
|
||||||
dir.flags = fid->flags;
|
dir.flags = fid->flags;
|
||||||
dir.size = fid->size >> fsi->cluster_size_bits;
|
dir.size = fid->size >> fsi->cluster_size_bits;
|
||||||
|
|
@ -2958,14 +2975,15 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
|
||||||
* NOTE :
|
* NOTE :
|
||||||
* If "dir.flags" has 0x01, "dir.size" is meaningless.
|
* If "dir.flags" has 0x01, "dir.size" is meaningless.
|
||||||
*/
|
*/
|
||||||
|
#if 0
|
||||||
|
if (info->Size == 0) {
|
||||||
|
s32 num_clu;
|
||||||
|
|
||||||
// if (info->Size == 0) {
|
if (__count_num_clusters(sb, &dir, &num_clu))
|
||||||
// s32 num_clu;
|
return -EIO;
|
||||||
// if (__count_num_clusters(sb, &dir, &num_clu))
|
info->Size = (u64)num_clu << fsi->cluster_size_bits;
|
||||||
// return -EIO;
|
}
|
||||||
// info->Size = (u64)num_clu << fsi->cluster_size_bits;
|
#endif
|
||||||
// }
|
|
||||||
|
|
||||||
count = __count_dos_name_entries(sb, &dir, TYPE_DIR, &dotcnt);
|
count = __count_dos_name_entries(sb, &dir, TYPE_DIR, &dotcnt);
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -3001,7 +3019,7 @@ s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, s32 sync)
|
||||||
u32 sector;
|
u32 sector;
|
||||||
TIMESTAMP_T tm;
|
TIMESTAMP_T tm;
|
||||||
DENTRY_T *ep, *ep2;
|
DENTRY_T *ep, *ep2;
|
||||||
ENTRY_SET_CACHE_T *es=NULL;
|
ENTRY_SET_CACHE_T *es = NULL;
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
FILE_ID_T *fid = &(SDFAT_I(inode)->fid);
|
||||||
|
|
@ -3055,13 +3073,13 @@ s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, s32 sync)
|
||||||
fsi->fs_func->set_entry_time(ep, &tm, TM_MODIFY);
|
fsi->fs_func->set_entry_time(ep, &tm, TM_MODIFY);
|
||||||
|
|
||||||
if (is_dir && fsi->vol_type != EXFAT) {
|
if (is_dir && fsi->vol_type != EXFAT) {
|
||||||
/* if FAT32, and dir size != 0
|
/* overwirte dirsize if FAT32 and dir size != 0 */
|
||||||
overwrite dirsize */
|
|
||||||
if (fsi->fs_func->get_entry_size(ep2))
|
if (fsi->fs_func->get_entry_size(ep2))
|
||||||
fsi->fs_func->set_entry_size(ep2, 0);
|
fsi->fs_func->set_entry_size(ep2, 0);
|
||||||
} else {
|
} else {
|
||||||
/* File size should be zero if there is no cluster allocated */
|
/* File size should be zero if there is no cluster allocated */
|
||||||
u64 on_disk_size = info->Size;
|
u64 on_disk_size = info->Size;
|
||||||
|
|
||||||
if (IS_CLUS_EOF(fid->start_clu))
|
if (IS_CLUS_EOF(fid->start_clu))
|
||||||
on_disk_size = 0;
|
on_disk_size = 0;
|
||||||
|
|
||||||
|
|
@ -3109,7 +3127,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest)
|
||||||
num_clusters = (s32)((SDFAT_I(inode)->i_size_ondisk-1) >> fsi->cluster_size_bits) + 1;
|
num_clusters = (s32)((SDFAT_I(inode)->i_size_ondisk-1) >> fsi->cluster_size_bits) + 1;
|
||||||
|
|
||||||
num_to_be_allocated = clu_offset - num_clusters + 1;
|
num_to_be_allocated = clu_offset - num_clusters + 1;
|
||||||
if ((dest==ALLOC_NOWHERE) && (num_to_be_allocated > 0)) {
|
if ((dest == ALLOC_NOWHERE) && (num_to_be_allocated > 0)) {
|
||||||
*clu = CLUS_EOF;
|
*clu = CLUS_EOF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -3119,7 +3137,8 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest)
|
||||||
*clu = last_clu = fid->start_clu;
|
*clu = last_clu = fid->start_clu;
|
||||||
|
|
||||||
/* XXX: Defensive code needed.
|
/* XXX: Defensive code needed.
|
||||||
what if i_size_ondisk != # of allocated clusters */
|
* what if i_size_ondisk != # of allocated clusters
|
||||||
|
*/
|
||||||
if (fid->flags == 0x03) {
|
if (fid->flags == 0x03) {
|
||||||
if ((clu_offset > 0) && (!IS_CLUS_EOF(*clu))) {
|
if ((clu_offset > 0) && (!IS_CLUS_EOF(*clu))) {
|
||||||
last_clu += clu_offset - 1;
|
last_clu += clu_offset - 1;
|
||||||
|
|
@ -3129,7 +3148,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest)
|
||||||
else
|
else
|
||||||
*clu += clu_offset;
|
*clu += clu_offset;
|
||||||
}
|
}
|
||||||
} else if (fid->type == TYPE_FILE){
|
} else if (fid->type == TYPE_FILE) {
|
||||||
s32 fclus = 0;
|
s32 fclus = 0;
|
||||||
s32 err = extent_get_clus(inode, clu_offset,
|
s32 err = extent_get_clus(inode, clu_offset,
|
||||||
&fclus, clu, &last_clu, 1);
|
&fclus, clu, &last_clu, 1);
|
||||||
|
|
@ -3283,10 +3302,10 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest)
|
||||||
// DA의 경우, i_blocks가 이미 증가해있어야 함.
|
// DA의 경우, i_blocks가 이미 증가해있어야 함.
|
||||||
BUG_ON(clu_offset >= (inode->i_blocks >> (fsi->cluster_size_bits - sb->s_blocksize_bits)));
|
BUG_ON(clu_offset >= (inode->i_blocks >> (fsi->cluster_size_bits - sb->s_blocksize_bits)));
|
||||||
}
|
}
|
||||||
/* fs_sync(sb, 0);
|
#if 0
|
||||||
fs_set_vol_flags(sb, VOL_CLEAN); */
|
fs_sync(sb, 0);
|
||||||
|
fs_set_vol_flags(sb, VOL_CLEAN);
|
||||||
|
#endif
|
||||||
/* (4) Move *clu pointer along FAT chains (hole care)
|
/* (4) Move *clu pointer along FAT chains (hole care)
|
||||||
* because the caller of this function expect *clu to be the last cluster.
|
* because the caller of this function expect *clu to be the last cluster.
|
||||||
* This only works when num_to_be_allocated >= 2,
|
* This only works when num_to_be_allocated >= 2,
|
||||||
|
|
@ -3326,8 +3345,7 @@ s32 fscore_reserve_clus(struct inode *inode)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fsi->used_clusters + fsi->reserved_clusters) >=
|
if ((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2))
|
||||||
(fsi->num_clusters - 2))
|
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
if (bdev_check_bdi_valid(sb))
|
if (bdev_check_bdi_valid(sb))
|
||||||
|
|
@ -3630,7 +3648,7 @@ s32 fscore_rmdir(struct inode *inode, FILE_ID_T *fid)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == -EIO)
|
if (ret == -EIO)
|
||||||
EMSG("%s : failed to check_dir_empty : err(%d)\n",
|
EMSG("%s : failed to check_dir_empty : err(%d)\n",
|
||||||
__func__,ret);
|
__func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
22
core.h
22
core.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_CORE_H
|
#ifndef _SDFAT_CORE_H
|
||||||
|
|
@ -90,7 +88,8 @@ s32 fscore_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid);
|
||||||
s32 fscore_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount);
|
s32 fscore_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount);
|
||||||
s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount);
|
s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount);
|
||||||
s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size);
|
s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size);
|
||||||
s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry);
|
s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid,
|
||||||
|
struct inode *new_parent_inode, struct dentry *new_dentry);
|
||||||
s32 fscore_remove(struct inode *inode, FILE_ID_T *fid);
|
s32 fscore_remove(struct inode *inode, FILE_ID_T *fid);
|
||||||
s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info);
|
s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info);
|
||||||
s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync);
|
s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync);
|
||||||
|
|
@ -116,17 +115,17 @@ DENTRY_T *get_dentry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u
|
||||||
void get_uniname_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode);
|
void get_uniname_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode);
|
||||||
|
|
||||||
/* file operation functions */
|
/* file operation functions */
|
||||||
s32 walk_fat_chain (struct super_block *sb, CHAIN_T *p_dir, s32 byte_offset, u32 *clu);
|
s32 walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, s32 byte_offset, u32 *clu);
|
||||||
|
|
||||||
/* sdfat/cache.c */
|
/* sdfat/cache.c */
|
||||||
s32 meta_cache_init(struct super_block *sb);
|
s32 meta_cache_init(struct super_block *sb);
|
||||||
s32 meta_cache_shutdown(struct super_block *sb);
|
s32 meta_cache_shutdown(struct super_block *sb);
|
||||||
u8* fcache_getblk(struct super_block *sb, u32 sec);
|
u8 *fcache_getblk(struct super_block *sb, u32 sec);
|
||||||
s32 fcache_modify(struct super_block *sb, u32 sec);
|
s32 fcache_modify(struct super_block *sb, u32 sec);
|
||||||
s32 fcache_release_all(struct super_block *sb);
|
s32 fcache_release_all(struct super_block *sb);
|
||||||
s32 fcache_flush(struct super_block *sb, u32 sync);
|
s32 fcache_flush(struct super_block *sb, u32 sync);
|
||||||
|
|
||||||
u8* dcache_getblk(struct super_block *sb, u32 sec);
|
u8 *dcache_getblk(struct super_block *sb, u32 sec);
|
||||||
s32 dcache_modify(struct super_block *sb, u32 sec);
|
s32 dcache_modify(struct super_block *sb, u32 sec);
|
||||||
s32 dcache_lock(struct super_block *sb, u32 sec);
|
s32 dcache_lock(struct super_block *sb, u32 sec);
|
||||||
s32 dcache_unlock(struct super_block *sb, u32 sec);
|
s32 dcache_unlock(struct super_block *sb, u32 sec);
|
||||||
|
|
@ -151,10 +150,11 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr);
|
||||||
|
|
||||||
s32 load_alloc_bmp(struct super_block *sb);
|
s32 load_alloc_bmp(struct super_block *sb);
|
||||||
void free_alloc_bmp(struct super_block *sb);
|
void free_alloc_bmp(struct super_block *sb);
|
||||||
ENTRY_SET_CACHE_T *get_dentry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep);
|
ENTRY_SET_CACHE_T *get_dentry_set_in_dir(struct super_block *sb,
|
||||||
void release_dentry_set (ENTRY_SET_CACHE_T *es);
|
CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep);
|
||||||
|
void release_dentry_set(ENTRY_SET_CACHE_T *es);
|
||||||
s32 update_dir_chksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry);
|
s32 update_dir_chksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry);
|
||||||
s32 update_dir_chksum_with_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es);
|
s32 update_dir_chksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es);
|
||||||
bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir);
|
bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir);
|
||||||
s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr);
|
s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr);
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ void amap_destroy(struct super_block *sb);
|
||||||
|
|
||||||
/* amap_smart.c : (de)allocation functions */
|
/* amap_smart.c : (de)allocation functions */
|
||||||
s32 amap_fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain, int dest);
|
s32 amap_fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain, int dest);
|
||||||
s32 amap_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); /* Free a FAT chain (Not impelmented) */
|
s32 amap_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse);/* Not impelmented */
|
||||||
s32 amap_release_cluster(struct super_block *sb, u32 clu); /* Only update AMAP */
|
s32 amap_release_cluster(struct super_block *sb, u32 clu); /* Only update AMAP */
|
||||||
|
|
||||||
/* amap_smart.c : misc (for defrag) */
|
/* amap_smart.c : misc (for defrag) */
|
||||||
|
|
|
||||||
203
core_exfat.c
203
core_exfat.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -94,46 +92,44 @@ static u32 exfat_get_entry_type(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
||||||
|
|
||||||
if (ep->type == EXFAT_UNUSED) {
|
if (ep->type == EXFAT_UNUSED)
|
||||||
return TYPE_UNUSED;
|
return TYPE_UNUSED;
|
||||||
} else if (ep->type < 0x80) {
|
if (ep->type < 0x80)
|
||||||
return TYPE_DELETED;
|
return TYPE_DELETED;
|
||||||
} else if (ep->type == 0x80) {
|
if (ep->type == 0x80)
|
||||||
return TYPE_INVALID;
|
return TYPE_INVALID;
|
||||||
} else if (ep->type < 0xA0) {
|
if (ep->type < 0xA0) {
|
||||||
if (ep->type == 0x81) {
|
if (ep->type == 0x81)
|
||||||
return TYPE_BITMAP;
|
return TYPE_BITMAP;
|
||||||
} else if (ep->type == 0x82) {
|
if (ep->type == 0x82)
|
||||||
return TYPE_UPCASE;
|
return TYPE_UPCASE;
|
||||||
} else if (ep->type == 0x83) {
|
if (ep->type == 0x83)
|
||||||
return TYPE_VOLUME;
|
return TYPE_VOLUME;
|
||||||
} else if (ep->type == 0x85) {
|
if (ep->type == 0x85) {
|
||||||
if (le16_to_cpu(ep->attr) & ATTR_SUBDIR)
|
if (le16_to_cpu(ep->attr) & ATTR_SUBDIR)
|
||||||
return TYPE_DIR;
|
return TYPE_DIR;
|
||||||
else
|
return TYPE_FILE;
|
||||||
return TYPE_FILE;
|
|
||||||
}
|
}
|
||||||
return TYPE_CRITICAL_PRI;
|
return TYPE_CRITICAL_PRI;
|
||||||
} else if (ep->type < 0xC0) {
|
}
|
||||||
if (ep->type == 0xA0) {
|
if (ep->type < 0xC0) {
|
||||||
|
if (ep->type == 0xA0)
|
||||||
return TYPE_GUID;
|
return TYPE_GUID;
|
||||||
} else if (ep->type == 0xA1) {
|
if (ep->type == 0xA1)
|
||||||
return TYPE_PADDING;
|
return TYPE_PADDING;
|
||||||
} else if (ep->type == 0xA2) {
|
if (ep->type == 0xA2)
|
||||||
return TYPE_ACLTAB;
|
return TYPE_ACLTAB;
|
||||||
}
|
|
||||||
return TYPE_BENIGN_PRI;
|
return TYPE_BENIGN_PRI;
|
||||||
} else if (ep->type < 0xE0) {
|
}
|
||||||
if (ep->type == 0xC0) {
|
if (ep->type < 0xE0) {
|
||||||
|
if (ep->type == 0xC0)
|
||||||
return TYPE_STREAM;
|
return TYPE_STREAM;
|
||||||
} else if (ep->type == 0xC1) {
|
if (ep->type == 0xC1)
|
||||||
return TYPE_EXTEND;
|
return TYPE_EXTEND;
|
||||||
} else if (ep->type == 0xC2) {
|
if (ep->type == 0xC2)
|
||||||
return TYPE_ACL;
|
return TYPE_ACL;
|
||||||
}
|
|
||||||
return TYPE_CRITICAL_SEC;
|
return TYPE_CRITICAL_SEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TYPE_BENIGN_SEC;
|
return TYPE_BENIGN_SEC;
|
||||||
} /* end of exfat_get_entry_type */
|
} /* end of exfat_get_entry_type */
|
||||||
|
|
||||||
|
|
@ -169,49 +165,57 @@ static void exfat_set_entry_type(DENTRY_T *p_entry, u32 type)
|
||||||
|
|
||||||
static u32 exfat_get_entry_attr(DENTRY_T *p_entry)
|
static u32 exfat_get_entry_attr(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
|
||||||
return((u32) le16_to_cpu(ep->attr));
|
|
||||||
|
return (u32)le16_to_cpu(ep->attr);
|
||||||
} /* end of exfat_get_entry_attr */
|
} /* end of exfat_get_entry_attr */
|
||||||
|
|
||||||
static void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr)
|
static void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr)
|
||||||
{
|
{
|
||||||
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->attr = cpu_to_le16((u16) attr);
|
ep->attr = cpu_to_le16((u16) attr);
|
||||||
} /* end of exfat_set_entry_attr */
|
} /* end of exfat_set_entry_attr */
|
||||||
|
|
||||||
static u8 exfat_get_entry_flag(DENTRY_T *p_entry)
|
static u8 exfat_get_entry_flag(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
return(ep->flags);
|
|
||||||
|
return ep->flags;
|
||||||
} /* end of exfat_get_entry_flag */
|
} /* end of exfat_get_entry_flag */
|
||||||
|
|
||||||
static void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags)
|
static void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->flags = flags;
|
ep->flags = flags;
|
||||||
} /* end of exfat_set_entry_flag */
|
} /* end of exfat_set_entry_flag */
|
||||||
|
|
||||||
static u32 exfat_get_entry_clu0(DENTRY_T *p_entry)
|
static u32 exfat_get_entry_clu0(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
return le32_to_cpu(ep->start_clu);
|
|
||||||
|
return (u32)le32_to_cpu(ep->start_clu);
|
||||||
} /* end of exfat_get_entry_clu0 */
|
} /* end of exfat_get_entry_clu0 */
|
||||||
|
|
||||||
static void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu)
|
static void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->start_clu = cpu_to_le32(start_clu);
|
ep->start_clu = cpu_to_le32(start_clu);
|
||||||
} /* end of exfat_set_entry_clu0 */
|
} /* end of exfat_set_entry_clu0 */
|
||||||
|
|
||||||
static u64 exfat_get_entry_size(DENTRY_T *p_entry)
|
static u64 exfat_get_entry_size(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
return le64_to_cpu(ep->valid_size);
|
return le64_to_cpu(ep->valid_size);
|
||||||
} /* end of exfat_get_entry_size */
|
} /* end of exfat_get_entry_size */
|
||||||
|
|
||||||
static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size)
|
static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size)
|
||||||
{
|
{
|
||||||
STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
|
STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->valid_size = cpu_to_le64(size);
|
ep->valid_size = cpu_to_le64(size);
|
||||||
ep->size = cpu_to_le64(size);
|
ep->size = cpu_to_le64(size);
|
||||||
} /* end of exfat_set_entry_size */
|
} /* end of exfat_set_entry_size */
|
||||||
|
|
@ -219,7 +223,7 @@ static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size)
|
||||||
static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
||||||
{
|
{
|
||||||
u16 t = 0x00, d = 0x21;
|
u16 t = 0x00, d = 0x21;
|
||||||
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case TM_CREATE:
|
case TM_CREATE:
|
||||||
|
|
@ -247,7 +251,7 @@ static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
||||||
static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
||||||
{
|
{
|
||||||
u16 t, d;
|
u16 t, d;
|
||||||
FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
|
t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
|
||||||
d = (tp->year << 9) | (tp->mon << 5) | tp->day;
|
d = (tp->year << 9) | (tp->mon << 5) | tp->day;
|
||||||
|
|
@ -432,7 +436,8 @@ static s32 exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 en
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 __write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, u32 sec, s32 off, u32 count)
|
static s32 __write_partial_entries_in_entry_set(struct super_block *sb,
|
||||||
|
ENTRY_SET_CACHE_T *es, u32 sec, s32 off, u32 count)
|
||||||
{
|
{
|
||||||
s32 num_entries, buf_off = (off - es->offset);
|
s32 num_entries, buf_off = (off - es->offset);
|
||||||
u32 remaining_byte_in_sector, copy_entries;
|
u32 remaining_byte_in_sector, copy_entries;
|
||||||
|
|
@ -444,10 +449,10 @@ static s32 __write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_S
|
||||||
MMSG("%s: es %p sec %u off %d cnt %d\n", __func__, es, sec, off, count);
|
MMSG("%s: es %p sec %u off %d cnt %d\n", __func__, es, sec, off, count);
|
||||||
num_entries = count;
|
num_entries = count;
|
||||||
|
|
||||||
while(num_entries) {
|
while (num_entries) {
|
||||||
// white per sector base
|
/* write per sector base */
|
||||||
remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off;
|
remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off;
|
||||||
copy_entries = min((s32)(remaining_byte_in_sector>> DENTRY_SIZE_BITS) , num_entries);
|
copy_entries = min((s32)(remaining_byte_in_sector >> DENTRY_SIZE_BITS), num_entries);
|
||||||
buf = dcache_getblk(sb, sec);
|
buf = dcache_getblk(sb, sec);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
@ -484,18 +489,18 @@ err_out:
|
||||||
/* write back all entries in entry set */
|
/* write back all entries in entry set */
|
||||||
static s32 __write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es)
|
static s32 __write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es)
|
||||||
{
|
{
|
||||||
return __write_partial_entries_in_entry_set(sb, es, es->sector,es->offset, es->num_entries);
|
return __write_partial_entries_in_entry_set(sb, es, es->sector, es->offset, es->num_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 update_dir_chksum_with_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es)
|
s32 update_dir_chksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es)
|
||||||
{
|
{
|
||||||
DENTRY_T *ep;
|
DENTRY_T *ep;
|
||||||
u16 chksum = 0;
|
u16 chksum = 0;
|
||||||
s32 chksum_type = CS_DIR_ENTRY, i;
|
s32 chksum_type = CS_DIR_ENTRY, i;
|
||||||
|
|
||||||
ep = (DENTRY_T *)&(es->__buf);
|
ep = (DENTRY_T *)&(es->__buf);
|
||||||
for (i=0; i < es->num_entries; i++) {
|
for (i = 0; i < es->num_entries; i++) {
|
||||||
MMSG ("%s %p\n", __func__, ep);
|
MMSG("%s %p\n", __func__, ep);
|
||||||
chksum = calc_chksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type);
|
chksum = calc_chksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type);
|
||||||
ep++;
|
ep++;
|
||||||
chksum_type = CS_DEFAULT;
|
chksum_type = CS_DEFAULT;
|
||||||
|
|
@ -524,10 +529,11 @@ s32 update_dir_chksum_with_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T
|
||||||
#define ES_MODE_GET_STRM_ENTRY 2
|
#define ES_MODE_GET_STRM_ENTRY 2
|
||||||
#define ES_MODE_GET_NAME_ENTRY 3
|
#define ES_MODE_GET_NAME_ENTRY 3
|
||||||
#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4
|
#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4
|
||||||
ENTRY_SET_CACHE_T *get_dentry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep)
|
ENTRY_SET_CACHE_T *get_dentry_set_in_dir(struct super_block *sb,
|
||||||
|
CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep)
|
||||||
{
|
{
|
||||||
s32 off, ret, byte_offset;
|
s32 off, ret, byte_offset;
|
||||||
u32 clu=0;
|
u32 clu = 0;
|
||||||
u32 sec, entry_type;
|
u32 sec, entry_type;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
ENTRY_SET_CACHE_T *es = NULL;
|
ENTRY_SET_CACHE_T *es = NULL;
|
||||||
|
|
@ -593,15 +599,15 @@ ENTRY_SET_CACHE_T *get_dentry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir
|
||||||
|
|
||||||
pos = (DENTRY_T *) &(es->__buf);
|
pos = (DENTRY_T *) &(es->__buf);
|
||||||
|
|
||||||
while(num_entries) {
|
while (num_entries) {
|
||||||
// instead of copying whole sector, we will check every entry.
|
// instead of copying whole sector, we will check every entry.
|
||||||
// this will provide minimum stablity and consistancy.
|
// this will provide minimum stablity and consistency.
|
||||||
entry_type = exfat_get_entry_type(ep);
|
entry_type = exfat_get_entry_type(ep);
|
||||||
|
|
||||||
if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
|
if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
switch(mode) {
|
switch (mode) {
|
||||||
case ES_MODE_STARTED:
|
case ES_MODE_STARTED:
|
||||||
if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
|
if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
|
||||||
mode = ES_MODE_GET_FILE_ENTRY;
|
mode = ES_MODE_GET_FILE_ENTRY;
|
||||||
|
|
@ -644,8 +650,8 @@ ENTRY_SET_CACHE_T *get_dentry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir
|
||||||
if (--num_entries == 0)
|
if (--num_entries == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( ((off + DENTRY_SIZE) & (u32)(sb->s_blocksize - 1)) <
|
if (((off + DENTRY_SIZE) & (u32)(sb->s_blocksize - 1)) <
|
||||||
(off & (u32)(sb->s_blocksize - 1)) ) {
|
(off & (u32)(sb->s_blocksize - 1))) {
|
||||||
// get the next sector
|
// get the next sector
|
||||||
if (IS_LAST_SECT_IN_CLUS(fsi, sec)) {
|
if (IS_LAST_SECT_IN_CLUS(fsi, sec)) {
|
||||||
if (es->alloc_flag == 0x03)
|
if (es->alloc_flag == 0x03)
|
||||||
|
|
@ -677,20 +683,20 @@ ENTRY_SET_CACHE_T *get_dentry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir
|
||||||
return es;
|
return es;
|
||||||
err_out:
|
err_out:
|
||||||
TMSG("%s exited (return NULL) (es %p)\n", __func__, es);
|
TMSG("%s exited (return NULL) (es %p)\n", __func__, es);
|
||||||
if (es) {
|
|
||||||
kfree(es);
|
/* kfree(NULL) is safe */
|
||||||
es = NULL;
|
kfree(es);
|
||||||
}
|
es = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release_dentry_set (ENTRY_SET_CACHE_T *es)
|
void release_dentry_set(ENTRY_SET_CACHE_T *es)
|
||||||
{
|
{
|
||||||
TMSG("%s %p\n", __func__, es);
|
TMSG("%s %p\n", __func__, es);
|
||||||
if (es) {
|
|
||||||
kfree(es);
|
/* kfree(NULL) is safe */
|
||||||
es = NULL;
|
kfree(es);
|
||||||
}
|
es = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order)
|
static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order)
|
||||||
|
|
@ -701,14 +707,13 @@ static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s
|
||||||
/* FIXME : unaligned? */
|
/* FIXME : unaligned? */
|
||||||
*uniname = le16_to_cpu(ep->unicode_0_14[i]);
|
*uniname = le16_to_cpu(ep->unicode_0_14[i]);
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
return(len);
|
return len;
|
||||||
uniname++;
|
uniname++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*uniname = 0x0;
|
*uniname = 0x0;
|
||||||
return(len);
|
return len;
|
||||||
|
|
||||||
} /* end of __extract_uni_name_from_name_entry */
|
} /* end of __extract_uni_name_from_name_entry */
|
||||||
|
|
||||||
#define DIRENT_STEP_FILE (0)
|
#define DIRENT_STEP_FILE (0)
|
||||||
|
|
@ -722,7 +727,8 @@ static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s
|
||||||
* -ENOENT : entry with the name does not exist
|
* -ENOENT : entry with the name does not exist
|
||||||
* -EIO : I/O error
|
* -EIO : I/O error
|
||||||
*/
|
*/
|
||||||
static s32 exfat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *unused, u32 type)
|
static s32 exfat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid,
|
||||||
|
CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *unused, u32 type)
|
||||||
{
|
{
|
||||||
s32 i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
|
s32 i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
|
||||||
s32 order, step, name_len;
|
s32 order, step, name_len;
|
||||||
|
|
@ -909,6 +915,7 @@ found:
|
||||||
/* next dentry we'll find is out of this cluster */
|
/* next dentry we'll find is out of this cluster */
|
||||||
if (!((dentry + 1) & (dentries_per_clu-1))) {
|
if (!((dentry + 1) & (dentries_per_clu-1))) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (clu.flags == 0x03) {
|
if (clu.flags == 0x03) {
|
||||||
if ((--clu.size) > 0)
|
if ((--clu.size) > 0)
|
||||||
clu.dir++;
|
clu.dir++;
|
||||||
|
|
@ -945,11 +952,10 @@ static s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 e
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
type = exfat_get_entry_type(ext_ep);
|
type = exfat_get_entry_type(ext_ep);
|
||||||
if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) {
|
if ((type == TYPE_EXTEND) || (type == TYPE_STREAM))
|
||||||
count++;
|
count++;
|
||||||
} else {
|
else
|
||||||
return count;
|
return count;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
@ -1006,6 +1012,15 @@ static s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname)
|
||||||
|
|
||||||
} /* end of exfat_calc_num_entries */
|
} /* end of exfat_calc_num_entries */
|
||||||
|
|
||||||
|
static s32 exfat_check_max_dentries(FILE_ID_T *fid)
|
||||||
|
{
|
||||||
|
if ((fid->size >> DENTRY_SIZE_BITS) >= MAX_EXFAT_DENTRIES) {
|
||||||
|
/* exFAT spec allows a dir to grow upto 8388608(256MB) dentries */
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} /* end of check_max_dentries */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocation Bitmap Management Functions
|
* Allocation Bitmap Management Functions
|
||||||
|
|
@ -1013,7 +1028,7 @@ static s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname)
|
||||||
s32 load_alloc_bmp(struct super_block *sb)
|
s32 load_alloc_bmp(struct super_block *sb)
|
||||||
{
|
{
|
||||||
s32 i, j, ret;
|
s32 i, j, ret;
|
||||||
u32 map_size;
|
u32 map_size, need_map_size;
|
||||||
u32 type, sector;
|
u32 type, sector;
|
||||||
CHAIN_T clu;
|
CHAIN_T clu;
|
||||||
BMAP_DENTRY_T *ep;
|
BMAP_DENTRY_T *ep;
|
||||||
|
|
@ -1039,8 +1054,18 @@ s32 load_alloc_bmp(struct super_block *sb)
|
||||||
fsi->map_clu = le32_to_cpu(ep->start_clu);
|
fsi->map_clu = le32_to_cpu(ep->start_clu);
|
||||||
map_size = (u32) le64_to_cpu(ep->size);
|
map_size = (u32) le64_to_cpu(ep->size);
|
||||||
|
|
||||||
fsi->map_sectors = ((map_size-1) >> (sb->s_blocksize_bits)) + 1;
|
need_map_size = (((fsi->num_clusters - CLUS_BASE) - 1) >> 3) + 1;
|
||||||
fsi->vol_amap = (struct buffer_head **) kmalloc((sizeof(struct buffer_head *) * fsi->map_sectors), GFP_KERNEL);
|
if (need_map_size != map_size) {
|
||||||
|
sdfat_log_msg(sb, KERN_ERR,
|
||||||
|
"bogus allocation bitmap size(need : %u, cur : %u)",
|
||||||
|
need_map_size, map_size);
|
||||||
|
/* Only allowed when bogus allocation bitmap size is large */
|
||||||
|
if (need_map_size > map_size)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
fsi->map_sectors = ((need_map_size - 1) >> (sb->s_blocksize_bits)) + 1;
|
||||||
|
fsi->vol_amap =
|
||||||
|
kmalloc((sizeof(struct buffer_head *) * fsi->map_sectors), GFP_KERNEL);
|
||||||
if (!fsi->vol_amap)
|
if (!fsi->vol_amap)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
@ -1051,14 +1076,13 @@ s32 load_alloc_bmp(struct super_block *sb)
|
||||||
ret = read_sect(sb, sector+j, &(fsi->vol_amap[j]), 1);
|
ret = read_sect(sb, sector+j, &(fsi->vol_amap[j]), 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* release all buffers and free vol_amap */
|
/* release all buffers and free vol_amap */
|
||||||
i=0;
|
i = 0;
|
||||||
while (i < j)
|
while (i < j)
|
||||||
brelse(fsi->vol_amap[i++]);
|
brelse(fsi->vol_amap[i++]);
|
||||||
|
|
||||||
if (fsi->vol_amap) {
|
/* kfree(NULL) is safe */
|
||||||
kfree(fsi->vol_amap);
|
kfree(fsi->vol_amap);
|
||||||
fsi->vol_amap = NULL;
|
fsi->vol_amap = NULL;
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1082,14 +1106,12 @@ void free_alloc_bmp(struct super_block *sb)
|
||||||
|
|
||||||
brelse(fsi->pbr_bh);
|
brelse(fsi->pbr_bh);
|
||||||
|
|
||||||
for (i = 0; i < fsi->map_sectors; i++) {
|
for (i = 0; i < fsi->map_sectors; i++)
|
||||||
__brelse(fsi->vol_amap[i]);
|
__brelse(fsi->vol_amap[i]);
|
||||||
}
|
|
||||||
|
|
||||||
if(fsi->vol_amap) {
|
/* kfree(NULL) is safe */
|
||||||
kfree(fsi->vol_amap);
|
kfree(fsi->vol_amap);
|
||||||
fsi->vol_amap = NULL;
|
fsi->vol_amap = NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WARN :
|
/* WARN :
|
||||||
|
|
@ -1106,8 +1128,7 @@ static s32 set_alloc_bitmap(struct super_block *sb, u32 clu)
|
||||||
b = clu & (u32)((sb->s_blocksize << 3) - 1);
|
b = clu & (u32)((sb->s_blocksize << 3) - 1);
|
||||||
|
|
||||||
sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
|
sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
|
||||||
|
bitmap_set((unsigned long *)(fsi->vol_amap[i]->b_data), b, 1);
|
||||||
bitmap_set((unsigned long*)(fsi->vol_amap[i]->b_data), b, 1);
|
|
||||||
|
|
||||||
return write_sect(sb, sector, fsi->vol_amap[i], 0);
|
return write_sect(sb, sector, fsi->vol_amap[i], 0);
|
||||||
} /* end of set_alloc_bitmap */
|
} /* end of set_alloc_bitmap */
|
||||||
|
|
@ -1130,12 +1151,13 @@ static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu)
|
||||||
|
|
||||||
sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
|
sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
|
||||||
|
|
||||||
bitmap_clear((unsigned long*)(fsi->vol_amap[i]->b_data), b, 1);
|
bitmap_clear((unsigned long *)(fsi->vol_amap[i]->b_data), b, 1);
|
||||||
|
|
||||||
ret = write_sect(sb, sector, fsi->vol_amap[i], 0);
|
ret = write_sect(sb, sector, fsi->vol_amap[i], 0);
|
||||||
|
|
||||||
if (opts->discard) {
|
if (opts->discard) {
|
||||||
s32 ret_discard;
|
s32 ret_discard;
|
||||||
|
|
||||||
TMSG("discard cluster(%08x)\n", clu+2);
|
TMSG("discard cluster(%08x)\n", clu+2);
|
||||||
ret_discard = sb_issue_discard(sb, CLUS_TO_SECT(fsi, clu+2),
|
ret_discard = sb_issue_discard(sb, CLUS_TO_SECT(fsi, clu+2),
|
||||||
(1 << fsi->sect_per_clus_bits), GFP_NOFS, 0);
|
(1 << fsi->sect_per_clus_bits), GFP_NOFS, 0);
|
||||||
|
|
@ -1254,7 +1276,7 @@ static s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
hint_clu = 2;
|
hint_clu = 2;
|
||||||
if (p_chain->flags == 0x03) {
|
if (p_chain->flags == 0x03) {
|
||||||
if (exfat_chain_cont_cluster( sb, p_chain->dir, num_clusters))
|
if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
p_chain->flags = 0x01;
|
p_chain->flags = 0x01;
|
||||||
}
|
}
|
||||||
|
|
@ -1265,8 +1287,8 @@ static s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p
|
||||||
p_chain->dir = CLUS_EOF;
|
p_chain->dir = CLUS_EOF;
|
||||||
|
|
||||||
while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUS_EOF) {
|
while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUS_EOF) {
|
||||||
if ( (new_clu != hint_clu) && (p_chain->flags == 0x03) ) {
|
if ((new_clu != hint_clu) && (p_chain->flags == 0x03)) {
|
||||||
if (exfat_chain_cont_cluster( sb, p_chain->dir, num_clusters))
|
if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
p_chain->flags = 0x01;
|
p_chain->flags = 0x01;
|
||||||
}
|
}
|
||||||
|
|
@ -1395,7 +1417,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
} /* end of exfat_free_cluster */
|
} /* end of exfat_free_cluster */
|
||||||
|
|
||||||
static s32 exfat_count_used_clusters(struct super_block *sb, u32* ret_count)
|
static s32 exfat_count_used_clusters(struct super_block *sb, u32 *ret_count)
|
||||||
{
|
{
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
u32 i, map_i, map_b;
|
u32 i, map_i, map_b;
|
||||||
|
|
@ -1406,8 +1428,8 @@ static s32 exfat_count_used_clusters(struct super_block *sb, u32* ret_count)
|
||||||
|
|
||||||
for (i = 0; i < total_clus; i += 8) {
|
for (i = 0; i < total_clus; i += 8) {
|
||||||
u8 k = *(((u8 *) fsi->vol_amap[map_i]->b_data) + map_b);
|
u8 k = *(((u8 *) fsi->vol_amap[map_i]->b_data) + map_b);
|
||||||
count += used_bit[k];
|
|
||||||
|
|
||||||
|
count += used_bit[k];
|
||||||
if ((++map_b) >= (u32)sb->s_blocksize) {
|
if ((++map_b) >= (u32)sb->s_blocksize) {
|
||||||
map_i++;
|
map_i++;
|
||||||
map_b = 0;
|
map_b = 0;
|
||||||
|
|
@ -1438,6 +1460,7 @@ static FS_FUNC_T exfat_fs_func = {
|
||||||
.get_uniname_from_ext_entry = exfat_get_uniname_from_ext_entry,
|
.get_uniname_from_ext_entry = exfat_get_uniname_from_ext_entry,
|
||||||
.count_ext_entries = exfat_count_ext_entries,
|
.count_ext_entries = exfat_count_ext_entries,
|
||||||
.calc_num_entries = exfat_calc_num_entries,
|
.calc_num_entries = exfat_calc_num_entries,
|
||||||
|
.check_max_dentries = exfat_check_max_dentries,
|
||||||
|
|
||||||
.get_entry_type = exfat_get_entry_type,
|
.get_entry_type = exfat_get_entry_type,
|
||||||
.set_entry_type = exfat_set_entry_type,
|
.set_entry_type = exfat_set_entry_type,
|
||||||
|
|
|
||||||
123
core_fat.c
123
core_fat.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -252,14 +250,17 @@ static s32 fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_rel
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = clu;
|
prev = clu;
|
||||||
if (get_next_clus(sb, &clu))
|
if (get_next_clus_safe(sb, &clu)) {
|
||||||
goto out;
|
/* print more helpful log */
|
||||||
|
if (IS_CLUS_BAD(clu)) {
|
||||||
/* FAT validity check */
|
sdfat_log_msg(sb, KERN_ERR, "%s : "
|
||||||
if (IS_CLUS_FREE(clu)) {
|
"deleting bad cluster (clu[%u]->BAD)",
|
||||||
/* GRACEFUL ERROR HANDLING */
|
__func__, prev);
|
||||||
/* Broken FAT chain (Already FREE) */
|
} else if (IS_CLUS_FREE(clu)) {
|
||||||
sdfat_fs_error(sb, "%s : deleting FAT entry beyond EOF (clu[%u]->0)", __func__, prev);
|
sdfat_log_msg(sb, KERN_ERR, "%s : "
|
||||||
|
"deleting free cluster (clu[%u]->FREE)",
|
||||||
|
__func__, prev);
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,8 +269,10 @@ static s32 fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_rel
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Update AMAP if needed */
|
/* Update AMAP if needed */
|
||||||
if (fsi->amap)
|
if (fsi->amap) {
|
||||||
amap_release_cluster(sb, prev);
|
if (amap_release_cluster(sb, prev))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
num_clusters++;
|
num_clusters++;
|
||||||
|
|
||||||
|
|
@ -283,7 +286,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
} /* end of fat_free_cluster */
|
} /* end of fat_free_cluster */
|
||||||
|
|
||||||
static s32 fat_count_used_clusters(struct super_block *sb, u32* ret_count)
|
static s32 fat_count_used_clusters(struct super_block *sb, u32 *ret_count)
|
||||||
{
|
{
|
||||||
s32 i;
|
s32 i;
|
||||||
u32 clu, count = 0;
|
u32 clu, count = 0;
|
||||||
|
|
@ -307,7 +310,7 @@ static s32 fat_count_used_clusters(struct super_block *sb, u32* ret_count)
|
||||||
*/
|
*/
|
||||||
static u32 fat_get_entry_type(DENTRY_T *p_entry)
|
static u32 fat_get_entry_type(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
/* first byte of 32bytes dummy */
|
/* first byte of 32bytes dummy */
|
||||||
if (*(ep->name) == MSDOS_UNUSED)
|
if (*(ep->name) == MSDOS_UNUSED)
|
||||||
|
|
@ -335,7 +338,7 @@ static u32 fat_get_entry_type(DENTRY_T *p_entry)
|
||||||
|
|
||||||
static void fat_set_entry_type(DENTRY_T *p_entry, u32 type)
|
static void fat_set_entry_type(DENTRY_T *p_entry, u32 type)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
if (type == TYPE_UNUSED)
|
if (type == TYPE_UNUSED)
|
||||||
*(ep->name) = MSDOS_UNUSED; /* 0x0 */
|
*(ep->name) = MSDOS_UNUSED; /* 0x0 */
|
||||||
|
|
@ -358,14 +361,16 @@ static void fat_set_entry_type(DENTRY_T *p_entry, u32 type)
|
||||||
|
|
||||||
static u32 fat_get_entry_attr(DENTRY_T *p_entry)
|
static u32 fat_get_entry_attr(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
return((u32) ep->attr);
|
|
||||||
|
return (u32)ep->attr;
|
||||||
} /* end of fat_get_entry_attr */
|
} /* end of fat_get_entry_attr */
|
||||||
|
|
||||||
static void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr)
|
static void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
ep->attr = (u8) attr;
|
|
||||||
|
ep->attr = (u8)attr;
|
||||||
} /* end of fat_set_entry_attr */
|
} /* end of fat_set_entry_attr */
|
||||||
|
|
||||||
static u8 fat_get_entry_flag(DENTRY_T *p_entry)
|
static u8 fat_get_entry_flag(DENTRY_T *p_entry)
|
||||||
|
|
@ -379,27 +384,30 @@ static void fat_set_entry_flag(DENTRY_T *p_entry, u8 flags)
|
||||||
|
|
||||||
static u32 fat_get_entry_clu0(DENTRY_T *p_entry)
|
static u32 fat_get_entry_clu0(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
/* FIXME : is ok? */
|
/* FIXME : is ok? */
|
||||||
return(((u32)(le16_to_cpu(ep->start_clu_hi)) << 16) | le16_to_cpu(ep->start_clu_lo));
|
return(((u32)(le16_to_cpu(ep->start_clu_hi)) << 16) | le16_to_cpu(ep->start_clu_lo));
|
||||||
} /* end of fat_get_entry_clu0 */
|
} /* end of fat_get_entry_clu0 */
|
||||||
|
|
||||||
static void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu)
|
static void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->start_clu_lo = cpu_to_le16(CLUSTER_16(start_clu));
|
ep->start_clu_lo = cpu_to_le16(CLUSTER_16(start_clu));
|
||||||
ep->start_clu_hi = cpu_to_le16(CLUSTER_16(start_clu >> 16));
|
ep->start_clu_hi = cpu_to_le16(CLUSTER_16(start_clu >> 16));
|
||||||
} /* end of fat_set_entry_clu0 */
|
} /* end of fat_set_entry_clu0 */
|
||||||
|
|
||||||
static u64 fat_get_entry_size(DENTRY_T *p_entry)
|
static u64 fat_get_entry_size(DENTRY_T *p_entry)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
return((u64) le32_to_cpu(ep->size));
|
|
||||||
|
return (u64)le32_to_cpu(ep->size);
|
||||||
} /* end of fat_get_entry_size */
|
} /* end of fat_get_entry_size */
|
||||||
|
|
||||||
static void fat_set_entry_size(DENTRY_T *p_entry, u64 size)
|
static void fat_set_entry_size(DENTRY_T *p_entry, u64 size)
|
||||||
{
|
{
|
||||||
DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
|
DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
ep->size = cpu_to_le32((u32)size);
|
ep->size = cpu_to_le32((u32)size);
|
||||||
} /* end of fat_set_entry_size */
|
} /* end of fat_set_entry_size */
|
||||||
|
|
||||||
|
|
@ -488,7 +496,7 @@ static void __init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uninam
|
||||||
}
|
}
|
||||||
|
|
||||||
/* aligned name */
|
/* aligned name */
|
||||||
for (i = 0; i < 6; i ++) {
|
for (i = 0; i < 6; i++) {
|
||||||
if (!end) {
|
if (!end) {
|
||||||
ep->unicode_5_10[i] = cpu_to_le16(*uniname);
|
ep->unicode_5_10[i] = cpu_to_le16(*uniname);
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
|
|
@ -608,7 +616,8 @@ static inline s32 __get_dentries_per_clu(FS_INFO_T *fsi, s32 clu)
|
||||||
return fsi->dentries_per_clu;
|
return fsi->dentries_per_clu;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 fat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type)
|
static s32 fat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid,
|
||||||
|
CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type)
|
||||||
{
|
{
|
||||||
s32 i, rewind = 0, dentry = 0, end_eidx = 0;
|
s32 i, rewind = 0, dentry = 0, end_eidx = 0;
|
||||||
s32 chksum = 0, lfn_ord = 0, lfn_len = 0;
|
s32 chksum = 0, lfn_ord = 0, lfn_len = 0;
|
||||||
|
|
@ -685,8 +694,8 @@ rewind:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* invalid lfn order */
|
/* invalid lfn order */
|
||||||
if ( !cur_ord || (cur_ord > MAX_LFN_ORDER) ||
|
if (!cur_ord || (cur_ord > MAX_LFN_ORDER) ||
|
||||||
((cur_ord + 1) != lfn_ord) )
|
((cur_ord + 1) != lfn_ord))
|
||||||
goto reset_dentry_set;
|
goto reset_dentry_set;
|
||||||
|
|
||||||
/* check checksum of directory entry set */
|
/* check checksum of directory entry set */
|
||||||
|
|
@ -702,7 +711,7 @@ rewind:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!uniname) {
|
if (!uniname) {
|
||||||
sdfat_fs_error(sb,
|
sdfat_fs_error(sb,
|
||||||
"%s : abnormal dentry "
|
"%s : abnormal dentry "
|
||||||
"(start_clu[%u], "
|
"(start_clu[%u], "
|
||||||
|
|
@ -760,16 +769,16 @@ rewind:
|
||||||
*/
|
*/
|
||||||
if (!lfn_len || (cur_chksum != chksum)) {
|
if (!lfn_len || (cur_chksum != chksum)) {
|
||||||
/* check shortname */
|
/* check shortname */
|
||||||
if ( (p_dosname->name[0] != '\0') &&
|
if ((p_dosname->name[0] != '\0') &&
|
||||||
!nls_cmp_sfn(sb,
|
!nls_cmp_sfn(sb,
|
||||||
p_dosname->name,
|
p_dosname->name,
|
||||||
dos_ep->name) ) {
|
dos_ep->name)) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
/* check name length */
|
/* check name length */
|
||||||
} else if ( (lfn_len > 0) &&
|
} else if ((lfn_len > 0) &&
|
||||||
((s32)p_uniname->name_len ==
|
((s32)p_uniname->name_len ==
|
||||||
lfn_len) ) {
|
lfn_len)) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -872,12 +881,12 @@ static s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 ent
|
||||||
chksum = calc_chksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0);
|
chksum = calc_chksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0);
|
||||||
|
|
||||||
for (entry--; entry >= 0; entry--) {
|
for (entry--; entry >= 0; entry--) {
|
||||||
ext_ep = (EXT_DENTRY_T*)get_dentry_in_dir(sb,p_dir,entry,NULL);
|
ext_ep = (EXT_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, NULL);
|
||||||
if (!ext_ep)
|
if (!ext_ep)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if ( (fat_get_entry_type((DENTRY_T*)ext_ep) == TYPE_EXTEND) &&
|
if ((fat_get_entry_type((DENTRY_T *)ext_ep) == TYPE_EXTEND) &&
|
||||||
(ext_ep->checksum == chksum) ) {
|
(ext_ep->checksum == chksum)) {
|
||||||
count++;
|
count++;
|
||||||
if (ext_ep->order > MSDOS_LAST_LFN)
|
if (ext_ep->order > MSDOS_LAST_LFN)
|
||||||
return count;
|
return count;
|
||||||
|
|
@ -900,7 +909,7 @@ static s32 __extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
*uniname = get_unaligned_le16(&(ep->unicode_0_4[i<<1]));
|
*uniname = get_unaligned_le16(&(ep->unicode_0_4[i<<1]));
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
return(len);
|
return len;
|
||||||
uniname++;
|
uniname++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
@ -910,7 +919,7 @@ static s32 __extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32
|
||||||
/* FIXME : unaligned? */
|
/* FIXME : unaligned? */
|
||||||
*uniname = le16_to_cpu(ep->unicode_5_10[i]);
|
*uniname = le16_to_cpu(ep->unicode_5_10[i]);
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
return(len);
|
return len;
|
||||||
uniname++;
|
uniname++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
@ -919,25 +928,25 @@ static s32 __extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32
|
||||||
/* FIXME : unaligned? */
|
/* FIXME : unaligned? */
|
||||||
*uniname = le16_to_cpu(ep->unicode_5_10[i]);
|
*uniname = le16_to_cpu(ep->unicode_5_10[i]);
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
return(len);
|
return len;
|
||||||
uniname++;
|
uniname++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
*uniname = 0x0; /* uniname[MAX_NAME_LENGTH] */
|
*uniname = 0x0; /* uniname[MAX_NAME_LENGTH] */
|
||||||
return(len);
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
/* FIXME : unaligned? */
|
/* FIXME : unaligned? */
|
||||||
*uniname = le16_to_cpu(ep->unicode_11_12[i]);
|
*uniname = le16_to_cpu(ep->unicode_11_12[i]);
|
||||||
if (*uniname == 0x0)
|
if (*uniname == 0x0)
|
||||||
return(len);
|
return len;
|
||||||
uniname++;
|
uniname++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*uniname = 0x0;
|
*uniname = 0x0;
|
||||||
return(len);
|
return len;
|
||||||
|
|
||||||
} /* end of __extract_uni_name_from_ext_entry */
|
} /* end of __extract_uni_name_from_ext_entry */
|
||||||
|
|
||||||
|
|
@ -959,6 +968,7 @@ static void fat_get_uniname_from_ext_entry(struct super_block *sb, CHAIN_T *p_di
|
||||||
|
|
||||||
for (entry--, i = 1; entry >= 0; entry--, i++) {
|
for (entry--, i = 1; entry >= 0; entry--, i++) {
|
||||||
EXT_DENTRY_T *ep;
|
EXT_DENTRY_T *ep;
|
||||||
|
|
||||||
ep = (EXT_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, NULL);
|
ep = (EXT_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, NULL);
|
||||||
if (!ep)
|
if (!ep)
|
||||||
goto invalid_lfn;
|
goto invalid_lfn;
|
||||||
|
|
@ -980,13 +990,13 @@ static void fat_get_uniname_from_ext_entry(struct super_block *sb, CHAIN_T *p_di
|
||||||
}
|
}
|
||||||
invalid_lfn:
|
invalid_lfn:
|
||||||
*uniname = (u16)0x0;
|
*uniname = (u16)0x0;
|
||||||
return;
|
|
||||||
} /* end of fat_get_uniname_from_ext_entry */
|
} /* end of fat_get_uniname_from_ext_entry */
|
||||||
|
|
||||||
/* Find if the shortname exists
|
/* Find if the shortname exists
|
||||||
and check if there are free entries
|
* and check if there are free entries
|
||||||
*/
|
*/
|
||||||
static s32 __fat_find_shortname_entry(struct super_block *sb, CHAIN_T *p_dir, u8 *p_dosname, s32 *offset, __attribute__((unused))int n_entry_needed)
|
static s32 __fat_find_shortname_entry(struct super_block *sb, CHAIN_T *p_dir,
|
||||||
|
u8 *p_dosname, s32 *offset, __attribute__((unused))int n_entry_needed)
|
||||||
{
|
{
|
||||||
u32 type;
|
u32 type;
|
||||||
s32 i, dentry = 0;
|
s32 i, dentry = 0;
|
||||||
|
|
@ -1004,7 +1014,7 @@ static s32 __fat_find_shortname_entry(struct super_block *sb, CHAIN_T *p_dir, u8
|
||||||
else
|
else
|
||||||
dentries_per_clu = fsi->dentries_per_clu;
|
dentries_per_clu = fsi->dentries_per_clu;
|
||||||
|
|
||||||
while(!IS_CLUS_EOF(clu.dir)) {
|
while (!IS_CLUS_EOF(clu.dir)) {
|
||||||
for (i = 0; i < dentries_per_clu; i++, dentry++) {
|
for (i = 0; i < dentries_per_clu; i++, dentry++) {
|
||||||
ep = get_dentry_in_dir(sb, &clu, i, NULL);
|
ep = get_dentry_in_dir(sb, &clu, i, NULL);
|
||||||
if (!ep)
|
if (!ep)
|
||||||
|
|
@ -1072,8 +1082,9 @@ s32 fat_generate_dos_name_new(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T
|
||||||
memset(work, ' ', DOS_NAME_LENGTH);
|
memset(work, ' ', DOS_NAME_LENGTH);
|
||||||
memcpy(work, p_dosname->name, DOS_NAME_LENGTH);
|
memcpy(work, p_dosname->name, DOS_NAME_LENGTH);
|
||||||
|
|
||||||
while(baselen && (work[--baselen] == ' '));
|
while (baselen && (work[--baselen] == ' ')) {
|
||||||
|
/* DO NOTHING, JUST FOR CHECK_PATCH */
|
||||||
|
}
|
||||||
|
|
||||||
if (baselen > 6)
|
if (baselen > 6)
|
||||||
baselen = 6;
|
baselen = 6;
|
||||||
|
|
@ -1141,6 +1152,14 @@ static s32 fat_calc_num_entries(UNI_NAME_T *p_uniname)
|
||||||
|
|
||||||
} /* end of calc_num_enties */
|
} /* end of calc_num_enties */
|
||||||
|
|
||||||
|
static s32 fat_check_max_dentries(FILE_ID_T *fid)
|
||||||
|
{
|
||||||
|
if ((fid->size >> DENTRY_SIZE_BITS) >= MAX_FAT_DENTRIES) {
|
||||||
|
/* FAT spec allows a dir to grow upto 65536 dentries */
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} /* end of check_max_dentries */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1158,6 +1177,7 @@ static FS_FUNC_T fat_fs_func = {
|
||||||
.get_uniname_from_ext_entry = fat_get_uniname_from_ext_entry,
|
.get_uniname_from_ext_entry = fat_get_uniname_from_ext_entry,
|
||||||
.count_ext_entries = fat_count_ext_entries,
|
.count_ext_entries = fat_count_ext_entries,
|
||||||
.calc_num_entries = fat_calc_num_entries,
|
.calc_num_entries = fat_calc_num_entries,
|
||||||
|
.check_max_dentries = fat_check_max_dentries,
|
||||||
|
|
||||||
.get_entry_type = fat_get_entry_type,
|
.get_entry_type = fat_get_entry_type,
|
||||||
.set_entry_type = fat_set_entry_type,
|
.set_entry_type = fat_set_entry_type,
|
||||||
|
|
@ -1185,6 +1205,7 @@ static FS_FUNC_T amap_fat_fs_func = {
|
||||||
.get_uniname_from_ext_entry = fat_get_uniname_from_ext_entry,
|
.get_uniname_from_ext_entry = fat_get_uniname_from_ext_entry,
|
||||||
.count_ext_entries = fat_count_ext_entries,
|
.count_ext_entries = fat_count_ext_entries,
|
||||||
.calc_num_entries = fat_calc_num_entries,
|
.calc_num_entries = fat_calc_num_entries,
|
||||||
|
.check_max_dentries = fat_check_max_dentries,
|
||||||
|
|
||||||
.get_entry_type = fat_get_entry_type,
|
.get_entry_type = fat_get_entry_type,
|
||||||
.set_entry_type = fat_set_entry_type,
|
.set_entry_type = fat_set_entry_type,
|
||||||
|
|
@ -1413,7 +1434,7 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr)
|
||||||
|
|
||||||
/* Check dependency of mount options */
|
/* Check dependency of mount options */
|
||||||
if (SDFAT_SB(sb)->options.improved_allocation !=
|
if (SDFAT_SB(sb)->options.improved_allocation !=
|
||||||
(SDFAT_ALLOC_DELAY | SDFAT_ALLOC_SMART) ) {
|
(SDFAT_ALLOC_DELAY | SDFAT_ALLOC_SMART)) {
|
||||||
sdfat_log_msg(sb, KERN_INFO, "disabling defragmentation because"
|
sdfat_log_msg(sb, KERN_INFO, "disabling defragmentation because"
|
||||||
" smart, delay options are disabled");
|
" smart, delay options are disabled");
|
||||||
SDFAT_SB(sb)->options.defrag = 0;
|
SDFAT_SB(sb)->options.defrag = 0;
|
||||||
|
|
|
||||||
124
dfr.c
124
dfr.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -62,7 +60,7 @@ defrag_get_info(
|
||||||
arg->total_sec = fsi->num_sectors;
|
arg->total_sec = fsi->num_sectors;
|
||||||
arg->fat_offset_sec = fsi->FAT1_start_sector;
|
arg->fat_offset_sec = fsi->FAT1_start_sector;
|
||||||
arg->fat_sz_sec = fsi->num_FAT_sectors;
|
arg->fat_sz_sec = fsi->num_FAT_sectors;
|
||||||
arg->n_fat = (fsi->FAT1_start_sector == fsi->FAT2_start_sector)? 1:2;
|
arg->n_fat = (fsi->FAT1_start_sector == fsi->FAT2_start_sector) ? 1 : 2;
|
||||||
|
|
||||||
arg->sec_per_au = amap->option.au_size;
|
arg->sec_per_au = amap->option.au_size;
|
||||||
arg->hidden_sectors = amap->option.au_align_factor % amap->option.au_size;
|
arg->hidden_sectors = amap->option.au_align_factor % amap->option.au_size;
|
||||||
|
|
@ -139,7 +137,7 @@ error:
|
||||||
* @return 0 on success, -errno otherwise
|
* @return 0 on success, -errno otherwise
|
||||||
* @param sb super block
|
* @param sb super block
|
||||||
* @param args traverse args
|
* @param args traverse args
|
||||||
* @remark protected by i_mutex, super_block and volume lock
|
* @remark protected by inode_lock, super_block and volume lock
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
defrag_scan_dir(
|
defrag_scan_dir(
|
||||||
|
|
@ -149,7 +147,7 @@ defrag_scan_dir(
|
||||||
struct sdfat_sb_info *sbi = NULL;
|
struct sdfat_sb_info *sbi = NULL;
|
||||||
FS_INFO_T *fsi = NULL;
|
FS_INFO_T *fsi = NULL;
|
||||||
struct defrag_trav_header *header = NULL;
|
struct defrag_trav_header *header = NULL;
|
||||||
IN DOS_DENTRY_T *dos_ep;
|
DOS_DENTRY_T *dos_ep;
|
||||||
CHAIN_T chain;
|
CHAIN_T chain;
|
||||||
int dot_found = 0, args_idx = DFR_TRAV_HEADER_IDX + 1, clus = 0, index = 0;
|
int dot_found = 0, args_idx = DFR_TRAV_HEADER_IDX + 1, clus = 0, index = 0;
|
||||||
int err = 0, j = 0;
|
int err = 0, j = 0;
|
||||||
|
|
@ -188,7 +186,7 @@ defrag_scan_dir(
|
||||||
/* For more-scan case */
|
/* For more-scan case */
|
||||||
if ((header->stat == DFR_TRAV_STAT_MORE) &&
|
if ((header->stat == DFR_TRAV_STAT_MORE) &&
|
||||||
(header->start_clus == sbi->dfr_hint_clus) &&
|
(header->start_clus == sbi->dfr_hint_clus) &&
|
||||||
(sbi->dfr_hint_idx > 0) ) {
|
(sbi->dfr_hint_idx > 0)) {
|
||||||
|
|
||||||
index = sbi->dfr_hint_idx;
|
index = sbi->dfr_hint_idx;
|
||||||
for (j = 0; j < (sbi->dfr_hint_idx / fsi->dentries_per_clu); j++) {
|
for (j = 0; j < (sbi->dfr_hint_idx / fsi->dentries_per_clu); j++) {
|
||||||
|
|
@ -236,7 +234,7 @@ scan_fat_chain:
|
||||||
err = __defrag_scan_dir(sb, dos_ep, i_pos, &args[args_idx]);
|
err = __defrag_scan_dir(sb, dos_ep, i_pos, &args[args_idx]);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
/* More-scan case */
|
/* More-scan case */
|
||||||
if ( ++args_idx >= (PAGE_SIZE / sizeof(struct defrag_trav_arg)) ) {
|
if (++args_idx >= (PAGE_SIZE / sizeof(struct defrag_trav_arg))) {
|
||||||
sbi->dfr_hint_clus = header->start_clus;
|
sbi->dfr_hint_clus = header->start_clus;
|
||||||
sbi->dfr_hint_idx = clus * fsi->dentries_per_clu + index + 1;
|
sbi->dfr_hint_idx = clus * fsi->dentries_per_clu + index + 1;
|
||||||
|
|
||||||
|
|
@ -252,10 +250,10 @@ scan_fat_chain:
|
||||||
/* End case */
|
/* End case */
|
||||||
} else if (err == -ENOENT) {
|
} else if (err == -ENOENT) {
|
||||||
sbi->dfr_hint_clus = sbi->dfr_hint_idx = 0;
|
sbi->dfr_hint_clus = sbi->dfr_hint_idx = 0;
|
||||||
err = 0;
|
err = 0;
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
;
|
/* DO NOTHING */
|
||||||
}
|
}
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +367,7 @@ __defrag_check_au(
|
||||||
{
|
{
|
||||||
unsigned int nr_free = amap_get_freeclus(sb, clus);
|
unsigned int nr_free = amap_get_freeclus(sb, clus);
|
||||||
|
|
||||||
#if defined(CONFIG_SDFAT_DFR_DEBUG) || defined(CONFIG_SDFAT_DBG_MSG)
|
#if defined(CONFIG_SDFAT_DFR_DEBUG) && defined(CONFIG_SDFAT_DBG_MSG)
|
||||||
if (nr_free < limit) {
|
if (nr_free < limit) {
|
||||||
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
AMAP_T *amap = SDFAT_SB(sb)->fsi.amap;
|
||||||
AU_INFO_T *au = GET_AU(amap, i_AU_of_CLU(amap, clus));
|
AU_INFO_T *au = GET_AU(amap, i_AU_of_CLU(amap, clus));
|
||||||
|
|
@ -377,8 +375,7 @@ __defrag_check_au(
|
||||||
dfr_debug("AU[%d] nr_free %d, limit %d", au->idx, nr_free, limit);
|
dfr_debug("AU[%d] nr_free %d, limit %d", au->idx, nr_free, limit);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return ((nr_free < limit) ? 1 : 0);
|
||||||
return ((nr_free < limit)? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -406,15 +403,15 @@ defrag_validate_cluster(
|
||||||
if (fid->dir.dir == DIR_DELETED)
|
if (fid->dir.dir == DIR_DELETED)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* Skip working-AU */
|
/* Skip working-AU */
|
||||||
err = amap_check_working(sb, chunk->d_clus);
|
err = amap_check_working(sb, chunk->d_clus);
|
||||||
if (err)
|
if (err)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
/* Check # of free_clus of belonged AU */
|
/* Check # of free_clus of belonged AU */
|
||||||
err = __defrag_check_au(inode->i_sb, chunk->d_clus, CLUS_PER_AU(sb) - chunk->au_clus);
|
err = __defrag_check_au(inode->i_sb, chunk->d_clus, CLUS_PER_AU(sb) - chunk->au_clus);
|
||||||
if (err)
|
if (err)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Check chunk's clusters */
|
/* Check chunk's clusters */
|
||||||
for (i = 0; i < chunk->nr_clus; i++) {
|
for (i = 0; i < chunk->nr_clus; i++) {
|
||||||
|
|
@ -457,7 +454,7 @@ defrag_reserve_clusters(
|
||||||
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
||||||
FS_INFO_T *fsi = &(sbi->fsi);
|
FS_INFO_T *fsi = &(sbi->fsi);
|
||||||
|
|
||||||
if ( !(sbi->options.improved_allocation & SDFAT_ALLOC_DELAY) )
|
if (!(sbi->options.improved_allocation & SDFAT_ALLOC_DELAY))
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -519,8 +516,6 @@ defrag_unmark_ignore_all(struct super_block *sb)
|
||||||
{
|
{
|
||||||
if (SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART)
|
if (SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART)
|
||||||
amap_unmark_ignore_all(sb);
|
amap_unmark_ignore_all(sb);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -596,11 +591,10 @@ defrag_map_cluster(
|
||||||
/* Make FAT-chain for new_clus */
|
/* Make FAT-chain for new_clus */
|
||||||
for (i = 0; i < chunk->nr_clus; i++) {
|
for (i = 0; i < chunk->nr_clus; i++) {
|
||||||
#if 0
|
#if 0
|
||||||
if (sbi->dfr_new_clus[chunk->new_idx + i]) {
|
if (sbi->dfr_new_clus[chunk->new_idx + i])
|
||||||
nr_new++;
|
nr_new++;
|
||||||
} else {
|
else
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (!sbi->dfr_new_clus[chunk->new_idx + i])
|
if (!sbi->dfr_new_clus[chunk->new_idx + i])
|
||||||
break;
|
break;
|
||||||
|
|
@ -654,11 +648,11 @@ defrag_writepage_end_io(
|
||||||
chunk_start = chunk->f_clus;
|
chunk_start = chunk->f_clus;
|
||||||
chunk_end = chunk->f_clus + chunk->nr_clus;
|
chunk_end = chunk->f_clus + chunk->nr_clus;
|
||||||
|
|
||||||
if ( (clus_start >= chunk_start) && (clus_end <= chunk_end) ) {
|
if ((clus_start >= chunk_start) && (clus_end <= chunk_end)) {
|
||||||
int off = clus_start - chunk_start;
|
int off = clus_start - chunk_start;
|
||||||
|
|
||||||
clear_bit( (page->index & (PAGES_PER_CLUS(sb) - 1)),
|
clear_bit((page->index & (PAGES_PER_CLUS(sb) - 1)),
|
||||||
(volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + off]) );
|
(volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + off]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -683,7 +677,7 @@ __defrag_check_wb(
|
||||||
|
|
||||||
/* Check WB complete status first */
|
/* Check WB complete status first */
|
||||||
for (wb_i = 0; wb_i < chunk->nr_clus; wb_i++) {
|
for (wb_i = 0; wb_i < chunk->nr_clus; wb_i++) {
|
||||||
if ( atomic_read((atomic_t *)&(sbi->dfr_page_wb[chunk->new_idx + wb_i])) ) {
|
if (atomic_read((atomic_t *)&(sbi->dfr_page_wb[chunk->new_idx + wb_i]))) {
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -700,7 +694,7 @@ __defrag_check_wb(
|
||||||
|
|
||||||
if (nr_new == chunk->nr_clus) {
|
if (nr_new == chunk->nr_clus) {
|
||||||
err = 0;
|
err = 0;
|
||||||
if ( (wb_i != chunk->nr_clus) && (wb_i != chunk->nr_clus - 1) )
|
if ((wb_i != chunk->nr_clus) && (wb_i != chunk->nr_clus - 1))
|
||||||
dfr_debug("submit_fullpage_bio() called on a page (nr_clus %d, wb_i %d)",
|
dfr_debug("submit_fullpage_bio() called on a page (nr_clus %d, wb_i %d)",
|
||||||
chunk->nr_clus, wb_i);
|
chunk->nr_clus, wb_i);
|
||||||
|
|
||||||
|
|
@ -741,7 +735,7 @@ __defrag_check_fat_old(
|
||||||
err = fat_ent_get(sb, clus, &clus);
|
err = fat_ent_get(sb, clus, &clus);
|
||||||
ERR_HANDLE(err);
|
ERR_HANDLE(err);
|
||||||
|
|
||||||
if ( (idx < max_idx - 1) && (IS_CLUS_EOF(clus) || IS_CLUS_FREE(clus)) ) {
|
if ((idx < max_idx - 1) && (IS_CLUS_EOF(clus) || IS_CLUS_FREE(clus))) {
|
||||||
dfr_err("FAT: inode %p, max_idx %d, idx %d, clus %08x, "
|
dfr_err("FAT: inode %p, max_idx %d, idx %d, clus %08x, "
|
||||||
"f_clus %d, nr_clus %d", inode, max_idx,
|
"f_clus %d, nr_clus %d", inode, max_idx,
|
||||||
idx, clus, chunk->f_clus, chunk->nr_clus);
|
idx, clus, chunk->f_clus, chunk->nr_clus);
|
||||||
|
|
@ -804,14 +798,13 @@ __defrag_check_fat_new(
|
||||||
BUG_ON(err);
|
BUG_ON(err);
|
||||||
err = fat_ent_get(sb, sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], &clus);
|
err = fat_ent_get(sb, sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], &clus);
|
||||||
BUG_ON(err);
|
BUG_ON(err);
|
||||||
if ( (chunk->next_clus & 0x0FFFFFFF) != (clus & 0x0FFFFFFF) ) {
|
if ((chunk->next_clus & 0x0FFFFFFF) != (clus & 0x0FFFFFFF)) {
|
||||||
dfr_err("FAT: inode %p, next_clus %08x, read_clus %08x", inode, chunk->next_clus, clus);
|
dfr_err("FAT: inode %p, next_clus %08x, read_clus %08x", inode, chunk->next_clus, clus);
|
||||||
err = EIO;
|
err = EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
BUG_ON(err);
|
BUG_ON(err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -872,7 +865,7 @@ defrag_update_fat_prev(
|
||||||
struct defrag_info *sb_dfr = &sbi->dfr_info, *ino_dfr = NULL;
|
struct defrag_info *sb_dfr = &sbi->dfr_info, *ino_dfr = NULL;
|
||||||
int skip = 0, done = 0;
|
int skip = 0, done = 0;
|
||||||
|
|
||||||
/* Check if FS_ERROR occured */
|
/* Check if FS_ERROR occurred */
|
||||||
if (sb->s_flags & MS_RDONLY) {
|
if (sb->s_flags & MS_RDONLY) {
|
||||||
dfr_err("RDONLY partition (err %d)", -EPERM);
|
dfr_err("RDONLY partition (err %d)", -EPERM);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -885,7 +878,7 @@ defrag_update_fat_prev(
|
||||||
int i = 0, j = 0;
|
int i = 0, j = 0;
|
||||||
|
|
||||||
mutex_lock(&ino_dfr->lock);
|
mutex_lock(&ino_dfr->lock);
|
||||||
BUG_ON (atomic_read(&ino_dfr->stat) != DFR_INO_STAT_REQ);
|
BUG_ON(atomic_read(&ino_dfr->stat) != DFR_INO_STAT_REQ);
|
||||||
for (i = 0; i < ino_dfr->nr_chunks; i++) {
|
for (i = 0; i < ino_dfr->nr_chunks; i++) {
|
||||||
struct defrag_chunk_info *chunk = NULL;
|
struct defrag_chunk_info *chunk = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
@ -906,15 +899,16 @@ defrag_update_fat_prev(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Double-check clusters */
|
/* Double-check clusters */
|
||||||
if ( chunk_prev &&
|
if (chunk_prev &&
|
||||||
(chunk->f_clus == chunk_prev->f_clus + chunk_prev->nr_clus) &&
|
(chunk->f_clus == chunk_prev->f_clus + chunk_prev->nr_clus) &&
|
||||||
(chunk_prev->stat == DFR_CHUNK_STAT_PASS) ) {
|
(chunk_prev->stat == DFR_CHUNK_STAT_PASS)) {
|
||||||
|
|
||||||
err = defrag_validate_cluster(inode, chunk, 1);
|
err = defrag_validate_cluster(inode, chunk, 1);
|
||||||
|
|
||||||
/* Handle continuous chunks in a file */
|
/* Handle continuous chunks in a file */
|
||||||
if (!err) {
|
if (!err) {
|
||||||
chunk->prev_clus = sbi->dfr_new_clus[chunk_prev->new_idx + chunk_prev->nr_clus - 1];
|
chunk->prev_clus =
|
||||||
|
sbi->dfr_new_clus[chunk_prev->new_idx + chunk_prev->nr_clus - 1];
|
||||||
dfr_debug("prev->f_clus %d, prev->nr_clus %d, chunk->f_clus %d",
|
dfr_debug("prev->f_clus %d, prev->nr_clus %d, chunk->f_clus %d",
|
||||||
chunk_prev->f_clus, chunk_prev->nr_clus, chunk->f_clus);
|
chunk_prev->f_clus, chunk_prev->nr_clus, chunk->f_clus);
|
||||||
}
|
}
|
||||||
|
|
@ -932,7 +926,7 @@ defrag_update_fat_prev(
|
||||||
* Skip update_fat_prev if WB or update_fat_next not completed.
|
* Skip update_fat_prev if WB or update_fat_next not completed.
|
||||||
* Go to error case if FORCE set.
|
* Go to error case if FORCE set.
|
||||||
*/
|
*/
|
||||||
if ( __defrag_check_wb(sbi, chunk) || (chunk->stat != DFR_CHUNK_STAT_PREP) ) {
|
if (__defrag_check_wb(sbi, chunk) || (chunk->stat != DFR_CHUNK_STAT_PREP)) {
|
||||||
if (force) {
|
if (force) {
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
dfr_err("Skip case: inode %p, stat %x, f_clus %d, err %d",
|
dfr_err("Skip case: inode %p, stat %x, f_clus %d, err %d",
|
||||||
|
|
@ -1050,7 +1044,7 @@ defrag_update_fat_next(
|
||||||
struct defrag_chunk_info *chunk = NULL;
|
struct defrag_chunk_info *chunk = NULL;
|
||||||
int done = 0, i = 0, j = 0, err = 0;
|
int done = 0, i = 0, j = 0, err = 0;
|
||||||
|
|
||||||
/* Check if FS_ERROR occured */
|
/* Check if FS_ERROR occurred */
|
||||||
if (sb->s_flags & MS_RDONLY) {
|
if (sb->s_flags & MS_RDONLY) {
|
||||||
dfr_err("RDONLY partition (err %d)", -EROFS);
|
dfr_err("RDONLY partition (err %d)", -EROFS);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -1063,7 +1057,7 @@ defrag_update_fat_next(
|
||||||
|
|
||||||
chunk = &(ino_dfr->chunks[i]);
|
chunk = &(ino_dfr->chunks[i]);
|
||||||
|
|
||||||
/* Do nothing if error occured or update_fat_next already passed */
|
/* Do nothing if error occurred or update_fat_next already passed */
|
||||||
if (chunk->stat == DFR_CHUNK_STAT_ERR)
|
if (chunk->stat == DFR_CHUNK_STAT_ERR)
|
||||||
continue;
|
continue;
|
||||||
if (chunk->stat & DFR_CHUNK_STAT_FAT) {
|
if (chunk->stat & DFR_CHUNK_STAT_FAT) {
|
||||||
|
|
@ -1083,7 +1077,7 @@ defrag_update_fat_next(
|
||||||
|
|
||||||
/* Update chunk's next cluster */
|
/* Update chunk's next cluster */
|
||||||
FAT32_CHECK_CLUSTER(fsi,
|
FAT32_CHECK_CLUSTER(fsi,
|
||||||
sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], err);
|
sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], err);
|
||||||
BUG_ON(err);
|
BUG_ON(err);
|
||||||
if (fat_ent_set(sb,
|
if (fat_ent_set(sb,
|
||||||
sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1],
|
sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1],
|
||||||
|
|
@ -1126,8 +1120,8 @@ defrag_check_discard(
|
||||||
|
|
||||||
BUG_ON(!amap);
|
BUG_ON(!amap);
|
||||||
|
|
||||||
if ( !(SDFAT_SB(sb)->options.discard) ||
|
if (!(SDFAT_SB(sb)->options.discard) ||
|
||||||
!(SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART) )
|
!(SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(tmp, 0, sizeof(int) * DFR_MAX_AU_MOVED);
|
memset(tmp, 0, sizeof(int) * DFR_MAX_AU_MOVED);
|
||||||
|
|
@ -1139,8 +1133,8 @@ defrag_check_discard(
|
||||||
au = GET_AU(amap, i_AU_of_CLU(amap, chunk->d_clus));
|
au = GET_AU(amap, i_AU_of_CLU(amap, chunk->d_clus));
|
||||||
|
|
||||||
/* Send DISCARD for free AU */
|
/* Send DISCARD for free AU */
|
||||||
if ( (IS_AU_IGNORED(au, amap)) &&
|
if ((IS_AU_IGNORED(au, amap)) &&
|
||||||
(amap_get_freeclus(sb, chunk->d_clus) == CLUS_PER_AU(sb)) ) {
|
(amap_get_freeclus(sb, chunk->d_clus) == CLUS_PER_AU(sb))) {
|
||||||
sector_t blk = 0, nr_blks = 0;
|
sector_t blk = 0, nr_blks = 0;
|
||||||
unsigned int au_align_factor = amap->option.au_align_factor % amap->option.au_size;
|
unsigned int au_align_factor = amap->option.au_align_factor % amap->option.au_size;
|
||||||
|
|
||||||
|
|
@ -1157,11 +1151,11 @@ defrag_check_discard(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Send DISCARD cmd */
|
/* Send DISCARD cmd */
|
||||||
blk = (sector_t) ( ((au->idx * CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits)
|
blk = (sector_t) (((au->idx * CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits)
|
||||||
- au_align_factor );
|
- au_align_factor);
|
||||||
nr_blks = ((sector_t)CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits;
|
nr_blks = ((sector_t)CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits;
|
||||||
|
|
||||||
dfr_debug("Send DISCARD for AU[%d] (blk %08llx)", au->idx, blk);
|
dfr_debug("Send DISCARD for AU[%d] (blk %08zx)", au->idx, blk);
|
||||||
sb_issue_discard(sb, blk, nr_blks, GFP_NOFS, 0);
|
sb_issue_discard(sb, blk, nr_blks, GFP_NOFS, 0);
|
||||||
|
|
||||||
/* Save previous AU's index */
|
/* Save previous AU's index */
|
||||||
|
|
@ -1236,14 +1230,14 @@ defrag_check_defrag_required(
|
||||||
int clean_ratio = 0, frag_ratio = 0;
|
int clean_ratio = 0, frag_ratio = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if( !(sb) || !(SDFAT_SB(sb)->options.defrag) )
|
if (!sb || !(SDFAT_SB(sb)->options.defrag))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Check DFR_DEFAULT_STOP_RATIO first */
|
/* Check DFR_DEFAULT_STOP_RATIO first */
|
||||||
fsi = &(SDFAT_SB(sb)->fsi);
|
fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
if (fsi->used_clusters == (unsigned int)(~0)) {
|
if (fsi->used_clusters == (unsigned int)(~0)) {
|
||||||
if (fsi->fs_func->count_used_clusters(sb, &fsi->used_clusters))
|
if (fsi->fs_func->count_used_clusters(sb, &fsi->used_clusters))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (fsi->used_clusters * DFR_FULL_RATIO >= fsi->num_clusters * DFR_DEFAULT_STOP_RATIO) {
|
if (fsi->used_clusters * DFR_FULL_RATIO >= fsi->num_clusters * DFR_DEFAULT_STOP_RATIO) {
|
||||||
dfr_debug("used_clusters %d, num_clusters %d", fsi->used_clusters, fsi->num_clusters);
|
dfr_debug("used_clusters %d, num_clusters %d", fsi->used_clusters, fsi->num_clusters);
|
||||||
|
|
@ -1262,12 +1256,11 @@ defrag_check_defrag_required(
|
||||||
(fsi->used_clusters * CLUS_PER_AU(sb));
|
(fsi->used_clusters * CLUS_PER_AU(sb));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake-up defrag_daemon
|
* Wake-up defrag_daemon:
|
||||||
* when # of clean AUs too small,
|
* when # of clean AUs too small, or frag_ratio exceeds the limit
|
||||||
* or frag_ratio exceeds the limit
|
|
||||||
*/
|
*/
|
||||||
if ( (clean_ratio < DFR_DEFAULT_WAKEUP_RATIO) ||
|
if ((clean_ratio < DFR_DEFAULT_WAKEUP_RATIO) ||
|
||||||
((clean_ratio < DFR_DEFAULT_CLEAN_RATIO) && (frag_ratio >= DFR_DEFAULT_FRAG_RATIO)) ) {
|
((clean_ratio < DFR_DEFAULT_CLEAN_RATIO) && (frag_ratio >= DFR_DEFAULT_FRAG_RATIO))) {
|
||||||
|
|
||||||
if (totalau)
|
if (totalau)
|
||||||
*totalau = amap->n_au;
|
*totalau = amap->n_au;
|
||||||
|
|
@ -1316,7 +1309,7 @@ defrag_check_defrag_on(
|
||||||
|
|
||||||
clus_start = start >> (fsi->cluster_size_bits);
|
clus_start = start >> (fsi->cluster_size_bits);
|
||||||
clus_end = (end >> (fsi->cluster_size_bits)) +
|
clus_end = (end >> (fsi->cluster_size_bits)) +
|
||||||
((end & (fsi->cluster_size - 1))? 1:0);
|
((end & (fsi->cluster_size - 1)) ? 1 : 0);
|
||||||
|
|
||||||
if (!ino_dfr->chunks)
|
if (!ino_dfr->chunks)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -1326,18 +1319,17 @@ defrag_check_defrag_on(
|
||||||
struct defrag_chunk_info *chunk = &(ino_dfr->chunks[i]);
|
struct defrag_chunk_info *chunk = &(ino_dfr->chunks[i]);
|
||||||
unsigned int chunk_start = 0, chunk_end = 0;
|
unsigned int chunk_start = 0, chunk_end = 0;
|
||||||
|
|
||||||
/* Skip this chunk when error occured or it already passed defrag process */
|
/* Skip this chunk when error occurred or it already passed defrag process */
|
||||||
if ((chunk->stat == DFR_CHUNK_STAT_ERR) || (chunk->stat == DFR_CHUNK_STAT_PASS))
|
if ((chunk->stat == DFR_CHUNK_STAT_ERR) || (chunk->stat == DFR_CHUNK_STAT_PASS))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
chunk_start = chunk->f_clus;
|
chunk_start = chunk->f_clus;
|
||||||
chunk_end = chunk->f_clus + chunk->nr_clus;
|
chunk_end = chunk->f_clus + chunk->nr_clus;
|
||||||
|
|
||||||
if ( ((clus_start >= chunk_start) && (clus_start < chunk_end)) ||
|
if (((clus_start >= chunk_start) && (clus_start < chunk_end)) ||
|
||||||
((clus_end > chunk_start) && (clus_end <= chunk_end)) ||
|
((clus_end > chunk_start) && (clus_end <= chunk_end)) ||
|
||||||
((clus_start < chunk_start) && (clus_end > chunk_end)) ) {
|
((clus_start < chunk_start) && (clus_end > chunk_end))) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
chunk->stat = DFR_CHUNK_STAT_ERR;
|
chunk->stat = DFR_CHUNK_STAT_ERR;
|
||||||
dfr_debug("Defrag canceled: inode %p, start %08x, end %08x, caller %s",
|
dfr_debug("Defrag canceled: inode %p, start %08x, end %08x, caller %s",
|
||||||
|
|
@ -1371,15 +1363,13 @@ defrag_spo_test(
|
||||||
{
|
{
|
||||||
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
||||||
|
|
||||||
if( !(sb) || !(SDFAT_SB(sb)->options.defrag) )
|
if (!sb || !(SDFAT_SB(sb)->options.defrag))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (flag == sbi->dfr_spo_flag) {
|
if (flag == sbi->dfr_spo_flag) {
|
||||||
dfr_err("Defrag SPO test (flag %d, caller %s)", flag, caller);
|
dfr_err("Defrag SPO test (flag %d, caller %s)", flag, caller);
|
||||||
panic("Defrag SPO test");
|
panic("Defrag SPO test");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SDFAT_DFR_DEBUG */
|
#endif /* CONFIG_SDFAT_DFR_DEBUG */
|
||||||
|
|
||||||
|
|
|
||||||
56
dfr.h
56
dfr.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_DEFRAG_H
|
#ifndef _SDFAT_DEFRAG_H
|
||||||
|
|
@ -23,45 +21,47 @@
|
||||||
#ifdef CONFIG_SDFAT_DFR
|
#ifdef CONFIG_SDFAT_DFR
|
||||||
|
|
||||||
/* Tuning parameters */
|
/* Tuning parameters */
|
||||||
#define DFR_MIN_TIMEOUT (1 * HZ) // Minimum timeout for forced-sync
|
#define DFR_MIN_TIMEOUT (1 * HZ) // Minimum timeout for forced-sync
|
||||||
#define DFR_DEFAULT_TIMEOUT (10 * HZ) // Default timeout for forced-sync
|
#define DFR_DEFAULT_TIMEOUT (10 * HZ) // Default timeout for forced-sync
|
||||||
|
|
||||||
#define DFR_DEFAULT_CLEAN_RATIO (50) // Wake-up daemon when clean AU ratio under 50%
|
#define DFR_DEFAULT_CLEAN_RATIO (50) // Wake-up daemon when clean AU ratio under 50%
|
||||||
#define DFR_DEFAULT_WAKEUP_RATIO (10) // Wake-up daemon when clean AU ratio under 10%, regardless of frag_ratio
|
#define DFR_DEFAULT_WAKEUP_RATIO (10) // Wake-up daemon when clean AU ratio under 10%, regardless of frag_ratio
|
||||||
|
|
||||||
#define DFR_DEFAULT_FRAG_RATIO (130) // Wake-up daemon when frag_ratio over 130%
|
#define DFR_DEFAULT_FRAG_RATIO (130) // Wake-up daemon when frag_ratio over 130%
|
||||||
|
|
||||||
#define DFR_DEFAULT_PACKING_RATIO (10) // Call allocator with PACKING flag, when clean AU ratio under 10%
|
#define DFR_DEFAULT_PACKING_RATIO (10) // Call allocator with PACKING flag, when clean AU ratio under 10%
|
||||||
|
|
||||||
#define DFR_DEFAULT_STOP_RATIO (98) // Stop defrag_daemon when disk used ratio over 98%
|
#define DFR_DEFAULT_STOP_RATIO (98) // Stop defrag_daemon when disk used ratio over 98%
|
||||||
#define DFR_FULL_RATIO (100)
|
#define DFR_FULL_RATIO (100)
|
||||||
|
|
||||||
#define DFR_MAX_AU_MOVED (16) // Maximum # of AUs for a request
|
#define DFR_MAX_AU_MOVED (16) // Maximum # of AUs for a request
|
||||||
|
|
||||||
|
|
||||||
/* Debugging support*/
|
/* Debugging support*/
|
||||||
#define dfr_err(fmt, args...) EMSG("DFR: " fmt "\n", args)
|
#define dfr_err(fmt, args...) pr_err("DFR: " fmt "\n", args)
|
||||||
|
|
||||||
#ifdef CONFIG_SDFAT_DFR_DEBUG
|
#ifdef CONFIG_SDFAT_DFR_DEBUG
|
||||||
#define dfr_debug(fmt, args...) DMSG("DFR: " fmt "\n", args)
|
#define dfr_debug(fmt, args...) pr_debug("DFR: " fmt "\n", args)
|
||||||
#else
|
#else
|
||||||
#define dfr_debug(fmt, args...)
|
#define dfr_debug(fmt, args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Error handling */
|
/* Error handling */
|
||||||
#define ERR_HANDLE(err) \
|
#define ERR_HANDLE(err) { \
|
||||||
if (err) { \
|
if (err) { \
|
||||||
dfr_debug("err %d", err); \
|
dfr_debug("err %d", err); \
|
||||||
goto error; \
|
goto error; \
|
||||||
}
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#define ERR_HANDLE2(cond, err, val) \
|
#define ERR_HANDLE2(cond, err, val) { \
|
||||||
if (cond) { \
|
if (cond) { \
|
||||||
err = val; \
|
err = val; \
|
||||||
dfr_debug("err %d", err); \
|
dfr_debug("err %d", err); \
|
||||||
goto error; \
|
goto error; \
|
||||||
}
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Arguments IN-OUT */
|
/* Arguments IN-OUT */
|
||||||
|
|
@ -91,16 +91,16 @@
|
||||||
(SDFAT_SB(sb)->options.amap_opt.sect_per_au) >> (SDFAT_SB(sb)->fsi.sect_per_clus_bits) \
|
(SDFAT_SB(sb)->options.amap_opt.sect_per_au) >> (SDFAT_SB(sb)->fsi.sect_per_clus_bits) \
|
||||||
)
|
)
|
||||||
#define PAGES_PER_AU(sb) ( \
|
#define PAGES_PER_AU(sb) ( \
|
||||||
( (SDFAT_SB(sb)->options.amap_opt.sect_per_au) << ((sb)->s_blocksize_bits) ) \
|
((SDFAT_SB(sb)->options.amap_opt.sect_per_au) << ((sb)->s_blocksize_bits)) \
|
||||||
>> PAGE_SHIFT \
|
>> PAGE_SHIFT \
|
||||||
)
|
)
|
||||||
#define PAGES_PER_CLUS(sb) ((SDFAT_SB(sb)->fsi.cluster_size) >> PAGE_SHIFT)
|
#define PAGES_PER_CLUS(sb) ((SDFAT_SB(sb)->fsi.cluster_size) >> PAGE_SHIFT)
|
||||||
|
|
||||||
#define FAT32_CHECK_CLUSTER(fsi, clus, err) \
|
#define FAT32_CHECK_CLUSTER(fsi, clus, err) \
|
||||||
{ \
|
{ \
|
||||||
if ( ((clus) < FAT32_UNUSED_CLUS) || \
|
if (((clus) < FAT32_UNUSED_CLUS) || \
|
||||||
((clus) > (fsi)->num_clusters) || \
|
((clus) > (fsi)->num_clusters) || \
|
||||||
((clus) >= FAT32_RESERVED) ) { \
|
((clus) >= FAT32_RESERVED)) { \
|
||||||
dfr_err("clus %08x, fsi->num_clusters %08x", (clus), (fsi)->num_clusters); \
|
dfr_err("clus %08x, fsi->num_clusters %08x", (clus), (fsi)->num_clusters); \
|
||||||
err = -EINVAL; \
|
err = -EINVAL; \
|
||||||
} else { \
|
} else { \
|
||||||
|
|
|
||||||
6
extent.c
6
extent.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -272,7 +270,7 @@ static inline void cache_init(struct extent_cache_id *cid, s32 fclus, u32 dclus)
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 extent_get_clus(struct inode *inode, s32 cluster, s32 *fclus,
|
s32 extent_get_clus(struct inode *inode, s32 cluster, s32 *fclus,
|
||||||
u32 *dclus, u32 *last_dclus, s32 allow_eof)
|
u32 *dclus, u32 *last_dclus, s32 allow_eof)
|
||||||
{
|
{
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
|
||||||
115
fatent.c
115
fatent.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -64,12 +62,11 @@ static s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
if (!fat_sector)
|
if (!fat_sector)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
_content = le32_to_cpu(*(__le32*)(&fat_sector[off]));
|
_content = le32_to_cpu(*(__le32 *)(&fat_sector[off]));
|
||||||
if (_content >= CLUSTER_32(0xFFFFFFF8)) {
|
|
||||||
//return 0xFFFFFFFF to simplify code
|
/* remap reserved clusters to simplify code */
|
||||||
*content = CLUS_EOF;
|
if (_content >= CLUSTER_32(0xFFFFFFF8))
|
||||||
return 0;
|
_content = CLUS_EOF;
|
||||||
}
|
|
||||||
|
|
||||||
*content = CLUSTER_32(_content);
|
*content = CLUSTER_32(_content);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -95,6 +92,8 @@ static s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
return fcache_modify(sb, sec);
|
return fcache_modify(sb, sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FATENT_FAT32_VALID_MASK (0x0FFFFFFFU)
|
||||||
|
#define FATENT_FAT32_IGNORE_MASK (0xF0000000U)
|
||||||
static s32 fat32_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
static s32 fat32_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
{
|
{
|
||||||
u32 sec, off, _content;
|
u32 sec, off, _content;
|
||||||
|
|
@ -108,14 +107,14 @@ static s32 fat32_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
if (!fat_sector)
|
if (!fat_sector)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
_content = le32_to_cpu(*(__le32*)(&fat_sector[off]));
|
_content = le32_to_cpu(*(__le32 *)(&fat_sector[off]));
|
||||||
_content &= 0x0FFFFFFF;
|
_content &= FATENT_FAT32_VALID_MASK;
|
||||||
|
|
||||||
if (_content >= CLUSTER_32(0x0FFFFFF8)) {
|
/* remap reserved clusters to simplify code */
|
||||||
//return 0xFFFFFFFF to simplify code
|
if (_content == CLUSTER_32(0x0FFFFFF7U))
|
||||||
*content = CLUS_EOF;
|
_content = CLUS_BAD;
|
||||||
return 0;
|
else if (_content >= CLUSTER_32(0x0FFFFFF8U))
|
||||||
}
|
_content = CLUS_EOF;
|
||||||
|
|
||||||
*content = CLUSTER_32(_content);
|
*content = CLUSTER_32(_content);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -128,7 +127,7 @@ static s32 fat32_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
__le32 *fat_entry;
|
__le32 *fat_entry;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
content &= 0x0FFFFFFF;
|
content &= FATENT_FAT32_VALID_MASK;
|
||||||
|
|
||||||
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2));
|
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2));
|
||||||
off = (loc << 2) & (u32)(sb->s_blocksize - 1);
|
off = (loc << 2) & (u32)(sb->s_blocksize - 1);
|
||||||
|
|
@ -138,12 +137,13 @@ static s32 fat32_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
fat_entry = (__le32 *)&(fat_sector[off]);
|
fat_entry = (__le32 *)&(fat_sector[off]);
|
||||||
content |= (le32_to_cpu(*fat_entry) & 0xF0000000);
|
content |= (le32_to_cpu(*fat_entry) & FATENT_FAT32_IGNORE_MASK);
|
||||||
*fat_entry = cpu_to_le32(content);
|
*fat_entry = cpu_to_le32(content);
|
||||||
|
|
||||||
return fcache_modify(sb, sec);
|
return fcache_modify(sb, sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FATENT_FAT16_VALID_MASK (0x0000FFFFU)
|
||||||
static s32 fat16_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
static s32 fat16_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
{
|
{
|
||||||
u32 sec, off, _content;
|
u32 sec, off, _content;
|
||||||
|
|
@ -154,17 +154,17 @@ static s32 fat16_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
off = (loc << 1) & (u32)(sb->s_blocksize - 1);
|
off = (loc << 1) & (u32)(sb->s_blocksize - 1);
|
||||||
|
|
||||||
fat_sector = fcache_getblk(sb, sec);
|
fat_sector = fcache_getblk(sb, sec);
|
||||||
if(!fat_sector)
|
if (!fat_sector)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
_content = (u32)le16_to_cpu(*(__le16*)(&fat_sector[off]));
|
_content = (u32)le16_to_cpu(*(__le16 *)(&fat_sector[off]));
|
||||||
_content &= 0x0000FFFF;
|
_content &= FATENT_FAT16_VALID_MASK;
|
||||||
|
|
||||||
if (_content >= CLUSTER_16(0xFFF8)) {
|
/* remap reserved clusters to simplify code */
|
||||||
// return 0x0FFFFFFF to simplify code
|
if (_content == CLUSTER_16(0xFFF7U))
|
||||||
*content = CLUS_EOF;
|
_content = CLUS_BAD;
|
||||||
return 0;
|
else if (_content >= CLUSTER_16(0xFFF8U))
|
||||||
}
|
_content = CLUS_EOF;
|
||||||
|
|
||||||
*content = CLUSTER_32(_content);
|
*content = CLUSTER_32(_content);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -177,7 +177,7 @@ static s32 fat16_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
__le16 *fat_entry;
|
__le16 *fat_entry;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
content &= 0x0000FFFF;
|
content &= FATENT_FAT16_VALID_MASK;
|
||||||
|
|
||||||
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-1));
|
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-1));
|
||||||
off = (loc << 1) & (u32)(sb->s_blocksize - 1);
|
off = (loc << 1) & (u32)(sb->s_blocksize - 1);
|
||||||
|
|
@ -186,12 +186,13 @@ static s32 fat16_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
if (!fat_sector)
|
if (!fat_sector)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
fat_entry = (__le16*)&(fat_sector[off]);
|
fat_entry = (__le16 *)&(fat_sector[off]);
|
||||||
*fat_entry = cpu_to_le16(content);
|
*fat_entry = cpu_to_le16(content);
|
||||||
|
|
||||||
return fcache_modify(sb, sec);
|
return fcache_modify(sb, sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FATENT_FAT12_VALID_MASK (0x00000FFFU)
|
||||||
static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
{
|
{
|
||||||
u32 sec, off, _content;
|
u32 sec, off, _content;
|
||||||
|
|
@ -217,15 +218,16 @@ static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
_content = get_unaligned_le16(&fat_sector[off]);
|
_content = get_unaligned_le16(&fat_sector[off]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loc & 1) _content >>= 4;
|
if (loc & 1)
|
||||||
|
_content >>= 4;
|
||||||
|
|
||||||
_content &= 0x00000FFF;
|
_content &= FATENT_FAT12_VALID_MASK;
|
||||||
|
|
||||||
if (_content >= CLUSTER_16(0x0FF8)) {
|
/* remap reserved clusters to simplify code */
|
||||||
/* return 0xFFFFFFFF to simplify code */
|
if (_content == CLUSTER_16(0x0FF7U))
|
||||||
*content = CLUS_EOF;
|
_content = CLUS_BAD;
|
||||||
return 0;
|
else if (_content >= CLUSTER_16(0x0FF8U))
|
||||||
}
|
_content = CLUS_EOF;
|
||||||
|
|
||||||
*content = CLUSTER_32(_content);
|
*content = CLUSTER_32(_content);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -237,7 +239,7 @@ static s32 fat12_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
u8 *fat_sector, *fat_entry;
|
u8 *fat_sector, *fat_entry;
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
content &= 0x00000FFF;
|
content &= FATENT_FAT12_VALID_MASK;
|
||||||
|
|
||||||
sec = fsi->FAT1_start_sector + ((loc + (loc >> 1)) >> sb->s_blocksize_bits);
|
sec = fsi->FAT1_start_sector + ((loc + (loc >> 1)) >> sb->s_blocksize_bits);
|
||||||
off = (loc + (loc >> 1)) & (u32)(sb->s_blocksize - 1);
|
off = (loc + (loc >> 1)) & (u32)(sb->s_blocksize - 1);
|
||||||
|
|
@ -262,9 +264,7 @@ static s32 fat12_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
fat_sector[0] = (u8)(content >> 8);
|
fat_sector[0] = (u8)(content >> 8);
|
||||||
} else {
|
} else {
|
||||||
fat_entry = &(fat_sector[off]);
|
fat_entry = &(fat_sector[off]);
|
||||||
content |= 0x000F &
|
content |= 0x000F & get_unaligned_le16(fat_entry);
|
||||||
get_unaligned_le16(fat_entry);
|
|
||||||
|
|
||||||
put_unaligned_le16(content, fat_entry);
|
put_unaligned_le16(content, fat_entry);
|
||||||
}
|
}
|
||||||
} else { /* even */
|
} else { /* even */
|
||||||
|
|
@ -282,9 +282,7 @@ static s32 fat12_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8));
|
fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8));
|
||||||
} else {
|
} else {
|
||||||
fat_entry = &(fat_sector[off]);
|
fat_entry = &(fat_sector[off]);
|
||||||
content |= 0xF000 &
|
content |= 0xF000 & get_unaligned_le16(fat_entry);
|
||||||
get_unaligned_le16(fat_entry);
|
|
||||||
|
|
||||||
put_unaligned_le16(content, fat_entry);
|
put_unaligned_le16(content, fat_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,12 +336,30 @@ s32 fat_ent_ops_init(struct super_block *sb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_reserved_clus(u32 clus)
|
||||||
|
{
|
||||||
|
if (IS_CLUS_FREE(clus))
|
||||||
|
return true;
|
||||||
|
if (IS_CLUS_EOF(clus))
|
||||||
|
return true;
|
||||||
|
if (IS_CLUS_BAD(clus))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus)
|
||||||
|
{
|
||||||
|
if (clus < CLUS_BASE || fsi->num_clusters <= clus)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
s32 err;
|
s32 err;
|
||||||
|
|
||||||
if (loc < CLUS_BASE || fsi->num_clusters <= loc) {
|
if (!is_valid_clus(fsi, loc)) {
|
||||||
sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", loc);
|
sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", loc);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
@ -355,8 +371,7 @@ s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*content && !IS_CLUS_EOF(*content) &&
|
if (!is_reserved_clus(*content) && !is_valid_clus(fsi, *content)) {
|
||||||
(*content < CLUS_BASE || fsi->num_clusters <= *content)) {
|
|
||||||
sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x) "
|
sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x) "
|
||||||
"bogus content (0x%08x)", loc, *content);
|
"bogus content (0x%08x)", loc, *content);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -368,17 +383,25 @@ s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content)
|
||||||
s32 fat_ent_set(struct super_block *sb, u32 loc, u32 content)
|
s32 fat_ent_set(struct super_block *sb, u32 loc, u32 content)
|
||||||
{
|
{
|
||||||
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
return fsi->fatent_ops->ent_set(sb, loc, content);
|
return fsi->fatent_ops->ent_set(sb, loc, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 fat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content)
|
s32 fat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content)
|
||||||
{
|
{
|
||||||
s32 err = fat_ent_get(sb, loc, content);
|
s32 err = fat_ent_get(sb, loc, content);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (IS_CLUS_FREE(*content)) {
|
if (IS_CLUS_FREE(*content)) {
|
||||||
sdfat_fs_error(sb, "invalid access to free FAT "
|
sdfat_fs_error(sb, "invalid access to FAT free cluster "
|
||||||
|
"(entry 0x%08x)", loc);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_CLUS_BAD(*content)) {
|
||||||
|
sdfat_fs_error(sb, "invalid access to FAT bad cluster "
|
||||||
"(entry 0x%08x)", loc);
|
"(entry 0x%08x)", loc);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
49
misc.c
49
misc.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -70,7 +68,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
printk(KERN_ERR "[SDFAT](%s[%d:%d]):ERR: %pV\n",
|
pr_err("[SDFAT](%s[%d:%d]):ERR: %pV\n",
|
||||||
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
|
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
|
||||||
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
||||||
if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
|
if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
|
||||||
|
|
@ -86,7 +84,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
||||||
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
||||||
} else if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
|
} else if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
printk(KERN_ERR "[SDFAT](%s[%d:%d]): Filesystem has been set "
|
pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set "
|
||||||
"read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
"read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
||||||
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
||||||
ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
|
ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
|
||||||
|
|
@ -97,9 +95,9 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
||||||
EXPORT_SYMBOL(__sdfat_fs_error);
|
EXPORT_SYMBOL(__sdfat_fs_error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __sdfat_msg() - print preformated FAT specific messages.
|
* __sdfat_msg() - print preformated SDFAT specific messages.
|
||||||
* Every thing what is not sdfat_fs_error() should be __sdfat_msg().
|
* All logs except what uses sdfat_fs_error() should be written by __sdfat_msg()
|
||||||
* If 'st' is set to 1, it means that this message should be saved on ST_LOG.
|
* If 'st' is set, the log is propagated to ST_LOG.
|
||||||
*/
|
*/
|
||||||
void __sdfat_msg(struct super_block *sb, const char *level, int st, const char *fmt, ...)
|
void __sdfat_msg(struct super_block *sb, const char *level, int st, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
|
@ -111,6 +109,7 @@ void __sdfat_msg(struct super_block *sb, const char *level, int st, const char *
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
/* level means KERN_ pacility level */
|
||||||
printk("%s[SDFAT](%s[%d:%d]): %pV\n", level,
|
printk("%s[SDFAT](%s[%d:%d]): %pV\n", level,
|
||||||
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
|
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
|
||||||
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
||||||
|
|
@ -125,15 +124,16 @@ EXPORT_SYMBOL(__sdfat_msg);
|
||||||
|
|
||||||
void sdfat_log_version(void)
|
void sdfat_log_version(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "[SDFAT] Filesystem version %s\n", SDFAT_VERSION);
|
pr_info("[SDFAT] Filesystem version %s\n", SDFAT_VERSION);
|
||||||
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
#ifdef CONFIG_SDFAT_SUPPORT_STLOG
|
||||||
ST_LOG("[SDFAT] Filesystem version %s\n", SDFAT_VERSION);
|
ST_LOG("[SDFAT] Filesystem version %s\n", SDFAT_VERSION);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sdfat_log_version);
|
EXPORT_SYMBOL(sdfat_log_version);
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
/* <linux/time.h> externs sys_tz
|
||||||
|
* extern struct timezone sys_tz;
|
||||||
|
*/
|
||||||
#define UNIX_SECS_1980 315532800L
|
#define UNIX_SECS_1980 315532800L
|
||||||
|
|
||||||
#if BITS_PER_LONG == 64
|
#if BITS_PER_LONG == 64
|
||||||
|
|
@ -154,15 +154,15 @@ extern struct timezone sys_tz;
|
||||||
do { \
|
do { \
|
||||||
/* 2100 isn't leap year */ \
|
/* 2100 isn't leap year */ \
|
||||||
if (unlikely(year > NO_LEAP_YEAR_2100)) \
|
if (unlikely(year > NO_LEAP_YEAR_2100)) \
|
||||||
leap_year = ((year + 3) / 4) - 1; \
|
leap_year = ((year + 3) / 4) - 1; \
|
||||||
else \
|
else \
|
||||||
leap_year = ((year + 3) / 4); \
|
leap_year = ((year + 3) / 4); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/* Linear day numbers of the respective 1sts in non-leap years. */
|
/* Linear day numbers of the respective 1sts in non-leap years. */
|
||||||
static time_t accum_days_in_year[] = {
|
static time_t accum_days_in_year[] = {
|
||||||
/* Month : 01 02 03 04 05 06 07 08 09 10 11 12 */
|
/* Month : N 01 02 03 04 05 06 07 08 09 10 11 12 */
|
||||||
0, 0, 31, 59, 90,120,151,181,212,243,273,304,334, 0, 0, 0,
|
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
|
/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
|
||||||
|
|
@ -179,10 +179,10 @@ void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
|
||||||
|
|
||||||
ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN
|
ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN
|
||||||
+ tp->Hour * SECS_PER_HOUR
|
+ tp->Hour * SECS_PER_HOUR
|
||||||
+ (year * 365 + ld + accum_days_in_year[(tp->Month)]
|
+ (year * 365 + ld + accum_days_in_year[tp->Month]
|
||||||
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
|
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
|
||||||
|
|
||||||
if(!sbi->options.tz_utc)
|
if (!sbi->options.tz_utc)
|
||||||
ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
|
ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
|
||||||
|
|
||||||
ts->tv_nsec = 0;
|
ts->tv_nsec = 0;
|
||||||
|
|
@ -255,6 +255,7 @@ TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
|
||||||
{
|
{
|
||||||
struct timespec ts = CURRENT_TIME_SEC;
|
struct timespec ts = CURRENT_TIME_SEC;
|
||||||
DATE_TIME_T dt;
|
DATE_TIME_T dt;
|
||||||
|
|
||||||
sdfat_time_unix2fat(sbi, &ts, &dt);
|
sdfat_time_unix2fat(sbi, &ts, &dt);
|
||||||
|
|
||||||
tp->year = dt.Year;
|
tp->year = dt.Year;
|
||||||
|
|
@ -264,7 +265,7 @@ TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
|
||||||
tp->min = dt.Minute;
|
tp->min = dt.Minute;
|
||||||
tp->sec = dt.Second;
|
tp->sec = dt.Second;
|
||||||
|
|
||||||
return(tp);
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 calc_chksum_1byte(void *data, s32 len, u8 chksum)
|
u8 calc_chksum_1byte(void *data, s32 len, u8 chksum)
|
||||||
|
|
@ -275,7 +276,7 @@ u8 calc_chksum_1byte(void *data, s32 len, u8 chksum)
|
||||||
for (i = 0; i < len; i++, c++)
|
for (i = 0; i < len; i++, c++)
|
||||||
chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c;
|
chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c;
|
||||||
|
|
||||||
return(chksum);
|
return chksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type)
|
u16 calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type)
|
||||||
|
|
@ -302,7 +303,8 @@ u32 sdfat_time_current_usec(struct timeval *tv)
|
||||||
|
|
||||||
#ifdef CONFIG_SDFAT_DBG_CAREFUL
|
#ifdef CONFIG_SDFAT_DBG_CAREFUL
|
||||||
/* Check the consistency of i_size_ondisk (FAT32, or flags 0x01 only) */
|
/* Check the consistency of i_size_ondisk (FAT32, or flags 0x01 only) */
|
||||||
void sdfat_debug_check_clusters(struct inode *inode){
|
void sdfat_debug_check_clusters(struct inode *inode)
|
||||||
|
{
|
||||||
int num_clusters;
|
int num_clusters;
|
||||||
volatile uint32_t tmp_fat_chain[50];
|
volatile uint32_t tmp_fat_chain[50];
|
||||||
volatile int num_clusters_org, tmp_i = 0;
|
volatile int num_clusters_org, tmp_i = 0;
|
||||||
|
|
@ -321,7 +323,8 @@ void sdfat_debug_check_clusters(struct inode *inode){
|
||||||
|
|
||||||
num_clusters_org = num_clusters;
|
num_clusters_org = num_clusters;
|
||||||
|
|
||||||
if (clu.flags == 0x03) return;
|
if (clu.flags == 0x03)
|
||||||
|
return;
|
||||||
|
|
||||||
while (num_clusters > 0) {
|
while (num_clusters > 0) {
|
||||||
/* FAT chain logging */
|
/* FAT chain logging */
|
||||||
|
|
@ -357,6 +360,7 @@ void __sdfat_dmsg(int level, const char *fmt, ...)
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
/* fmt already includes KERN_ pacility level */
|
||||||
printk("[%u] %pV", current->pid, &vaf);
|
printk("[%u] %pV", current->pid, &vaf);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
#else
|
#else
|
||||||
|
|
@ -367,6 +371,7 @@ void __sdfat_dmsg(int level, const char *fmt, ...)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
/* fmt already includes KERN_ pacility level */
|
||||||
vprintk(fmt, args);
|
vprintk(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
112
mpage.c
112
mpage.c
|
|
@ -26,9 +26,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -64,7 +62,7 @@
|
||||||
#include <linux/swap.h> /* for mark_page_accessed() */
|
#include <linux/swap.h> /* for mark_page_accessed() */
|
||||||
#include <asm/current.h>
|
#include <asm/current.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
|
||||||
#include <linux/aio.h>
|
#include <linux/aio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -80,30 +78,43 @@ static void __mpage_write_end_io(struct bio *bio, int err);
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
|
||||||
|
static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio)
|
||||||
|
{
|
||||||
|
bio_set_op_attrs(bio, REQ_OP_WRITE, flags);
|
||||||
|
submit_bio(bio);
|
||||||
|
}
|
||||||
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) */
|
||||||
|
static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio)
|
||||||
|
{
|
||||||
|
submit_bio(WRITE | flags, bio);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||||
static void mpage_write_end_io(struct bio *bio)
|
static void mpage_write_end_io(struct bio *bio)
|
||||||
{
|
{
|
||||||
__mpage_write_end_io(bio, bio->bi_error);
|
__mpage_write_end_io(bio, bio->bi_error);
|
||||||
}
|
}
|
||||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) */
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */
|
||||||
static void mpage_write_end_io(struct bio *bio, int err)
|
static void mpage_write_end_io(struct bio *bio, int err)
|
||||||
{
|
{
|
||||||
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
|
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
|
||||||
err = 0;
|
err = 0;
|
||||||
__mpage_write_end_io(bio, err);
|
__mpage_write_end_io(bio, err);
|
||||||
}
|
}
|
||||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) */
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||||
static inline int bio_get_nr_vecs(struct block_device *bdev)
|
static inline int bio_get_nr_vecs(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
return BIO_MAX_PAGES;
|
return BIO_MAX_PAGES;
|
||||||
}
|
}
|
||||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) */
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) */
|
||||||
/* EMPTY */
|
/* EMPTY */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
||||||
static inline sector_t __sdfat_bio_sector(struct bio *bio)
|
static inline sector_t __sdfat_bio_sector(struct bio *bio)
|
||||||
{
|
{
|
||||||
return bio->bi_iter.bi_sector;
|
return bio->bi_iter.bi_sector;
|
||||||
|
|
@ -123,10 +134,10 @@ static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size)
|
||||||
{
|
{
|
||||||
bio->bi_iter.bi_size = size;
|
bio->bi_iter.bi_size = size;
|
||||||
}
|
}
|
||||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) */
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
|
||||||
static inline sector_t __sdfat_bio_sector(struct bio *bio)
|
static inline sector_t __sdfat_bio_sector(struct bio *bio)
|
||||||
{
|
{
|
||||||
return bio->bi_sector;
|
return bio->bi_sector;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __sdfat_set_bio_sector(struct bio *bio, sector_t sector)
|
static inline void __sdfat_set_bio_sector(struct bio *bio, sector_t sector)
|
||||||
|
|
@ -136,26 +147,26 @@ static inline void __sdfat_set_bio_sector(struct bio *bio, sector_t sector)
|
||||||
|
|
||||||
static inline unsigned int __sdfat_bio_size(struct bio *bio)
|
static inline unsigned int __sdfat_bio_size(struct bio *bio)
|
||||||
{
|
{
|
||||||
return bio->bi_size;
|
return bio->bi_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size)
|
static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size)
|
||||||
{
|
{
|
||||||
bio->bi_size = size;
|
bio->bi_size = size;
|
||||||
}
|
}
|
||||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) */
|
#endif
|
||||||
|
|
||||||
/* __check_dfr_on() and __dfr_writepage_end_io() functions are copied from
|
/* __check_dfr_on() and __dfr_writepage_end_io() functions
|
||||||
* sdfat.c.
|
* are copied from sdfat.c
|
||||||
* Each function should be same perfectly
|
* Each function should be same perfectly
|
||||||
*/
|
*/
|
||||||
static inline int __check_dfr_on(struct inode *inode, loff_t start, loff_t end, const char *fname)
|
static inline int __check_dfr_on(struct inode *inode, loff_t start, loff_t end, const char *fname)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SDFAT_DFR
|
#ifdef CONFIG_SDFAT_DFR
|
||||||
struct defrag_info *ino_dfr = &(SDFAT_I(inode)->dfr_info);
|
struct defrag_info *ino_dfr = &(SDFAT_I(inode)->dfr_info);
|
||||||
|
|
||||||
if ( (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) &&
|
if ((atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) &&
|
||||||
fsapi_dfr_check_dfr_on(inode, start, end, 0, fname) )
|
fsapi_dfr_check_dfr_on(inode, start, end, 0, fname))
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -163,8 +174,9 @@ static inline int __check_dfr_on(struct inode *inode, loff_t start, loff_t end,
|
||||||
|
|
||||||
static inline int __dfr_writepage_end_io(struct page *page)
|
static inline int __dfr_writepage_end_io(struct page *page)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SDFAT_DFR
|
#ifdef CONFIG_SDFAT_DFR
|
||||||
struct defrag_info *ino_dfr = &(SDFAT_I(page->mapping->host)->dfr_info);
|
struct defrag_info *ino_dfr = &(SDFAT_I(page->mapping->host)->dfr_info);
|
||||||
|
|
||||||
if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ)
|
if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ)
|
||||||
fsapi_dfr_writepage_endio(page);
|
fsapi_dfr_writepage_endio(page);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -172,7 +184,7 @@ static inline int __dfr_writepage_end_io(struct page *page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline unsigned int __calc_size_to_align(struct super_block* sb)
|
static inline unsigned int __calc_size_to_align(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct block_device *bdev = sb->s_bdev;
|
struct block_device *bdev = sb->s_bdev;
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
|
|
@ -203,8 +215,8 @@ struct mpage_data {
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
sector_t last_block_in_bio;
|
sector_t last_block_in_bio;
|
||||||
get_block_t *get_block;
|
get_block_t *get_block;
|
||||||
unsigned use_writepage;
|
unsigned int use_writepage;
|
||||||
unsigned size_to_align;
|
unsigned int size_to_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -243,10 +255,10 @@ static void __mpage_write_end_io(struct bio *bio, int err)
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bio *mpage_bio_submit(int rw, struct bio *bio)
|
static struct bio *mpage_bio_submit_write(int flags, struct bio *bio)
|
||||||
{
|
{
|
||||||
bio->bi_end_io = mpage_write_end_io;
|
bio->bi_end_io = mpage_write_end_io;
|
||||||
submit_bio(rw, bio);
|
__sdfat_submit_bio_write2(flags, bio);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,13 +290,13 @@ static int sdfat_mpage_writepage(struct page *page,
|
||||||
struct bio *bio = mpd->bio;
|
struct bio *bio = mpd->bio;
|
||||||
struct address_space *mapping = page->mapping;
|
struct address_space *mapping = page->mapping;
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
const unsigned blkbits = inode->i_blkbits;
|
const unsigned int blkbits = inode->i_blkbits;
|
||||||
const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
|
const unsigned int blocks_per_page = PAGE_SIZE >> blkbits;
|
||||||
sector_t last_block;
|
sector_t last_block;
|
||||||
sector_t block_in_file;
|
sector_t block_in_file;
|
||||||
sector_t blocks[MAX_BUF_PER_PAGE];
|
sector_t blocks[MAX_BUF_PER_PAGE];
|
||||||
unsigned page_block;
|
unsigned int page_block;
|
||||||
unsigned first_unmapped = blocks_per_page;
|
unsigned int first_unmapped = blocks_per_page;
|
||||||
struct block_device *bdev = NULL;
|
struct block_device *bdev = NULL;
|
||||||
int boundary = 0;
|
int boundary = 0;
|
||||||
sector_t boundary_block = 0;
|
sector_t boundary_block = 0;
|
||||||
|
|
@ -292,7 +304,7 @@ static int sdfat_mpage_writepage(struct page *page,
|
||||||
int length;
|
int length;
|
||||||
struct buffer_head map_bh;
|
struct buffer_head map_bh;
|
||||||
loff_t i_size = i_size_read(inode);
|
loff_t i_size = i_size_read(inode);
|
||||||
unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
|
unsigned long end_index = i_size >> PAGE_SHIFT;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (page_has_buffers(page)) {
|
if (page_has_buffers(page)) {
|
||||||
|
|
@ -323,9 +335,10 @@ static int sdfat_mpage_writepage(struct page *page,
|
||||||
|
|
||||||
/* bh should be mapped if delay is set */
|
/* bh should be mapped if delay is set */
|
||||||
if (buffer_delay(bh)) {
|
if (buffer_delay(bh)) {
|
||||||
sector_t blk_in_file = (sector_t)(page->index << (PAGE_CACHE_SHIFT - blkbits)) + page_block;
|
sector_t blk_in_file =
|
||||||
BUG_ON(bh->b_size != (1 << blkbits));
|
(sector_t)(page->index << (PAGE_SHIFT - blkbits)) + page_block;
|
||||||
|
|
||||||
|
BUG_ON(bh->b_size != (1 << blkbits));
|
||||||
if (page->index > end_index) {
|
if (page->index > end_index) {
|
||||||
MMSG("%s(inode:%p) "
|
MMSG("%s(inode:%p) "
|
||||||
"over end with delayed buffer"
|
"over end with delayed buffer"
|
||||||
|
|
@ -387,7 +400,7 @@ static int sdfat_mpage_writepage(struct page *page,
|
||||||
* The page has no buffers: map it to disk
|
* The page has no buffers: map it to disk
|
||||||
*/
|
*/
|
||||||
BUG_ON(!PageUptodate(page));
|
BUG_ON(!PageUptodate(page));
|
||||||
block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
|
block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);
|
||||||
last_block = (i_size - 1) >> blkbits;
|
last_block = (i_size - 1) >> blkbits;
|
||||||
map_bh.b_page = page;
|
map_bh.b_page = page;
|
||||||
for (page_block = 0; page_block < blocks_per_page; ) {
|
for (page_block = 0; page_block < blocks_per_page; ) {
|
||||||
|
|
@ -430,7 +443,7 @@ page_is_mapped:
|
||||||
* is zeroed when mapped, and writes to that region are not
|
* is zeroed when mapped, and writes to that region are not
|
||||||
* written out to the file."
|
* written out to the file."
|
||||||
*/
|
*/
|
||||||
unsigned offset = i_size & (PAGE_CACHE_SIZE - 1);
|
unsigned int offset = i_size & (PAGE_SIZE - 1);
|
||||||
|
|
||||||
if (page->index > end_index || !offset) {
|
if (page->index > end_index || !offset) {
|
||||||
MMSG("%s(inode:%p) over end "
|
MMSG("%s(inode:%p) over end "
|
||||||
|
|
@ -439,7 +452,7 @@ page_is_mapped:
|
||||||
(u32)end_index, (u32)offset);
|
(u32)end_index, (u32)offset);
|
||||||
goto confused;
|
goto confused;
|
||||||
}
|
}
|
||||||
zero_user_segment(page, offset, PAGE_CACHE_SIZE);
|
zero_user_segment(page, offset, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -449,22 +462,22 @@ page_is_mapped:
|
||||||
*/
|
*/
|
||||||
if (bio) {
|
if (bio) {
|
||||||
if (mpd->last_block_in_bio != blocks[0] - 1) {
|
if (mpd->last_block_in_bio != blocks[0] - 1) {
|
||||||
bio = mpage_bio_submit(WRITE, bio);
|
bio = mpage_bio_submit_write(0, bio);
|
||||||
} else if (mpd->size_to_align) {
|
} else if (mpd->size_to_align) {
|
||||||
unsigned mask = mpd->size_to_align - 1;
|
unsigned int mask = mpd->size_to_align - 1;
|
||||||
sector_t max_end_block =
|
sector_t max_end_block =
|
||||||
(__sdfat_bio_sector(bio) & ~(mask)) + mask;
|
(__sdfat_bio_sector(bio) & ~(mask)) + mask;
|
||||||
|
|
||||||
if ( (__sdfat_bio_size(bio) != (1 << (mask + 1))) &&
|
if ((__sdfat_bio_size(bio) != (1 << (mask + 1))) &&
|
||||||
(mpd->last_block_in_bio == max_end_block) ) {
|
(mpd->last_block_in_bio == max_end_block)) {
|
||||||
MMSG("%s(inode:%p) alignment mpage_bio_submit"
|
MMSG("%s(inode:%p) alignment mpage_bio_submit"
|
||||||
"(start:%u, len:%u aligned:%u)\n",
|
"(start:%u, len:%u aligned:%u)\n",
|
||||||
__func__, inode,
|
__func__, inode,
|
||||||
(unsigned)__sdfat_bio_sector(bio),
|
(unsigned int)__sdfat_bio_sector(bio),
|
||||||
(unsigned)(mpd->last_block_in_bio -
|
(unsigned int)(mpd->last_block_in_bio -
|
||||||
__sdfat_bio_sector(bio) + 1),
|
__sdfat_bio_sector(bio) + 1),
|
||||||
(unsigned)mpd->size_to_align);
|
(unsigned int)mpd->size_to_align);
|
||||||
bio = mpage_bio_submit(WRITE | REQ_NOMERGE, bio);
|
bio = mpage_bio_submit_write(REQ_NOMERGE, bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -484,7 +497,7 @@ alloc_new:
|
||||||
*/
|
*/
|
||||||
length = first_unmapped << blkbits;
|
length = first_unmapped << blkbits;
|
||||||
if (bio_add_page(bio, page, length, 0) < length) {
|
if (bio_add_page(bio, page, length, 0) < length) {
|
||||||
bio = mpage_bio_submit(WRITE, bio);
|
bio = mpage_bio_submit_write(0, bio);
|
||||||
goto alloc_new;
|
goto alloc_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,7 +508,7 @@ alloc_new:
|
||||||
if (page_has_buffers(page)) {
|
if (page_has_buffers(page)) {
|
||||||
struct buffer_head *head = page_buffers(page);
|
struct buffer_head *head = page_buffers(page);
|
||||||
struct buffer_head *bh = head;
|
struct buffer_head *bh = head;
|
||||||
unsigned buffer_counter = 0;
|
unsigned int buffer_counter = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (buffer_counter++ == first_unmapped)
|
if (buffer_counter++ == first_unmapped)
|
||||||
|
|
@ -529,6 +542,7 @@ alloc_new:
|
||||||
(loff_t)((page->index + 1) << PAGE_SHIFT), __func__))) {
|
(loff_t)((page->index + 1) << PAGE_SHIFT), __func__))) {
|
||||||
struct buffer_head *head = page_buffers(page);
|
struct buffer_head *head = page_buffers(page);
|
||||||
struct buffer_head *bh = head;
|
struct buffer_head *bh = head;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
clear_buffer_mapped(bh);
|
clear_buffer_mapped(bh);
|
||||||
bh = bh->b_this_page;
|
bh = bh->b_this_page;
|
||||||
|
|
@ -537,7 +551,7 @@ alloc_new:
|
||||||
|
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
if (boundary || (first_unmapped != blocks_per_page)) {
|
if (boundary || (first_unmapped != blocks_per_page)) {
|
||||||
bio = mpage_bio_submit(WRITE, bio);
|
bio = mpage_bio_submit_write(0, bio);
|
||||||
if (boundary_block) {
|
if (boundary_block) {
|
||||||
write_boundary_block(boundary_bdev,
|
write_boundary_block(boundary_bdev,
|
||||||
boundary_block, 1 << blkbits);
|
boundary_block, 1 << blkbits);
|
||||||
|
|
@ -550,7 +564,7 @@ alloc_new:
|
||||||
|
|
||||||
confused:
|
confused:
|
||||||
if (bio)
|
if (bio)
|
||||||
bio = mpage_bio_submit(WRITE, bio);
|
bio = mpage_bio_submit_write(0, bio);
|
||||||
|
|
||||||
if (mpd->use_writepage) {
|
if (mpd->use_writepage) {
|
||||||
ret = mapping->a_ops->writepage(page, wbc);
|
ret = mapping->a_ops->writepage(page, wbc);
|
||||||
|
|
@ -581,12 +595,10 @@ int sdfat_mpage_writepages(struct address_space *mapping,
|
||||||
};
|
};
|
||||||
|
|
||||||
BUG_ON(!get_block);
|
BUG_ON(!get_block);
|
||||||
|
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
|
|
||||||
ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd);
|
ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd);
|
||||||
if (mpd.bio)
|
if (mpd.bio)
|
||||||
mpage_bio_submit(WRITE, mpd.bio);
|
mpage_bio_submit_write(0, mpd.bio);
|
||||||
blk_finish_plug(&plug);
|
blk_finish_plug(&plug);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
nls.c
65
nls.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -62,10 +60,10 @@ static u16 bad_dos_chars[] = {
|
||||||
static u16 bad_uni_chars[] = {
|
static u16 bad_uni_chars[] = {
|
||||||
0x0022, 0x002A, 0x002F, 0x003A,
|
0x0022, 0x002A, 0x002F, 0x003A,
|
||||||
0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
|
0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
|
||||||
/*
|
#if 0 /* allow full-width characters */
|
||||||
0x201C, 0x201D, 0xFF0A, 0xFF0F, 0xFF1A,
|
0x201C, 0x201D, 0xFF0A, 0xFF0F, 0xFF1A,
|
||||||
0xFF1C, 0xFF1E, 0xFF1F, 0xFF3C, 0xFF5C,
|
0xFF1C, 0xFF1E, 0xFF1F, 0xFF3C, 0xFF5C,
|
||||||
*/
|
#endif
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -101,7 +99,7 @@ u16 *nls_wstrchr(u16 *str, u16 wchar)
|
||||||
|
|
||||||
s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b)
|
s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b)
|
||||||
{
|
{
|
||||||
return(strncmp((void *) a, (void *) b, DOS_NAME_LENGTH));
|
return strncmp((void *)a, (void *)b, DOS_NAME_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b)
|
s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b)
|
||||||
|
|
@ -110,9 +108,9 @@ s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b)
|
||||||
|
|
||||||
for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
|
for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
|
||||||
if (nls_upper(sb, *a) != nls_upper(sb, *b))
|
if (nls_upper(sb, *a) != nls_upper(sb, *b))
|
||||||
return 1;
|
return 1;
|
||||||
if (*a == 0x0)
|
if (*a == 0x0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +144,8 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < DOS_NAME_LENGTH) {
|
while (i < DOS_NAME_LENGTH) {
|
||||||
if (i == 8) {
|
if (i == 8) {
|
||||||
if (last_period == NULL) break;
|
if (last_period == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
if (uniname <= last_period) {
|
if (uniname <= last_period) {
|
||||||
if (uniname < last_period)
|
if (uniname < last_period)
|
||||||
|
|
@ -172,9 +171,9 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T
|
||||||
len = convert_uni_to_ch(nls, *uniname, buf, &lossy);
|
len = convert_uni_to_ch(nls, *uniname, buf, &lossy);
|
||||||
|
|
||||||
if (len > 1) {
|
if (len > 1) {
|
||||||
if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) {
|
if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if ((i < 8) && ((i+len) > 8)) {
|
if ((i < 8) && ((i+len) > 8)) {
|
||||||
i = 8;
|
i = 8;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -182,9 +181,8 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T
|
||||||
|
|
||||||
lower = 0xFF;
|
lower = 0xFF;
|
||||||
|
|
||||||
for (j = 0; j < len; j++, i++) {
|
for (j = 0; j < len; j++, i++)
|
||||||
*(dosname+i) = *(buf+j);
|
*(dosname+i) = *(buf+j);
|
||||||
}
|
|
||||||
} else { /* len == 1 */
|
} else { /* len == 1 */
|
||||||
if ((*buf >= 'a') && (*buf <= 'z')) {
|
if ((*buf >= 'a') && (*buf <= 'z')) {
|
||||||
*(dosname+i) = *buf - ('a' - 'A');
|
*(dosname+i) = *buf - ('a' - 'A');
|
||||||
|
|
@ -209,17 +207,17 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*dosname == 0xE5)
|
if (*dosname == 0xE5)
|
||||||
*dosname = 0x05;
|
*dosname = 0x05;
|
||||||
if (*uniname != 0x0)
|
if (*uniname != 0x0)
|
||||||
lossy |= NLS_NAME_OVERLEN;
|
lossy |= NLS_NAME_OVERLEN;
|
||||||
|
|
||||||
if (upper & lower)
|
if (upper & lower)
|
||||||
p_dosname->name_case = 0xFF;
|
p_dosname->name_case = 0xFF;
|
||||||
else
|
else
|
||||||
p_dosname->name_case = lower;
|
p_dosname->name_case = lower;
|
||||||
|
|
||||||
if (p_lossy)
|
if (p_lossy)
|
||||||
*p_lossy = lossy;
|
*p_lossy = lossy;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,7 +289,8 @@ static s32 __nls_utf16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring, const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
|
static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
|
const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
|
||||||
{
|
{
|
||||||
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
|
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
|
||||||
u16 upname[MAX_NAME_LENGTH+1];
|
u16 upname[MAX_NAME_LENGTH+1];
|
||||||
|
|
@ -307,7 +306,7 @@ static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
return unilen;
|
return unilen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unilen > MAX_NAME_LENGTH ) {
|
if (unilen > MAX_NAME_LENGTH) {
|
||||||
MMSG("%s: failed to vfsname_to_utf16(estr:ENAMETOOLONG) "
|
MMSG("%s: failed to vfsname_to_utf16(estr:ENAMETOOLONG) "
|
||||||
"vfsnamelen:%d, unilen:%d>%d",
|
"vfsnamelen:%d, unilen:%d>%d",
|
||||||
__func__, len, unilen, MAX_NAME_LENGTH);
|
__func__, len, unilen, MAX_NAME_LENGTH);
|
||||||
|
|
@ -316,7 +315,7 @@ static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
|
|
||||||
p_uniname->name_len = (u8)(unilen & 0xFF);
|
p_uniname->name_len = (u8)(unilen & 0xFF);
|
||||||
|
|
||||||
for (i=0; i<unilen; i++) {
|
for (i = 0; i < unilen; i++) {
|
||||||
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
|
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
|
||||||
lossy |= NLS_NAME_LOSSY;
|
lossy |= NLS_NAME_LOSSY;
|
||||||
|
|
||||||
|
|
@ -344,8 +343,8 @@ static s32 __nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((i < MAX_NAME_LENGTH) && (out_len < (buflen-1))) {
|
while ((i < MAX_NAME_LENGTH) && (out_len < (buflen-1))) {
|
||||||
if (*uniname == (u16) '\0')
|
if (*uniname == (u16)'\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
len = convert_uni_to_ch(nls, *uniname, buf, NULL);
|
len = convert_uni_to_ch(nls, *uniname, buf, NULL);
|
||||||
|
|
||||||
|
|
@ -369,7 +368,8 @@ static s32 __nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname
|
||||||
return out_len;
|
return out_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 __nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
|
static s32 __nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
|
const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
|
||||||
{
|
{
|
||||||
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
|
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
|
||||||
u16 upname[MAX_NAME_LENGTH+1];
|
u16 upname[MAX_NAME_LENGTH+1];
|
||||||
|
|
@ -379,8 +379,8 @@ static s32 __nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
BUG_ON(!len);
|
BUG_ON(!len);
|
||||||
|
|
||||||
i = unilen = 0;
|
i = unilen = 0;
|
||||||
while ( (unilen < MAX_NAME_LENGTH) && (i < len)) {
|
while ((unilen < MAX_NAME_LENGTH) && (i < len)) {
|
||||||
i += convert_ch_to_uni(nls, (u8*)(p_cstring+i), uniname, &lossy);
|
i += convert_ch_to_uni(nls, (u8 *)(p_cstring+i), uniname, &lossy);
|
||||||
|
|
||||||
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
|
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
|
||||||
lossy |= NLS_NAME_LOSSY;
|
lossy |= NLS_NAME_LOSSY;
|
||||||
|
|
@ -435,16 +435,16 @@ static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((len = nls->char2uni(ch, MAX_CHARSET_SIZE, uni)) < 0) {
|
len = nls->char2uni(ch, MAX_CHARSET_SIZE, uni);
|
||||||
|
if (len < 0) {
|
||||||
/* conversion failed */
|
/* conversion failed */
|
||||||
DMSG("%s: fail to use nls \n", __func__);
|
DMSG("%s: fail to use nls\n", __func__);
|
||||||
if (lossy != NULL)
|
if (lossy != NULL)
|
||||||
*lossy |= NLS_NAME_LOSSY;
|
*lossy |= NLS_NAME_LOSSY;
|
||||||
*uni = (u16) '_';
|
*uni = (u16) '_';
|
||||||
if (!strcmp(nls->charset, "utf8"))
|
if (!strcmp(nls->charset, "utf8"))
|
||||||
return 1;
|
return 1;
|
||||||
else
|
return 2;
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
|
@ -461,9 +461,10 @@ static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((len = nls->uni2char(uni, ch, MAX_CHARSET_SIZE)) < 0) {
|
len = nls->uni2char(uni, ch, MAX_CHARSET_SIZE);
|
||||||
|
if (len < 0) {
|
||||||
/* conversion failed */
|
/* conversion failed */
|
||||||
DMSG("%s: fail to use nls \n", __func__);
|
DMSG("%s: fail to use nls\n", __func__);
|
||||||
if (lossy != NULL)
|
if (lossy != NULL)
|
||||||
*lossy |= NLS_NAME_LOSSY;
|
*lossy |= NLS_NAME_LOSSY;
|
||||||
ch[0] = '_';
|
ch[0] = '_';
|
||||||
|
|
|
||||||
142
sdfat.h
142
sdfat.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_H
|
#ifndef _SDFAT_H
|
||||||
|
|
@ -38,25 +36,25 @@
|
||||||
/*
|
/*
|
||||||
* sdfat error flags
|
* sdfat error flags
|
||||||
*/
|
*/
|
||||||
#define SDFAT_ERRORS_CONT 1 /* ignore error and continue */
|
#define SDFAT_ERRORS_CONT (1) /* ignore error and continue */
|
||||||
#define SDFAT_ERRORS_PANIC 2 /* panic on error */
|
#define SDFAT_ERRORS_PANIC (2) /* panic on error */
|
||||||
#define SDFAT_ERRORS_RO 3 /* remount r/o on error */
|
#define SDFAT_ERRORS_RO (3) /* remount r/o on error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sdfat allocator flags
|
* sdfat allocator flags
|
||||||
*/
|
*/
|
||||||
#define SDFAT_ALLOC_DELAY 1 /* Delayed allocation */
|
#define SDFAT_ALLOC_DELAY (1) /* Delayed allocation */
|
||||||
#define SDFAT_ALLOC_SMART 2 /* Smart allocation */
|
#define SDFAT_ALLOC_SMART (2) /* Smart allocation */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sdfat allocator destination for smart allocation
|
* sdfat allocator destination for smart allocation
|
||||||
*/
|
*/
|
||||||
#define ALLOC_NOWHERE 0
|
#define ALLOC_NOWHERE (0)
|
||||||
#define ALLOC_COLD 1
|
#define ALLOC_COLD (1)
|
||||||
#define ALLOC_HOT 16
|
#define ALLOC_HOT (16)
|
||||||
#define ALLOC_COLD_ALIGNED 1
|
#define ALLOC_COLD_ALIGNED (1)
|
||||||
#define ALLOC_COLD_PACKING 2
|
#define ALLOC_COLD_PACKING (2)
|
||||||
#define ALLOC_COLD_SEQ 4
|
#define ALLOC_COLD_SEQ (4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sdfat nls lossy flag
|
* sdfat nls lossy flag
|
||||||
|
|
@ -71,22 +69,24 @@
|
||||||
#define CLUSTER_16(x) ((u16)((x) & 0xFFFFU))
|
#define CLUSTER_16(x) ((u16)((x) & 0xFFFFU))
|
||||||
#define CLUSTER_32(x) ((u32)((x) & 0xFFFFFFFFU))
|
#define CLUSTER_32(x) ((u32)((x) & 0xFFFFFFFFU))
|
||||||
#define CLUS_EOF CLUSTER_32(~0)
|
#define CLUS_EOF CLUSTER_32(~0)
|
||||||
|
#define CLUS_BAD (0xFFFFFFF7U)
|
||||||
#define CLUS_FREE (0)
|
#define CLUS_FREE (0)
|
||||||
#define CLUS_BASE (2)
|
#define CLUS_BASE (2)
|
||||||
#define IS_CLUS_EOF(x) (x == CLUS_EOF)
|
#define IS_CLUS_EOF(x) ((x) == CLUS_EOF)
|
||||||
#define IS_CLUS_FREE(x) (x == CLUS_FREE)
|
#define IS_CLUS_BAD(x) ((x) == CLUS_BAD)
|
||||||
#define IS_LAST_SECT_IN_CLUS(fsi, sec) \
|
#define IS_CLUS_FREE(x) ((x) == CLUS_FREE)
|
||||||
( (((sec) - (fsi)->data_start_sector + 1) \
|
#define IS_LAST_SECT_IN_CLUS(fsi, sec) \
|
||||||
& ((1 << (fsi)->sect_per_clus_bits) -1)) == 0 )
|
((((sec) - (fsi)->data_start_sector + 1) \
|
||||||
|
& ((1 << (fsi)->sect_per_clus_bits) - 1)) == 0)
|
||||||
|
|
||||||
#define CLUS_TO_SECT(fsi, x) \
|
#define CLUS_TO_SECT(fsi, x) \
|
||||||
( (((x) - CLUS_BASE) << (fsi)->sect_per_clus_bits) + (fsi)->data_start_sector )
|
((((x) - CLUS_BASE) << (fsi)->sect_per_clus_bits) + (fsi)->data_start_sector)
|
||||||
|
|
||||||
#define SECT_TO_CLUS(fsi, sec) \
|
#define SECT_TO_CLUS(fsi, sec) \
|
||||||
((((sec) - (fsi)->data_start_sector) >> (fsi)->sect_per_clus_bits) + CLUS_BASE)
|
((((sec) - (fsi)->data_start_sector) >> (fsi)->sect_per_clus_bits) + CLUS_BASE)
|
||||||
|
|
||||||
/* variables defined at sdfat.c */
|
/* variables defined at sdfat.c */
|
||||||
extern const char* FS_TYPE_STR[];
|
extern const char *FS_TYPE_STR[];
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FS_TYPE_AUTO,
|
FS_TYPE_AUTO,
|
||||||
|
|
@ -99,12 +99,12 @@ enum {
|
||||||
* sdfat mount in-memory data
|
* sdfat mount in-memory data
|
||||||
*/
|
*/
|
||||||
struct sdfat_mount_options {
|
struct sdfat_mount_options {
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
|
||||||
uid_t fs_uid;
|
|
||||||
gid_t fs_gid;
|
|
||||||
#else
|
|
||||||
kuid_t fs_uid;
|
kuid_t fs_uid;
|
||||||
kgid_t fs_gid;
|
kgid_t fs_gid;
|
||||||
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
|
||||||
|
uid_t fs_uid;
|
||||||
|
gid_t fs_gid;
|
||||||
#endif
|
#endif
|
||||||
unsigned short fs_fmask;
|
unsigned short fs_fmask;
|
||||||
unsigned short fs_dmask;
|
unsigned short fs_dmask;
|
||||||
|
|
@ -142,7 +142,7 @@ struct sdfat_sb_info {
|
||||||
struct mutex s_vlock; /* volume lock */
|
struct mutex s_vlock; /* volume lock */
|
||||||
int use_vmalloc;
|
int use_vmalloc;
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
|
||||||
int s_dirt;
|
int s_dirt;
|
||||||
struct mutex s_lock; /* superblock lock */
|
struct mutex s_lock; /* superblock lock */
|
||||||
int write_super_queued; /* Write_super work is pending? */
|
int write_super_queued; /* Write_super work is pending? */
|
||||||
|
|
@ -195,12 +195,12 @@ struct sdfat_sb_info {
|
||||||
struct sdfat_inode_info {
|
struct sdfat_inode_info {
|
||||||
FILE_ID_T fid;
|
FILE_ID_T fid;
|
||||||
char *target;
|
char *target;
|
||||||
/* NOTE: i_size_ondisk is 64bits, so must hold ->i_mutex to access */
|
/* NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access */
|
||||||
loff_t i_size_ondisk; /* physically allocated size */
|
loff_t i_size_ondisk; /* physically allocated size */
|
||||||
loff_t i_size_aligned; /* block-aligned i_size (used in cont_write_begin) */
|
loff_t i_size_aligned; /* block-aligned i_size (used in cont_write_begin) */
|
||||||
loff_t i_pos; /* on-disk position of directory entry or 0 */
|
loff_t i_pos; /* on-disk position of directory entry or 0 */
|
||||||
struct hlist_node i_hash_fat; /* hash by i_location */
|
struct hlist_node i_hash_fat; /* hash by i_location */
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
||||||
struct rw_semaphore truncate_lock; /* protect bmap against truncate */
|
struct rw_semaphore truncate_lock; /* protect bmap against truncate */
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SDFAT_DFR
|
#ifdef CONFIG_SDFAT_DFR
|
||||||
|
|
@ -218,7 +218,7 @@ static inline const char *sdfat_get_vol_type_str(unsigned int type)
|
||||||
{
|
{
|
||||||
if (type == EXFAT)
|
if (type == EXFAT)
|
||||||
return "exfat";
|
return "exfat";
|
||||||
else if (type == FAT32)
|
else if (type == FAT32)
|
||||||
return "vfat:32";
|
return "vfat:32";
|
||||||
else if (type == FAT16)
|
else if (type == FAT16)
|
||||||
return "vfat:16";
|
return "vfat:16";
|
||||||
|
|
@ -230,7 +230,7 @@ static inline const char *sdfat_get_vol_type_str(unsigned int type)
|
||||||
|
|
||||||
static inline struct sdfat_sb_info *SDFAT_SB(struct super_block *sb)
|
static inline struct sdfat_sb_info *SDFAT_SB(struct super_block *sb)
|
||||||
{
|
{
|
||||||
return (struct sdfat_sb_info*)sb->s_fs_info;
|
return (struct sdfat_sb_info *)sb->s_fs_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sdfat_inode_info *SDFAT_I(struct inode *inode)
|
static inline struct sdfat_inode_info *SDFAT_I(struct inode *inode)
|
||||||
|
|
@ -279,6 +279,7 @@ static inline mode_t sdfat_make_mode(struct sdfat_sb_info *sbi,
|
||||||
static inline u32 sdfat_make_attr(struct inode *inode)
|
static inline u32 sdfat_make_attr(struct inode *inode)
|
||||||
{
|
{
|
||||||
u32 attrs = SDFAT_I(inode)->fid.attr;
|
u32 attrs = SDFAT_I(inode)->fid.attr;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
attrs |= ATTR_SUBDIR;
|
attrs |= ATTR_SUBDIR;
|
||||||
if (sdfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO))
|
if (sdfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO))
|
||||||
|
|
@ -294,6 +295,31 @@ static inline void sdfat_save_attr(struct inode *inode, u32 attr)
|
||||||
SDFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY);
|
SDFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sdfat/statistics.c */
|
||||||
|
/* bigdata function */
|
||||||
|
#ifdef CONFIG_SDFAT_STATISTICS
|
||||||
|
extern int sdfat_statistics_init(struct kset *sdfat_kset);
|
||||||
|
extern void sdfat_statistics_uninit(void);
|
||||||
|
extern void sdfat_statistics_set_mnt(FS_INFO_T *fsi);
|
||||||
|
extern void sdfat_statistics_set_mkdir(u8 flags);
|
||||||
|
extern void sdfat_statistics_set_create(u8 flags);
|
||||||
|
extern void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create);
|
||||||
|
extern void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu);
|
||||||
|
extern void sdfat_statistics_set_vol_size(struct super_block *sb);
|
||||||
|
#else
|
||||||
|
static inline int sdfat_statistics_init(struct kset *sdfat_kset)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline void sdfat_statistics_uninit(void) {};
|
||||||
|
static inline void sdfat_statistics_set_mnt(FS_INFO_T *fsi) {};
|
||||||
|
static inline void sdfat_statistics_set_mkdir(u8 flags) {};
|
||||||
|
static inline void sdfat_statistics_set_create(u8 flags) {};
|
||||||
|
static inline void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create) {};
|
||||||
|
static inline void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu) {};
|
||||||
|
static inline void sdfat_statistics_set_vol_size(struct super_block *sb) {};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* sdfat/nls.c */
|
/* sdfat/nls.c */
|
||||||
/* NLS management function */
|
/* NLS management function */
|
||||||
s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b);
|
s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b);
|
||||||
|
|
@ -301,37 +327,41 @@ s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b);
|
||||||
s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname, s32 *p_lossy);
|
s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname, s32 *p_lossy);
|
||||||
s32 nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname);
|
s32 nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname);
|
||||||
s32 nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 len);
|
s32 nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 len);
|
||||||
s32 nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, const s32 len, UNI_NAME_T *uniname, s32 *p_lossy);
|
s32 nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring,
|
||||||
|
const s32 len, UNI_NAME_T *uniname, s32 *p_lossy);
|
||||||
|
|
||||||
/* sdfat/mpage.c */
|
/* sdfat/mpage.c */
|
||||||
#ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE
|
#ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE
|
||||||
int sdfat_mpage_writepages(struct address_space *mapping,
|
int sdfat_mpage_writepages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc, get_block_t *get_block);
|
struct writeback_control *wbc, get_block_t *get_block);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sdfat/xattr.c */
|
/* sdfat/xattr.c */
|
||||||
#ifdef CONFIG_SDFAT_VIRTUAL_XATTR
|
#ifdef CONFIG_SDFAT_VIRTUAL_XATTR
|
||||||
extern int sdfat_setxattr(struct dentry*dentry, const char *name, const void *value, size_t size, int flags);
|
void setup_sdfat_xattr_handler(struct super_block *sb);
|
||||||
|
extern int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
|
||||||
extern ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size);
|
extern ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size);
|
||||||
extern ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size);
|
extern ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size);
|
||||||
extern int sdfat_removexattr(struct dentry *dentry, const char *name);
|
extern int sdfat_removexattr(struct dentry *dentry, const char *name);
|
||||||
|
#else
|
||||||
|
static inline void setup_sdfat_xattr_handler(struct super_block *sb) {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sdfat/misc.c */
|
/* sdfat/misc.c */
|
||||||
extern void
|
extern void
|
||||||
__sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
__sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
||||||
__attribute__ ((format (printf, 3, 4))) __cold;
|
__printf(3, 4) __cold;
|
||||||
#define sdfat_fs_error(sb, fmt, args...) \
|
#define sdfat_fs_error(sb, fmt, args...) \
|
||||||
__sdfat_fs_error(sb, 1, fmt , ## args)
|
__sdfat_fs_error(sb, 1, fmt, ## args)
|
||||||
#define sdfat_fs_error_ratelimit(sb, fmt, args...) \
|
#define sdfat_fs_error_ratelimit(sb, fmt, args...) \
|
||||||
__sdfat_fs_error(sb, __ratelimit(&SDFAT_SB(sb)->ratelimit), fmt, ## args)
|
__sdfat_fs_error(sb, __ratelimit(&SDFAT_SB(sb)->ratelimit), fmt, ## args)
|
||||||
extern void
|
extern void
|
||||||
__sdfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...)
|
__sdfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...)
|
||||||
__attribute__ ((format (printf, 4, 5))) __cold;
|
__printf(4, 5) __cold;
|
||||||
#define sdfat_msg(sb, lv, fmt, args...) \
|
#define sdfat_msg(sb, lv, fmt, args...) \
|
||||||
__sdfat_msg(sb, lv, 0, fmt , ## args)
|
__sdfat_msg(sb, lv, 0, fmt, ## args)
|
||||||
#define sdfat_log_msg(sb, lv, fmt, args...) \
|
#define sdfat_log_msg(sb, lv, fmt, args...) \
|
||||||
__sdfat_msg(sb, lv, 1, fmt , ## args)
|
__sdfat_msg(sb, lv, 1, fmt, ## args)
|
||||||
extern void sdfat_log_version(void);
|
extern void sdfat_log_version(void);
|
||||||
extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
|
extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
|
||||||
DATE_TIME_T *tp);
|
DATE_TIME_T *tp);
|
||||||
|
|
@ -367,20 +397,16 @@ void sdfat_debug_check_clusters(struct inode *inode);
|
||||||
#endif /* CONFIG_SDFAT_DEBUG */
|
#endif /* CONFIG_SDFAT_DEBUG */
|
||||||
|
|
||||||
#ifdef CONFIG_SDFAT_TRACE_ELAPSED_TIME
|
#ifdef CONFIG_SDFAT_TRACE_ELAPSED_TIME
|
||||||
u32 sdfat_time_current_usec(struct timeval* tv);
|
u32 sdfat_time_current_usec(struct timeval *tv);
|
||||||
extern struct timeval __t1;
|
extern struct timeval __t1;
|
||||||
extern struct timeval __t2;
|
extern struct timeval __t2;
|
||||||
|
|
||||||
#define TIME_GET(tv) sdfat_time_current_usec(tv)
|
#define TIME_GET(tv) sdfat_time_current_usec(tv)
|
||||||
#define TIME_START(s) do {sdfat_time_current_usec(s); } while (0)
|
#define TIME_START(s) sdfat_time_current_usec(s)
|
||||||
#define TIME_END(e) do {sdfat_time_current_usec(e); } while (0)
|
#define TIME_END(e) sdfat_time_current_usec(e)
|
||||||
#define TIME_ELAPSED(s, e) ((u32)(((e)->tv_sec - (s)->tv_sec) * 1000000 + \
|
#define TIME_ELAPSED(s, e) ((u32)(((e)->tv_sec - (s)->tv_sec) * 1000000 + \
|
||||||
((e)->tv_usec - (s)->tv_usec)))
|
((e)->tv_usec - (s)->tv_usec)))
|
||||||
#define PRINT_TIME(n) \
|
#define PRINT_TIME(n) pr_info("[SDFAT] Elapsed time %d = %d (usec)\n", n, (__t2 - __t1))
|
||||||
do { \
|
|
||||||
printk("[SDFAT] Elapsed time %d = %d (usec)\n", \
|
|
||||||
n, (__t2 - __t1)); \
|
|
||||||
} while(0)
|
|
||||||
#else /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */
|
#else /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */
|
||||||
#define TIME_GET(tv) (0)
|
#define TIME_GET(tv) (0)
|
||||||
#define TIME_START(s)
|
#define TIME_START(s)
|
||||||
|
|
@ -403,11 +429,12 @@ extern struct timeval __t2;
|
||||||
#define __S(x) #x
|
#define __S(x) #x
|
||||||
#define _S(x) __S(x)
|
#define _S(x) __S(x)
|
||||||
|
|
||||||
extern void __sdfat_dmsg(int level, const char *fmt, ...)
|
extern void __sdfat_dmsg(int level, const char *fmt, ...) __printf(2, 3) __cold;
|
||||||
__attribute__ ((format (printf, 2, 3))) __cold;
|
|
||||||
|
|
||||||
#define SDFAT_EMSG_T(level, ...) __sdfat_dmsg(level, KERN_ERR "[" SDFAT_TAG_NAME "] [" _S(__FILE__) "(" _S(__LINE__) ")] " __VA_ARGS__)
|
#define SDFAT_EMSG_T(level, ...) \
|
||||||
#define SDFAT_DMSG_T(level, ...) __sdfat_dmsg(level, KERN_INFO "[" SDFAT_TAG_NAME "] " __VA_ARGS__)
|
__sdfat_dmsg(level, KERN_ERR "[" SDFAT_TAG_NAME "] [" _S(__FILE__) "(" _S(__LINE__) ")] " __VA_ARGS__)
|
||||||
|
#define SDFAT_DMSG_T(level, ...) \
|
||||||
|
__sdfat_dmsg(level, KERN_INFO "[" SDFAT_TAG_NAME "] " __VA_ARGS__)
|
||||||
|
|
||||||
#define SDFAT_EMSG(...) SDFAT_EMSG_T(SDFAT_MSG_LV_ERR, __VA_ARGS__)
|
#define SDFAT_EMSG(...) SDFAT_EMSG_T(SDFAT_MSG_LV_ERR, __VA_ARGS__)
|
||||||
#define SDFAT_IMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_INFO, __VA_ARGS__)
|
#define SDFAT_IMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_INFO, __VA_ARGS__)
|
||||||
|
|
@ -469,11 +496,12 @@ extern void __sdfat_dmsg(int level, const char *fmt, ...)
|
||||||
#endif /* CONFIG_SDFAT_DBG_MSG */
|
#endif /* CONFIG_SDFAT_DBG_MSG */
|
||||||
|
|
||||||
|
|
||||||
#define ASSERT(expr) \
|
#define ASSERT(expr) { \
|
||||||
if (!(expr)) { \
|
if (!(expr)) { \
|
||||||
printk(KERN_ERR "Assertion failed! %s\n", #expr); \
|
pr_err("Assertion failed! %s\n", #expr); \
|
||||||
BUG_ON(1); \
|
BUG_ON(1); \
|
||||||
}
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !_SDFAT_H */
|
#endif /* !_SDFAT_H */
|
||||||
|
|
||||||
|
|
|
||||||
20
sdfat_fs.h
20
sdfat_fs.h
|
|
@ -12,8 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDFAT_FS_H
|
#ifndef _SDFAT_FS_H
|
||||||
|
|
@ -59,7 +58,7 @@
|
||||||
/* NOTE :
|
/* NOTE :
|
||||||
* The maximum length of input or output is limited to 256 including NULL,
|
* The maximum length of input or output is limited to 256 including NULL,
|
||||||
* But we allocate 4 extra bytes for utf8 translation reside in last position,
|
* But we allocate 4 extra bytes for utf8 translation reside in last position,
|
||||||
* because utf8 can uses memory upto 6 bytes per one charactor.
|
* because utf8 can uses memory upto 6 bytes per one character.
|
||||||
* Therefore, MAX_CHARSET_SIZE supports upto 6 bytes for utf8
|
* Therefore, MAX_CHARSET_SIZE supports upto 6 bytes for utf8
|
||||||
*/
|
*/
|
||||||
#define MAX_UNINAME_BUF_SIZE (((MAX_NAME_LENGTH+1)*2)+4)
|
#define MAX_UNINAME_BUF_SIZE (((MAX_NAME_LENGTH+1)*2)+4)
|
||||||
|
|
@ -73,6 +72,7 @@
|
||||||
#define DENTRY_SIZE_BITS 5
|
#define DENTRY_SIZE_BITS 5
|
||||||
|
|
||||||
#define MAX_FAT_DENTRIES 65536 /* FAT allows 65536 directory entries */
|
#define MAX_FAT_DENTRIES 65536 /* FAT allows 65536 directory entries */
|
||||||
|
#define MAX_EXFAT_DENTRIES 8388608 /* exFAT allows 8388608(256MB) directory entries */
|
||||||
|
|
||||||
/* PBR entries */
|
/* PBR entries */
|
||||||
#define PBR_SIGNATURE 0xAA55
|
#define PBR_SIGNATURE 0xAA55
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
#define MSDOS_UNUSED 0x00 /* end of directory */
|
#define MSDOS_UNUSED 0x00 /* end of directory */
|
||||||
|
|
||||||
#define EXFAT_UNUSED 0x00 /* end of directory */
|
#define EXFAT_UNUSED 0x00 /* end of directory */
|
||||||
#define IS_EXFAT_DELETED(x) ((x)<0x80) /* deleted file (0x01~0x7F) */
|
#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */
|
||||||
#define EXFAT_INVAL 0x80 /* invalid value */
|
#define EXFAT_INVAL 0x80 /* invalid value */
|
||||||
#define EXFAT_BITMAP 0x81 /* allocation bitmap */
|
#define EXFAT_BITMAP 0x81 /* allocation bitmap */
|
||||||
#define EXFAT_UPCASE 0x82 /* upcase table */
|
#define EXFAT_UPCASE 0x82 /* upcase table */
|
||||||
|
|
@ -148,7 +148,7 @@
|
||||||
*/
|
*/
|
||||||
#define SDFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
|
#define SDFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
|
||||||
#define SDFAT_IOCTL_DFR_INFO _IOC(_IOC_NONE, 'E', 0x13, sizeof(u32))
|
#define SDFAT_IOCTL_DFR_INFO _IOC(_IOC_NONE, 'E', 0x13, sizeof(u32))
|
||||||
#define SDFAT_IOCTL_DFR_TRAV _IOC(_IOC_NONE, 'E', 0x14, sizeof(u32))
|
#define SDFAT_IOCTL_DFR_TRAV _IOC(_IOC_NONE, 'E', 0x14, sizeof(u32))
|
||||||
#define SDFAT_IOCTL_DFR_REQ _IOC(_IOC_NONE, 'E', 0x15, sizeof(u32))
|
#define SDFAT_IOCTL_DFR_REQ _IOC(_IOC_NONE, 'E', 0x15, sizeof(u32))
|
||||||
#define SDFAT_IOCTL_DFR_SPO_FLAG _IOC(_IOC_NONE, 'E', 0x16, sizeof(u32))
|
#define SDFAT_IOCTL_DFR_SPO_FLAG _IOC(_IOC_NONE, 'E', 0x16, sizeof(u32))
|
||||||
#define SDFAT_IOCTL_PANIC _IOC(_IOC_NONE, 'E', 0x17, sizeof(u32))
|
#define SDFAT_IOCTL_PANIC _IOC(_IOC_NONE, 'E', 0x17, sizeof(u32))
|
||||||
|
|
@ -162,7 +162,7 @@
|
||||||
* - file systems typically #0~0x1F
|
* - file systems typically #0~0x1F
|
||||||
* - embedded terminal devices #128~
|
* - embedded terminal devices #128~
|
||||||
* - exts for debugging purpose #99
|
* - exts for debugging purpose #99
|
||||||
* number 100 and 101 is availble now but has possible conflicts
|
* number 100 and 101 is available now but has possible conflicts
|
||||||
*
|
*
|
||||||
* NOTE : This is available only If CONFIG_SDFAT_DVBG_IOCTL is enabled.
|
* NOTE : This is available only If CONFIG_SDFAT_DVBG_IOCTL is enabled.
|
||||||
*
|
*
|
||||||
|
|
@ -184,15 +184,15 @@ typedef struct {
|
||||||
|
|
||||||
__u8 sect_size[2]; /* unaligned */
|
__u8 sect_size[2]; /* unaligned */
|
||||||
__u8 sect_per_clus;
|
__u8 sect_per_clus;
|
||||||
__le16 num_reserved; /* . */
|
__le16 num_reserved; /* . */
|
||||||
__u8 num_fats;
|
__u8 num_fats;
|
||||||
__u8 num_root_entries[2]; /* unaligned */
|
__u8 num_root_entries[2]; /* unaligned */
|
||||||
__u8 num_sectors[2]; /* unaligned */
|
__u8 num_sectors[2]; /* unaligned */
|
||||||
__u8 media_type;
|
__u8 media_type;
|
||||||
__le16 num_fat_sectors;
|
__le16 num_fat_sectors;
|
||||||
__le16 sectors_in_track;
|
__le16 sectors_in_track;
|
||||||
__le16 num_heads;
|
__le16 num_heads;
|
||||||
__le32 num_hid_sectors; /* . */
|
__le32 num_hid_sectors; /* . */
|
||||||
__le32 num_huge_sectors;
|
__le32 num_huge_sectors;
|
||||||
|
|
||||||
__u8 phy_drv_no;
|
__u8 phy_drv_no;
|
||||||
|
|
@ -213,7 +213,7 @@ typedef struct {
|
||||||
__u8 sect_per_clus;
|
__u8 sect_per_clus;
|
||||||
__le16 num_reserved;
|
__le16 num_reserved;
|
||||||
__u8 num_fats;
|
__u8 num_fats;
|
||||||
__u8 num_root_entries[2]; /* unaligned */
|
__u8 num_root_entries[2]; /* unaligned */
|
||||||
__u8 num_sectors[2]; /* unaligned */
|
__u8 num_sectors[2]; /* unaligned */
|
||||||
__u8 media_type;
|
__u8 media_type;
|
||||||
__le16 num_fat_sectors; /* zero */
|
__le16 num_fat_sectors; /* zero */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
#include "sdfat.h"
|
||||||
|
|
||||||
|
#define SDFAT_VF_CLUS_MAX 7 /* 512 Byte ~ 32 KByte */
|
||||||
|
#define SDFAT_EF_CLUS_MAX 17 /* 512 Byte ~ 32 MByte */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SDFAT_MNT_FAT12,
|
||||||
|
SDFAT_MNT_FAT16,
|
||||||
|
SDFAT_MNT_FAT32,
|
||||||
|
SDFAT_MNT_EXFAT,
|
||||||
|
SDFAT_MNT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SDFAT_OP_EXFAT_MNT,
|
||||||
|
SDFAT_OP_MKDIR,
|
||||||
|
SDFAT_OP_CREATE,
|
||||||
|
SDFAT_OP_READ,
|
||||||
|
SDFAT_OP_WRITE,
|
||||||
|
SDFAT_OP_TRUNC,
|
||||||
|
SDFAT_OP_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SDFAT_VOL_4G,
|
||||||
|
SDFAT_VOL_8G,
|
||||||
|
SDFAT_VOL_16G,
|
||||||
|
SDFAT_VOL_32G,
|
||||||
|
SDFAT_VOL_64G,
|
||||||
|
SDFAT_VOL_128G,
|
||||||
|
SDFAT_VOL_256G,
|
||||||
|
SDFAT_VOL_512G,
|
||||||
|
SDFAT_VOL_XTB,
|
||||||
|
SDFAT_VOL_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sdfat_statistics {
|
||||||
|
u32 clus_vfat[SDFAT_VF_CLUS_MAX];
|
||||||
|
u32 clus_exfat[SDFAT_EF_CLUS_MAX];
|
||||||
|
u32 mnt_cnt[SDFAT_MNT_MAX];
|
||||||
|
u32 nofat_op[SDFAT_OP_MAX];
|
||||||
|
u32 vol_size[SDFAT_VOL_MAX];
|
||||||
|
} statistics;
|
||||||
|
|
||||||
|
static struct kset *sdfat_statistics_kset;
|
||||||
|
|
||||||
|
static ssize_t vfat_cl_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buff)
|
||||||
|
{
|
||||||
|
return snprintf(buff, PAGE_SIZE, "VCL_512B_I:%u,VCL_1K_I:%u,VCL_2K_I:%u,"
|
||||||
|
"VCL_4K_I:%u,VCL_8K_I:%u,VCL_16K_I:%u,VCL_32K_I:%u\n",
|
||||||
|
statistics.clus_vfat[0], statistics.clus_vfat[1],
|
||||||
|
statistics.clus_vfat[2], statistics.clus_vfat[3],
|
||||||
|
statistics.clus_vfat[4], statistics.clus_vfat[5],
|
||||||
|
statistics.clus_vfat[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t exfat_cl_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buff)
|
||||||
|
{
|
||||||
|
return snprintf(buff, PAGE_SIZE, "ECL_512B_I:%u,ECL_1K_I:%u,ECL_2K_I:%u,"
|
||||||
|
"ECL_4K_I:%u,ECL_8K_I:%u,ECL_16K_I:%u,ECL_32K_I:%u,ECL_64K_I:%u,"
|
||||||
|
"ECL_128K_I:%u,ECL_256K_I:%u,ECL_512K_I:%u,ECL_1M_I:%u,"
|
||||||
|
"ECL_2M_I:%u,ECL_4M_I:%u,ECL_8M_I:%u,ECL_16M_I:%u,ECL_32M_I:%u\n",
|
||||||
|
statistics.clus_exfat[0], statistics.clus_exfat[1],
|
||||||
|
statistics.clus_exfat[2], statistics.clus_exfat[3],
|
||||||
|
statistics.clus_exfat[4], statistics.clus_exfat[5],
|
||||||
|
statistics.clus_exfat[6], statistics.clus_exfat[7],
|
||||||
|
statistics.clus_exfat[8], statistics.clus_exfat[9],
|
||||||
|
statistics.clus_exfat[10], statistics.clus_exfat[11],
|
||||||
|
statistics.clus_exfat[12], statistics.clus_exfat[13],
|
||||||
|
statistics.clus_exfat[14], statistics.clus_exfat[15],
|
||||||
|
statistics.clus_exfat[16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mount_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buff)
|
||||||
|
{
|
||||||
|
return snprintf(buff, PAGE_SIZE, "FAT12_MNT_I:%u,FAT16_MNT_I:%u,FAT32_MNT_I:%u,"
|
||||||
|
"EXFAT_MNT_I:%u\n",
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT12],
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT16],
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT32],
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_EXFAT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t nofat_op_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buff)
|
||||||
|
{
|
||||||
|
return snprintf(buff, PAGE_SIZE, "NOFAT_MOUNT_I:%u,NOFAT_MKDIR_I:%u,NOFAT_CREATE_I:%u,"
|
||||||
|
"NOFAT_READ_I:%u,NOFAT_WRITE_I:%u,NOFAT_TRUNC_I:%u\n",
|
||||||
|
statistics.nofat_op[SDFAT_OP_EXFAT_MNT],
|
||||||
|
statistics.nofat_op[SDFAT_OP_MKDIR],
|
||||||
|
statistics.nofat_op[SDFAT_OP_CREATE],
|
||||||
|
statistics.nofat_op[SDFAT_OP_READ],
|
||||||
|
statistics.nofat_op[SDFAT_OP_WRITE],
|
||||||
|
statistics.nofat_op[SDFAT_OP_TRUNC]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t vol_size_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buff)
|
||||||
|
{
|
||||||
|
return snprintf(buff, PAGE_SIZE, "VOL_4G_I:%u,VOL_8G_I:%u,VOL_16G_I:%u,"
|
||||||
|
"VOL_32G_I:%u,VOL_64G_I:%u,VOL_128G_I:%u,VOL_256G_I:%u,"
|
||||||
|
"VOL_512G_I:%u,VOL_XTB_I:%u\n",
|
||||||
|
statistics.vol_size[SDFAT_VOL_4G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_8G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_16G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_32G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_64G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_128G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_256G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_512G],
|
||||||
|
statistics.vol_size[SDFAT_VOL_XTB]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kobj_attribute vfat_cl_attr = __ATTR_RO(vfat_cl);
|
||||||
|
static struct kobj_attribute exfat_cl_attr = __ATTR_RO(exfat_cl);
|
||||||
|
static struct kobj_attribute mount_attr = __ATTR_RO(mount);
|
||||||
|
static struct kobj_attribute nofat_op_attr = __ATTR_RO(nofat_op);
|
||||||
|
static struct kobj_attribute vol_size_attr = __ATTR_RO(vol_size);
|
||||||
|
|
||||||
|
static struct attribute *attributes_statistics[] = {
|
||||||
|
&vfat_cl_attr.attr,
|
||||||
|
&exfat_cl_attr.attr,
|
||||||
|
&mount_attr.attr,
|
||||||
|
&nofat_op_attr.attr,
|
||||||
|
&vol_size_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group attr_group_statistics = {
|
||||||
|
.attrs = attributes_statistics,
|
||||||
|
};
|
||||||
|
|
||||||
|
int sdfat_statistics_init(struct kset *sdfat_kset)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sdfat_statistics_kset = kset_create_and_add("statistics", NULL, &sdfat_kset->kobj);
|
||||||
|
if (!sdfat_statistics_kset) {
|
||||||
|
pr_err("[SDFAT] failed to create sdfat statistics kobj\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sysfs_create_group(&sdfat_statistics_kset->kobj, &attr_group_statistics);
|
||||||
|
if (err) {
|
||||||
|
pr_err("[SDFAT] failed to create sdfat statistics attributes\n");
|
||||||
|
kset_unregister(sdfat_statistics_kset);
|
||||||
|
sdfat_statistics_kset = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdfat_statistics_uninit(void)
|
||||||
|
{
|
||||||
|
if (sdfat_statistics_kset) {
|
||||||
|
sysfs_remove_group(&sdfat_statistics_kset->kobj, &attr_group_statistics);
|
||||||
|
kset_unregister(sdfat_statistics_kset);
|
||||||
|
sdfat_statistics_kset = NULL;
|
||||||
|
}
|
||||||
|
memset(&statistics, 0, sizeof(struct sdfat_statistics));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdfat_statistics_set_mnt(FS_INFO_T *fsi)
|
||||||
|
{
|
||||||
|
if (fsi->vol_type == EXFAT) {
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_EXFAT]++;
|
||||||
|
statistics.nofat_op[SDFAT_OP_EXFAT_MNT] = 1;
|
||||||
|
if (fsi->sect_per_clus_bits < SDFAT_EF_CLUS_MAX)
|
||||||
|
statistics.clus_exfat[fsi->sect_per_clus_bits]++;
|
||||||
|
else
|
||||||
|
statistics.clus_exfat[SDFAT_EF_CLUS_MAX - 1]++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsi->vol_type == FAT32)
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT32]++;
|
||||||
|
else if (fsi->vol_type == FAT16)
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT16]++;
|
||||||
|
else if (fsi->vol_type == FAT12)
|
||||||
|
statistics.mnt_cnt[SDFAT_MNT_FAT12]++;
|
||||||
|
|
||||||
|
if (fsi->sect_per_clus_bits < SDFAT_VF_CLUS_MAX)
|
||||||
|
statistics.clus_vfat[fsi->sect_per_clus_bits]++;
|
||||||
|
else
|
||||||
|
statistics.clus_vfat[SDFAT_VF_CLUS_MAX - 1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdfat_statistics_set_mkdir(u8 flags)
|
||||||
|
{
|
||||||
|
if (flags != 0x03)
|
||||||
|
return;
|
||||||
|
statistics.nofat_op[SDFAT_OP_MKDIR] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdfat_statistics_set_create(u8 flags)
|
||||||
|
{
|
||||||
|
if (flags != 0x03)
|
||||||
|
return;
|
||||||
|
statistics.nofat_op[SDFAT_OP_CREATE] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flags : file or dir flgas, 0x03 means no fat-chain.
|
||||||
|
* clu_offset : file or dir logical cluster offset
|
||||||
|
* create : BMAP_ADD_CLUSTER or not
|
||||||
|
*
|
||||||
|
* File or dir have BMAP_ADD_CLUSTER is no fat-chain write
|
||||||
|
* when they have 0x03 flag and two or more clusters.
|
||||||
|
* And don`t have BMAP_ADD_CLUSTER is no fat-chain read
|
||||||
|
* when above same condition.
|
||||||
|
*/
|
||||||
|
void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create)
|
||||||
|
{
|
||||||
|
if ((flags == 0x03) && (clu_offset > 1)) {
|
||||||
|
if (create)
|
||||||
|
statistics.nofat_op[SDFAT_OP_WRITE] = 1;
|
||||||
|
else
|
||||||
|
statistics.nofat_op[SDFAT_OP_READ] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flags : file or dir flgas, 0x03 means no fat-chain.
|
||||||
|
* clu : cluster chain
|
||||||
|
*
|
||||||
|
* Set no fat-chain trunc when file or dir have 0x03 flag
|
||||||
|
* and tow or more clusters.
|
||||||
|
*/
|
||||||
|
void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu)
|
||||||
|
{
|
||||||
|
if ((flags == 0x03) && (clu->size > 1))
|
||||||
|
statistics.nofat_op[SDFAT_OP_TRUNC] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdfat_statistics_set_vol_size(struct super_block *sb)
|
||||||
|
{
|
||||||
|
u64 vol_size;
|
||||||
|
FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
|
||||||
|
|
||||||
|
vol_size = (u64)fsi->num_sectors << sb->s_blocksize_bits;
|
||||||
|
|
||||||
|
if (vol_size <= ((u64)1 << 32))
|
||||||
|
statistics.vol_size[SDFAT_VOL_4G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 33))
|
||||||
|
statistics.vol_size[SDFAT_VOL_8G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 34))
|
||||||
|
statistics.vol_size[SDFAT_VOL_16G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 35))
|
||||||
|
statistics.vol_size[SDFAT_VOL_32G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 36))
|
||||||
|
statistics.vol_size[SDFAT_VOL_64G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 37))
|
||||||
|
statistics.vol_size[SDFAT_VOL_128G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 38))
|
||||||
|
statistics.vol_size[SDFAT_VOL_256G]++;
|
||||||
|
else if (vol_size <= ((u64)1 << 39))
|
||||||
|
statistics.vol_size[SDFAT_VOL_512G]++;
|
||||||
|
else
|
||||||
|
statistics.vol_size[SDFAT_VOL_XTB]++;
|
||||||
|
}
|
||||||
8
upcase.h
8
upcase.h
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _UPCASE_H
|
#ifndef _UPCASE_H
|
||||||
|
|
@ -30,11 +28,11 @@
|
||||||
|
|
||||||
static inline u16 get_col_index(u16 i)
|
static inline u16 get_col_index(u16 i)
|
||||||
{
|
{
|
||||||
return i >> LOW_INDEX_BIT;
|
return i >> LOW_INDEX_BIT;
|
||||||
}
|
}
|
||||||
static inline u16 get_row_index(u16 i)
|
static inline u16 get_row_index(u16 i)
|
||||||
{
|
{
|
||||||
return i & ~HIGH_INDEX_MASK;
|
return i & ~HIGH_INDEX_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -24,4 +22,4 @@
|
||||||
/* PURPOSE : sdFAT File Manager */
|
/* PURPOSE : sdFAT File Manager */
|
||||||
/* */
|
/* */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
#define SDFAT_VERSION "1.3.24"
|
#define SDFAT_VERSION "1.4.16"
|
||||||
|
|
|
||||||
73
xattr.c
73
xattr.c
|
|
@ -12,9 +12,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
@ -48,7 +46,16 @@ static int can_support(const char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
|
ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* INNER FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
||||||
|
*************************************************************************/
|
||||||
|
static int __sdfat_xattr_check_support(const char *name)
|
||||||
{
|
{
|
||||||
if (can_support(name))
|
if (can_support(name))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
@ -56,7 +63,7 @@ int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, s
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
|
ssize_t __sdfat_getxattr(const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
if (can_support(name))
|
if (can_support(name))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
@ -67,17 +74,59 @@ ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, siz
|
||||||
return strlen(default_xattr);
|
return strlen(default_xattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size)
|
|
||||||
|
/*************************************************************************
|
||||||
|
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
||||||
|
*************************************************************************/
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||||
|
static int sdfat_xattr_get(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry, struct inode *inode,
|
||||||
|
const char *name, void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
return 0;
|
return __sdfat_getxattr(name, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdfat_xattr_set(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry, struct inode *inode,
|
||||||
|
const char *name, const void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return __sdfat_xattr_check_support(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct xattr_handler sdfat_xattr_handler = {
|
||||||
|
.prefix = "", /* match anything */
|
||||||
|
.get = sdfat_xattr_get,
|
||||||
|
.set = sdfat_xattr_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct xattr_handler *sdfat_xattr_handlers[] = {
|
||||||
|
&sdfat_xattr_handler,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup_sdfat_xattr_handler(struct super_block *sb)
|
||||||
|
{
|
||||||
|
sb->s_xattr = sdfat_xattr_handlers;
|
||||||
|
}
|
||||||
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
|
||||||
|
int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
return __sdfat_xattr_check_support(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
return __sdfat_getxattr(name, value, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdfat_removexattr(struct dentry *dentry, const char *name)
|
int sdfat_removexattr(struct dentry *dentry, const char *name)
|
||||||
{
|
{
|
||||||
if (can_support(name))
|
return __sdfat_xattr_check_support(name);
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setup_sdfat_xattr_handler(struct super_block *sb)
|
||||||
|
{
|
||||||
|
/* DO NOTHING */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue