From 0490ece85e57819430429bf5caf3b3eb13389f4d Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 12 Feb 2018 19:25:18 +0100 Subject: [PATCH] Update from SM-G950F_OO_Opensource_kernel --- Kconfig | 12 +- Makefile | 5 +- amap_smart.c | 429 +++++++++++------------ amap_smart.h | 76 +++-- api.c | 44 +-- api.h | 65 ++-- blkdev.c | 97 +++--- cache.c | 163 +++++---- config.h | 10 +- core.c | 448 ++++++++++++------------ core.h | 22 +- core_exfat.c | 205 ++++++----- core_fat.c | 147 ++++---- dfr.c | 144 ++++---- dfr.h | 60 ++-- extent.c | 10 +- fatent.c | 127 ++++--- misc.c | 53 +-- mpage.c | 138 ++++---- nls.c | 89 ++--- sdfat.c | 935 ++++++++++++++++++++++++++++++--------------------- sdfat.h | 148 ++++---- sdfat_fs.h | 26 +- statistics.c | 262 +++++++++++++++ upcase.h | 8 +- version.h | 6 +- xattr.c | 73 +++- 27 files changed, 2182 insertions(+), 1620 deletions(-) create mode 100644 statistics.c diff --git a/Kconfig b/Kconfig index d31dd4b..2ab3e99 100644 --- a/Kconfig +++ b/Kconfig @@ -6,7 +6,7 @@ config SDFAT_FS select NLS_CODEPAGE_437 select NLS_ISO8859_1 help - If you want to use the sdFAT file system, then you must say Y or M + If you want to use the sdFAT file system, then you must say Y or M here to inlucde sdFAT support. sdFAT is unified FAT-based file system which supports not only fat12/ 16/32 with vfat but also exfat. sdFAT supports winnt short-name rule. @@ -21,12 +21,15 @@ config SDFAT_DELAYED_META_DIRTY depends on SDFAT_FS help If you enable this feature, metadata(FAT/Directory entry) is updated - by flush thread. + by flush thread. config SDFAT_SUPPORT_DIR_SYNC bool "Enable supporting dir sync" default n 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 int "Default codepage for sdFAT" @@ -93,3 +96,8 @@ config SDFAT_DBG_BUGON bool "enable strict BUG_ON() for debugging" depends on SDFAT_FS && SDFAT_DEBUG default n + +config SDFAT_STATISTICS + bool "enable statistics for bigdata" + depends on SDFAT_FS + default y diff --git a/Makefile b/Makefile index 6be6324..a5cd085 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,11 @@ obj-$(CONFIG_SDFAT_FS) += sdfat_fs.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 - +sdfat_fs-$(CONFIG_SDFAT_VIRTUAL_XATTR) += xattr.o +sdfat_fs-$(CONFIG_SDFAT_STATISTICS) += statistics.o all: diff --git a/amap_smart.c b/amap_smart.c index a86d5c6..99e32a6 100644 --- a/amap_smart.c +++ b/amap_smart.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -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 */ -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; uint16_t max_fclu = 0; @@ -98,7 +96,7 @@ static inline AU_INFO_T* amap_find_hot_au_largest(struct slist_head *shead) while (iter) { entry = list_entry(iter, AU_INFO_T, shead); - + if (entry->free_clusters > max_fclu) { max_fclu = entry->free_clusters; ret = entry; @@ -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. - If there is no partial AU available, pick a clean one */ -static inline AU_INFO_T* amap_find_hot_au_partial(AMAP_T *amap) + * If there is no partial AU available, pick a clean one + */ +static inline AU_INFO_T *amap_find_hot_au_partial(AMAP_T *amap) { struct slist_head *iter; uint16_t max_fclu = 0; @@ -126,7 +125,7 @@ static inline AU_INFO_T* amap_find_hot_au_partial(AMAP_T *amap) while (iter) { entry = list_entry(iter, AU_INFO_T, shead); - + if (entry->free_clusters > max_fclu) { if (entry->free_clusters < amap->clusters_per_au) { max_fclu = entry->free_clusters; @@ -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 - au: an isolated (not in a list) AU data structure -*/ + * Add au into cold AU MAP + * au: an isolated (not in a list) AU data structure + */ int amap_add_cold_au(AMAP_T *amap, AU_INFO_T *au) { 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 -*/ -int amap_remove_cold_au(AMAP_T *amap, AU_INFO_T* au) + * Remove an AU from AU MAP + */ +int amap_remove_cold_au(AMAP_T *amap, AU_INFO_T *au) { 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 - returns NULL if there is no AU w/ enough free space. - - This function doesn't change AU status. - 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) +/* "Find" best fit AU + * returns NULL if there is no AU w/ enough free space. + * + * This function doesn't change AU status. + * 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 *au = NULL; FCLU_NODE_T *fclu_iter; @@ -214,7 +213,7 @@ AU_INFO_T* amap_find_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters) free_clusters); return NULL; } - + fclu_iter = NODE(free_clusters, amap); if (amap->fclu_hint < free_clusters) { @@ -243,14 +242,15 @@ AU_INFO_T* amap_find_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters) } -/* "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. -*/ -AU_INFO_T* amap_pop_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters) +/* "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. + */ +AU_INFO_T *amap_pop_cold_au_bestfit(AMAP_T *amap, uint16_t free_clusters) { /* Naive implementation */ - AU_INFO_T* au; + AU_INFO_T *au; au = amap_find_cold_au_bestfit(amap, free_clusters); 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 - - search from 'start_fclu' to 0 - (target freecluster : -1 for each step) - - 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) + * + * search from 'start_fclu' to 0 + * (target freecluster : -1 for each step) + * 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* au = NULL; + AU_INFO_T *au = NULL; FCLU_NODE_T *fclu_iter; if (!start_fclu) @@ -283,7 +282,7 @@ AU_INFO_T* amap_pop_cold_au_largest(AMAP_T *amap, uint16_t start_fclu) fclu_iter = NODE(amap->fclu_hint, amap); else fclu_iter = NODE(start_fclu, amap); - + /* Naive Hash management */ do { if (!list_empty(&fclu_iter->head)) { @@ -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) */ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hidden_sect) @@ -350,7 +349,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid sdfat_msg(sb, KERN_ERR, "invalid AU size (sect_per_au : %u, " "sect_per_clus : %u) " - "please re-format for performance.", + "please re-format for performance.", sect_per_au, fsi->sect_per_clus); return -EINVAL; } @@ -360,7 +359,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid sdfat_msg(sb, KERN_ERR, "misaligned part (start sect : %u, " "sect_per_clus : %u) " - "please re-format for performance.", + "please re-format for performance.", misaligned_sect, fsi->sect_per_clus); return -EINVAL; } @@ -370,7 +369,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid sdfat_msg(sb, KERN_ERR, "misaligned data area (start sect : %u, " "sect_per_clus : %u) " - "please re-format for performance.", + "please re-format for performance.", fsi->data_start_sector, fsi->sect_per_clus); return -EINVAL; } @@ -383,22 +382,23 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid return -ENOMEM; amap->sb = sb; - + amap->n_au = (fsi->num_sectors + misaligned_sect + sect_per_au - 1) / sect_per_au; amap->n_clean_au = 0; amap->n_full_au = 0; - /* Reflect block-partition align first, - then partition-data_start align */ + /* Reflect block-partition align first, + * then partition-data_start align + */ 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->clusters_per_au = sect_per_au / fsi->sect_per_clus; - /* That is, + /* That is, * the size of cluster is at least 4KB if the size of AU is 4MB */ if (amap->clusters_per_au > MAX_CLU_PER_AU) { - sdfat_log_msg(sb, KERN_INFO, + sdfat_log_msg(sb, KERN_INFO, "too many clusters per AU (clus/au:%d > %d).", amap->clusters_per_au, MAX_CLU_PER_AU); @@ -417,7 +417,6 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid /* Allocate AU info 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); - if (!amap->au_table) { sdfat_msg(sb, KERN_ERR, "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)); if (!amap->fclu_order) - amap->fclu_nodes = (FCLU_NODE_T*)get_zeroed_page(GFP_NOIO); - else - amap->fclu_nodes = (FCLU_NODE_T*)vzalloc(PAGE_SIZE << amap->fclu_order); + amap->fclu_nodes = (FCLU_NODE_T *)get_zeroed_page(GFP_NOIO); + else + amap->fclu_nodes = vzalloc(PAGE_SIZE << amap->fclu_order); 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++) INIT_LIST_HEAD(&amap->fclu_nodes[i].head); - /* - Thanks to kzalloc() - amap->entries[i_au].free_clusters = 0; - amap->entries[i_au].head.prev = NULL; - amap->entries[i_au].head.next = NULL; - */ - + * Thanks to kzalloc() + * amap->entries[i_au].free_clusters = 0; + * amap->entries[i_au].head.prev = NULL; + * amap->entries[i_au].head.next = NULL; + */ + /* 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; AU_INFO_T *au; @@ -486,7 +484,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid "failed to read fat entry(%u)\n", i_clu); goto free_and_eio; } - + if (IS_CLUS_FREE(clu_data)) { au = GET_AU(amap, i_AU_of_CLU(amap, i_clu)); au->free_clusters++; @@ -495,7 +493,7 @@ int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hid } /* 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->idx = i_au; @@ -522,13 +520,12 @@ 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; } - fsi->amap = amap; fsi->used_clusters = total_used_clusters; - sdfat_msg(sb, KERN_INFO, + sdfat_msg(sb, KERN_INFO, "AMAP: Smart allocation enabled (opt : %u / %u / %u)", - amap->option.au_size, amap->option.au_align_factor, + amap->option.au_size, amap->option.au_align_factor, amap->option.packing_ratio); /* Debug purpose - check */ @@ -575,6 +572,7 @@ void amap_destroy(struct super_block *sb) if (amap->au_table) { int i; + for (i = 0; i < n_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); kfree(amap); SDFAT_SB(sb)->fsi.amap = NULL; - - return; } /* - Check status of FS - and change destination if needed to disable AU-aligned alloc. - (from ALLOC_COLD_ALIGNED to ALLOC_COLD_SEQ) -*/ + * Check status of FS + * and change destination if needed to disable AU-aligned alloc. + * (from ALLOC_COLD_ALIGNED to ALLOC_COLD_SEQ) + */ static inline int amap_update_dest(AMAP_T *amap, int ori_dest) { 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 - amap->clusters_per_au * amap->n_clean_au; - /* Status of AUs : Full / Partial / Clean - If there are many partial (and badly fragmented) AUs, - the throughput will decrease extremly. + /* Status of AUs : Full / Partial / Clean + * If there are many partial (and badly fragmented) AUs, + * 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) && (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) - and fragment ratio is more than 2 (AVG free_clusters=half AU) - - disable clean-first allocation - enable VFAT-like sequential allocation - */ - + * and fragment ratio is more than 2 (AVG free_clusters=half AU) + * + * disable clean-first allocation + * enable VFAT-like sequential allocation + */ return ALLOC_COLD_SEQ; } @@ -635,39 +630,37 @@ static inline int amap_update_dest(AMAP_T *amap, int ori_dest) #define PACKING_SOFTLIMIT (amap->option.packing_ratio) #define PACKING_HARDLIMIT (amap->option.packing_ratio * 4) -/* - Pick a packing AU if needed. - Otherwise just return NULL - - 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) +/* + * Pick a packing AU if needed. + * Otherwise just return NULL + * + * 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) { - AU_INFO_T* au = NULL; + AU_INFO_T *au = NULL; if (dest == ALLOC_COLD_PACKING) { - /* ALLOC_COLD_PACKING: - Packing-first mode for defrag. - Optimized to save clean AU - - 1) best-fit AU - 2) Smallest AU (w/ minimum free clusters) - */ - + /* ALLOC_COLD_PACKING: + * Packing-first mode for defrag. + * Optimized to save clean AU + * + * 1) best-fit AU + * 2) Smallest AU (w/ minimum free clusters) + */ 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; + /* 이거 주석처리하면, AU size 딱 맞을때는 clean, 나머지는 작은거부터 */ if (num_to_wb == 0) 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 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); } - + if (au) { amap->n_need_packing = 0; amap_remove_cold_au(amap, au); @@ -676,28 +669,27 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_ } - /* Heuristic packing: - This will improve QoS greatly. - - Count # of AU_ALLIGNED allocation. - If the number exceeds the specific threshold, - allocate on a partial AU or generate random I/O. - */ - if ((PACKING_SOFTLIMIT > 0) && \ - (amap->n_need_packing >= PACKING_SOFTLIMIT) && \ - (num_to_wb < (int)amap->clusters_per_au) ){ + /* Heuristic packing: + * This will improve QoS greatly. + * + * Count # of AU_ALIGNED allocation. + * If the number exceeds the specific threshold, + * allocate on a partial AU or generate random I/O. + */ + if ((PACKING_SOFTLIMIT > 0) && + (amap->n_need_packing >= PACKING_SOFTLIMIT) && + (num_to_wb < (int)amap->clusters_per_au)) { /* Best-fit packing: - If num_to_wb (expected number to be allocated) is smaller than AU_SIZE, - find a best-fit AU. - */ + * If num_to_wb (expected number to be allocated) is smaller + * than AU_SIZE, find a best-fit AU. + */ - // Back margin (heuristics) + /* Back margin (heuristics) */ if (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); - - if ((au != NULL)) { + if (au != NULL) { amap_remove_cold_au(amap, au); MMSG("AMAP: packing (cnt: %d) / softlimit, " @@ -712,16 +704,14 @@ static inline AU_INFO_T* amap_get_packing_au(AMAP_T *amap, int dest, int num_to_ return au; } } - - if (PACKING_HARDLIMIT != 0 && \ - amap->n_need_packing >= PACKING_HARDLIMIT) { - /* Compulsory SLC flushing: - If there was no chance to do best-fit packing - and the # of AU-aligned allocation exceeds HARD threshold, - then pick a clean AU and generate a compulsory random I/O. - */ - au = amap_pop_cold_au_largest(amap, amap->clusters_per_au); + if ((PACKING_HARDLIMIT) && amap->n_need_packing >= PACKING_HARDLIMIT) { + /* Compulsory SLC flushing: + * If there was no chance to do best-fit packing + * and the # of AU-aligned allocation exceeds HARD threshold, + * then pick a clean AU and generate a compulsory random I/O. + */ + au = amap_pop_cold_au_largest(amap, amap->clusters_per_au); if (au) { MMSG("AMAP: packing (cnt: %d) / hard-limit, largest)\n", 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 - - This function should be called only if there are one or more free clusters in the bdev. -*/ +/* Pick a target AU: + * 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) { 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: if (++loop_count >= 3) { /* No space available (or AMAP consistency error) - This could happen because of the ignored AUs - but not likely - (because the defrag daemon will not work if there is no enough space) - */ + * This could happen because of the ignored AUs but not likely + * (because the defrag daemon will not work if there is no enough space) + */ BUG_ON(amap->slist_ignored.next == NULL); return NULL; } @@ -787,13 +777,12 @@ retry: return &amap->cur_hot; } - /* Cold allocation: - If amap->cur_cold.au has one or more free cluster(s), - then just return amap->cur_cold - */ - if ( (!amap->cur_cold.au) \ - || (amap->cur_cold.idx == amap->clusters_per_au) \ + * If amap->cur_cold.au has one or more free cluster(s), + * then just return amap->cur_cold + */ + if ((!amap->cur_cold.au) + || (amap->cur_cold.idx == amap->clusters_per_au) || (amap->cur_cold.au->free_clusters == 0)) { AU_INFO_T *au = NULL; @@ -802,20 +791,21 @@ retry: if (old_au) { 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: - There are 3 possible ALLOC options for cold AU - - ALLOC_COLD_ALGINED: Clean AU first, but heuristic packing is ON - ALLOC_COLD_PACKING: Packing AU first (usually for defrag) - ALLOC_COLD_SEQ : Sequential AU allocation (VFAT-like) - */ - + * There are 3 possible ALLOC options for cold AU + * + * ALLOC_COLD_ALIGNED: Clean AU first, but heuristic packing is ON + * ALLOC_COLD_PACKING: Packing AU first (usually for defrag) + * ALLOC_COLD_SEQ : Sequential AU allocation (VFAT-like) + */ /* 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) { int i_au = old_au->idx + 1; @@ -823,10 +813,9 @@ retry: while (i_au != old_au->idx) { au = GET_AU(amap, i_au); - if ((au->free_clusters > 0) && - !IS_AU_HOT(au, amap) && + if ((au->free_clusters > 0) && + !IS_AU_HOT(au, amap) && !IS_AU_IGNORED(au, amap)) { - MMSG("AMAP: new cold AU(%d) with %d " "clusters (seq)\n", au->idx, au->free_clusters); @@ -845,9 +834,9 @@ retry: } - /* - * Check if packing is needed - * (ALLOC_COLD_PACKING is treated by this function) + /* + * Check if packing is needed + * (ALLOC_COLD_PACKING is treated by this function) */ au = amap_get_packing_au(amap, dest, num_to_wb, &n_clu_to_skip); if (au) { @@ -855,14 +844,13 @@ retry: "(packing)\n", au->idx, au->free_clusters); goto ret_new_cold; } - + /* ALLOC_COLD_ALIGNED */ /* Check if the adjacent AU is clean */ if (old_au && ((old_au->idx + 1) < amap->n_au)) { au = GET_AU(amap, old_au->idx + 1); - - if ((au->free_clusters == amap->clusters_per_au) && - !IS_AU_HOT(au, amap) && + if ((au->free_clusters == amap->clusters_per_au) && + !IS_AU_HOT(au, amap) && !IS_AU_IGNORED(au, amap)) { MMSG("AMAP: new cold AU(%d) with %d clusters " "(adjacent)\n", au->idx, au->free_clusters); @@ -879,7 +867,7 @@ 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); ret_new_cold: @@ -897,14 +885,14 @@ ret_new_cold: void amap_put_target_au(AMAP_T *amap, TARGET_AU_T *cur, int num_allocated) { /* Update AMAP info vars. */ - if (num_allocated > 0 && \ - (cur->au->free_clusters + num_allocated) == amap->clusters_per_au) - // if the target AU was a clean AU before this allocation ... + if (num_allocated > 0 && + (cur->au->free_clusters + num_allocated) == amap->clusters_per_au) { + /* if the target AU was a clean AU before this allocation ... */ amap->n_clean_au--; - if (num_allocated > 0 && \ + } + if (num_allocated > 0 && cur->au->free_clusters == 0) amap->n_full_au++; - if (IS_AU_HOT(cur->au, amap)) { /* Hot AU */ @@ -936,11 +924,9 @@ void amap_put_target_au(AMAP_T *amap, TARGET_AU_T *cur, int num_allocated) } -/* Reposition target->idx for packing - (Heuristics) - - Skip (num_to_skip) free clusters in (cur->au) -*/ +/* Reposition target->idx for packing (Heuristics): + * 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) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; @@ -953,12 +939,11 @@ 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); - while (num_to_skip > 0) { if (clu >= CLUS_BASE) { /* Cf. * If AMAP's integrity is okay, - * we don't need to check if (clu < fsi->num_clusters) + * we don't need to check if (clu < fsi->num_clusters) */ if (fat_ent_get(sb, clu, &read_clu)) @@ -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); return 0; @@ -1005,11 +990,12 @@ 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)) { /* 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; if (unlikely(num_alloc < 0)) { - sdfat_fs_error_ratelimit(sb, + sdfat_fs_error_ratelimit(sb, "AMAP(%s): invalid used clusters(t:%u,u:%u)\n", __func__, fsi->num_clusters, fsi->used_clusters); return -EIO; @@ -1040,13 +1026,11 @@ retry_alloc: } target_au = cur->au; - - /* + /* * 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->free_clusters); BUG_ON(cur->idx >= amap->clusters_per_au); @@ -1075,7 +1059,6 @@ retry_alloc: else if (fat_ent_set(sb, last_clu, new_clu)) return -EIO; - last_clu = new_clu; /* Update au info */ @@ -1090,8 +1073,7 @@ retry_alloc: /* End of the AU */ if ((cur->idx >= amap->clusters_per_au) || !(target_au->free_clusters)) break; - } while(num_allocated_each < num_alloc); - + } while (num_allocated_each < num_alloc); /* Update strategy info */ 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() - to update AMAP info. -*/ + * This is called by fat_free_cluster() + * to update AMAP info. + */ s32 amap_release_cluster(struct super_block *sb, u32 clu) { 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); BUG_ON(i_au >= amap->n_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)) { MMSG("AMAP: Hot cluster freed\n"); @@ -1141,7 +1128,7 @@ s32 amap_release_cluster(struct super_block *sb, u32 clu) amap->total_fclu_hot++; } else if (!IS_AU_WORKING(au, amap) && !IS_AU_IGNORED(au, amap)) { /* 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); au->free_clusters++; 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 - The caller should hold sb lock. - This func. should be used only if smart allocation is on -*/ + * Check if the cluster is in a working AU + * The caller should hold sb lock. + * This func. should be used only if smart allocation is on + */ s32 amap_check_working(struct super_block *sb, u32 clu) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; AU_INFO_T *au; BUG_ON(!amap); - 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) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; AU_INFO_T *au; BUG_ON(!amap); - 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. - The AU will not be used by the allocator. - - XXX: Ignored counter needed -*/ + * Add the AU containing 'clu' to the ignored AU list. + * The AU will not be used by the allocator. + * + * XXX: Ignored counter needed + */ s32 amap_mark_ignore(struct super_block *sb, u32 clu) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; AU_INFO_T *au; BUG_ON(!amap); - au = GET_AU(amap, i_AU_of_CLU(amap, clu)); - if (IS_AU_HOT(au, amap)) { - // Doesn't work with hot AUs + /* Doesn't work with hot AUs */ return -EPERM; } else if (IS_AU_WORKING(au, amap)) { return -EBUSY; @@ -1227,17 +1208,15 @@ s32 amap_mark_ignore(struct super_block *sb, u32 clu) BUG_ON(!IS_AU_IGNORED(au, amap)); //INC_IGN_CNT(au); - MMSG("AMAP: Mark ignored AU (%d)\n", au->idx); - return 0; } /* - This function could be used only on IGNORED AUs. - The caller should care whether it's ignored or not before using this func. -*/ + * This function could be used only on IGNORED AUs. + * The caller should care whether it's ignored or not before using this func. + */ s32 amap_unmark_ignore(struct super_block *sb, u32 clu) { 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 - This will return # of unmarked AUs -*/ + * Unmark all ignored AU + * This will return # of unmarked AUs + */ s32 amap_unmark_ignore_all(struct super_block *sb) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; @@ -1274,7 +1253,6 @@ s32 amap_unmark_ignore_all(struct super_block *sb) int n = 0; BUG_ON(!amap); - entry = amap->slist_ignored.next; while (entry) { au = list_entry(entry, AU_INFO_T, shead); @@ -1283,13 +1261,12 @@ s32 amap_unmark_ignore_all(struct super_block *sb) BUG_ON(!IS_AU_IGNORED(au, amap)); //CLEAR_IGN_CNT(au); - amap_remove_from_list(au, &amap->slist_ignored); amap_add_cold_au(amap, au); - + MMSG("AMAP: Unmark ignored AU (%d)\n", au->idx); n++; - + entry = amap->slist_ignored.next; } diff --git a/amap_smart.h b/amap_smart.h index ffd931d..b628ff4 100644 --- a/amap_smart.h +++ b/amap_smart.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_AMAP_H @@ -25,16 +23,19 @@ #include /* AMAP Configuration Variable */ -#define SMART_ALLOC_N_HOT_AU 5 +#define SMART_ALLOC_N_HOT_AU (5) - -/* Allocating Destination (for smart allocator) */ -#define ALLOC_COLD_ALIGNED 1 -#define ALLOC_COLD_PACKING 2 -#define ALLOC_COLD_SEQ 4 +/* Allocating Destination (for smart allocator): + * moved to sdfat.h + */ +/* + * #define ALLOC_COLD_ALIGNED (1) + * #define ALLOC_COLD_PACKING (2) + * #define ALLOC_COLD_SEQ (4) + */ /* 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) @@ -45,20 +46,20 @@ struct slist_head { }; /* AU entry type */ -typedef struct __AU_INFO_T{ - uint16_t idx; /* the index of the AU (0, 1, 2, ... ) */ - uint16_t free_clusters; /* # of available cluster */ +typedef struct __AU_INFO_T { + uint16_t idx; /* the index of the AU (0, 1, 2, ... ) */ + uint16_t free_clusters; /* # of available cluster */ union { 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; /* Allocation Target AU */ -typedef struct __TARGET_AU_T{ - AU_INFO_T *au; /* Working AU */ - uint16_t idx; /* Intra-AU cluster index */ +typedef struct __TARGET_AU_T { + AU_INFO_T *au; /* Working AU */ + uint16_t idx; /* Intra-AU cluster index */ uint16_t clu_to_skip; /* Clusters to skip */ } TARGET_AU_T; @@ -71,29 +72,29 @@ typedef struct { /* AMAP options */ typedef struct { - unsigned int packing_ratio; /* Tunable packing ratio */ - unsigned int au_size; /* AU size in sectors */ + unsigned int packing_ratio; /* Tunable packing ratio */ + unsigned int au_size; /* AU size in sectors */ unsigned int au_align_factor; /* Hidden sectors % au_size */ } AMAP_OPT_T; -typedef struct __AMAP_T{ - spinlock_t amap_lock; // obsolete +typedef struct __AMAP_T { + spinlock_t amap_lock; /* obsolete */ struct super_block *sb; int n_au; int n_clean_au, n_full_au; int clu_align_bias; 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; /* Size-based AU management pool (cold) */ - FCLU_NODE_T *fclu_nodes; /* An array of listheads */ - int fclu_order; /* Page order that fclu_nodes needs */ - int fclu_hint; /* maximum # of free clusters in an AU */ + FCLU_NODE_T *fclu_nodes; /* An array of listheads */ + int fclu_order; /* Page order that fclu_nodes needs */ + int fclu_hint; /* maximum # of free clusters in an AU */ /* 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 */ /* Ignored AU list */ @@ -113,23 +114,24 @@ typedef struct __AMAP_T{ #define MAX_CLU_PER_AU (1024) /* Cold AU bucket <-> # of freeclusters */ -#define NODE_CLEAN(amap) &amap->fclu_nodes[amap->clusters_per_au - 1] -#define NODE(fclu, amap) &amap->fclu_nodes[fclu - 1] +#define NODE_CLEAN(amap) (&amap->fclu_nodes[amap->clusters_per_au - 1]) +#define NODE(fclu, amap) (&amap->fclu_nodes[fclu - 1]) #define FREE_CLUSTERS(node, amap) ((int)(node - amap->fclu_nodes) + 1) /* AU status */ -#define MAGIC_WORKING (struct slist_head*)0xFFFF5091 -#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_WORKING(au, amap) (au->shead.head == MAGIC_WORKING) -#define SET_AU_WORKING(au) (au->shead.head = MAGIC_WORKING) +#define MAGIC_WORKING ((struct slist_head *)0xFFFF5091) +#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_WORKING(au, amap) (au->shead.head == MAGIC_WORKING) +#define SET_AU_WORKING(au) (au->shead.head = MAGIC_WORKING) /* AU <-> cluster */ -#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 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) -/* - * NOTE : AMAP internal functions are moved to core.h +/* + * NOTE : AMAP internal functions are moved to core.h */ #endif /* _SDFAT_AMAP_H */ diff --git a/api.c b/api.c index bf8e343..e1f17cc 100644 --- a/api.c +++ b/api.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -132,10 +130,11 @@ s32 fsapi_statfs(struct super_block *sb, VOL_INFO_T *info) FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); /* check the validity of pointer parameters */ - ASSERT(info); + ASSERT(info); if (fsi->used_clusters == (u32) ~0) { s32 err; + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_statfs(sb, info); 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 err; + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_sync_fs(sb, do_sync); 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 err; + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_set_vol_flags(sb, new_flag, always_sync); 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); /* 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; struct super_block *sb = old_parent_inode->i_sb; @@ -299,7 +301,7 @@ s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info) { s32 err; struct super_block *sb = inode->i_sb; - + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode %p info %p\n", __func__, inode, info); err = fscore_read_inode(inode, info); @@ -414,13 +416,14 @@ s32 fsapi_rmdir(struct inode *inode, FILE_ID_T *fid) } EXPORT_SYMBOL(fsapi_rmdir); -/* unlink a file. - * that is, remove an entry from a directory. BUT don't truncate */ +/* unlink a file. + * that is, remove an entry from a directory. BUT don't truncate + */ s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; - + /* check the validity of pointer parameters */ ASSERT(fid); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); @@ -441,7 +444,6 @@ s32 fsapi_cache_flush(struct super_block *sb, int do_sync) } EXPORT_SYMBOL(fsapi_cache_flush); - /* release FAT & buf cache */ 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); - u32 fsapi_get_au_stat(struct super_block *sb, s32 mode) { /* 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); - s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args) { s32 err; @@ -505,23 +505,23 @@ s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args) } EXPORT_SYMBOL(fsapi_dfr_scan_dir); - s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev) { s32 err; struct super_block *sb = inode->i_sb; + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); - err = defrag_validate_cluster(inode, - (struct defrag_chunk_info *)chunk, skip_prev); + err = defrag_validate_cluster(inode, + (struct defrag_chunk_info *)chunk, skip_prev); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); - return(err); + return err; } EXPORT_SYMBOL(fsapi_dfr_validate_clus); - s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus) { s32 err; + mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = defrag_reserve_clusters(sb, nr_clus); 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); - s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus) { /* 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); - void fsapi_dfr_unmark_ignore_all(struct super_block *sb) { /* 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); - s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu) { 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); - void fsapi_dfr_writepage_endio(struct page *page) { /* volume lock is not required */ @@ -570,7 +566,6 @@ void fsapi_dfr_writepage_endio(struct page *page) } EXPORT_SYMBOL(fsapi_dfr_writepage_endio); - void fsapi_dfr_update_fat_prev(struct super_block *sb, int force) { 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); - void fsapi_dfr_update_fat_next(struct super_block *sb) { 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); - void fsapi_dfr_check_discard(struct super_block *sb) { 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); - void fsapi_dfr_free_clus(struct super_block *sb, u32 clus) { 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); - s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau) { /* 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); - 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 */ diff --git a/api.h b/api.h index 26bc816..fb0bf7a 100644 --- a/api.h +++ b/api.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_API_H @@ -83,13 +81,13 @@ extern "C" { /* NLS Type Definitions */ /*----------------------------------------------------------------------*/ -/* DOS name stucture */ +/* DOS name structure */ typedef struct { u8 name[DOS_NAME_LENGTH]; u8 name_case; } DOS_NAME_T; -/* unicode name stucture */ +/* unicode name structure */ typedef struct { u16 name[MAX_NAME_LENGTH+3]; /* +3 for null and for converting */ u16 name_hash; @@ -187,8 +185,8 @@ typedef struct { } FILE_ID_T; typedef struct { - s8* lfn; - s8* sfn; + s8 *lfn; + s8 *sfn; s32 lfnbuf_len; //usally MAX_UNINAME_BUF_SIZE s32 sfnbuf_len; //usally MAX_DOSNAME_BUF_SIZE, used only for vfat, not for exfat } DENTRY_NAMEBUF_T; @@ -225,32 +223,32 @@ typedef struct __FATENT_OPS_T { } FATENT_OPS_T; typedef struct { - s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain, int dest); - s32 (*free_cluster)(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); - s32 (*count_used_clusters)(struct super_block *sb, u32* ret_count); - s32 (*init_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type,u32 start_clu, u64 size); - 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 (*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 (*delete_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 offset, s32 num_entries); - void (*get_uniname_from_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); - s32 (*count_ext_entries)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); - s32 (*calc_num_entries)(UNI_NAME_T *p_uniname); - u32 (*get_entry_type)(DENTRY_T *p_entry); - void (*set_entry_type)(DENTRY_T *p_entry, u32 type); - u32 (*get_entry_attr)(DENTRY_T *p_entry); - void (*set_entry_attr)(DENTRY_T *p_entry, u32 attr); - u8 (*get_entry_flag)(DENTRY_T *p_entry); - void (*set_entry_flag)(DENTRY_T *p_entry, u8 flag); - u32 (*get_entry_clu0)(DENTRY_T *p_entry); - void (*set_entry_clu0)(DENTRY_T *p_entry, u32 clu0); - u64 (*get_entry_size)(DENTRY_T *p_entry); - void (*set_entry_size)(DENTRY_T *p_entry, u64 size); - void (*get_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); - void (*set_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); - u32 (*get_au_stat)(struct super_block *sb, s32 mode); + s32 (*alloc_cluster)(struct super_block *, s32, CHAIN_T *, int); + s32 (*free_cluster)(struct super_block *, CHAIN_T *, s32); + s32 (*count_used_clusters)(struct super_block *, u32 *); + s32 (*init_dir_entry)(struct super_block *, CHAIN_T *, s32, u32, u32, u64); + s32 (*init_ext_entry)(struct super_block *, CHAIN_T *, s32, s32, UNI_NAME_T *, DOS_NAME_T *); + 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 *, CHAIN_T *, s32, s32, s32); + void (*get_uniname_from_ext_entry)(struct super_block *, CHAIN_T *, s32, u16 *); + s32 (*count_ext_entries)(struct super_block *, CHAIN_T *, s32, DENTRY_T *); + s32 (*calc_num_entries)(UNI_NAME_T *); + s32 (*check_max_dentries)(FILE_ID_T *); + u32 (*get_entry_type)(DENTRY_T *); + void (*set_entry_type)(DENTRY_T *, u32); + u32 (*get_entry_attr)(DENTRY_T *); + void (*set_entry_attr)(DENTRY_T *, u32); + u8 (*get_entry_flag)(DENTRY_T *); + void (*set_entry_flag)(DENTRY_T *, u8); + u32 (*get_entry_clu0)(DENTRY_T *); + void (*set_entry_clu0)(DENTRY_T *, u32); + u64 (*get_entry_size)(DENTRY_T *); + void (*set_entry_size)(DENTRY_T *, u64); + void (*get_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8); + void (*set_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8); + u32 (*get_au_stat)(struct super_block *, s32); } FS_FUNC_T; - typedef struct __FS_INFO_T { s32 bd_opened; // opened or not u32 vol_type; // volume FAT type @@ -270,7 +268,7 @@ typedef struct __FS_INFO_T { u32 dentries_in_root; // num of dentries in root dir u32 dentries_per_clu; // num of dentries per cluster u32 vol_flag; // volume dirty flag - struct buffer_head *pbr_bh; // buffer_head of PBR sector + struct buffer_head *pbr_bh; // buffer_head of PBR sector u32 map_clu; // allocation bitmap start cluster u32 map_sectors; // num of allocation bitmap sectors @@ -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_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_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_read_inode(struct inode *inode, DIR_ENTRY_T *info); s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync); diff --git a/blkdev.c b/blkdev.c index f5af49e..d0f38db 100644 --- a/blkdev.c +++ b/blkdev.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -50,14 +48,14 @@ /* 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 */ -#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) { return bd_inode->i_mapping->backing_dev_info; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) */ +#endif /*======================================================================*/ /* Function Definitions */ @@ -66,7 +64,7 @@ s32 bdev_open_dev(struct super_block *sb) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - if (fsi->bd_opened) + if (fsi->bd_opened) return 0; fsi->bd_opened = true; @@ -86,12 +84,13 @@ static inline s32 block_device_ejected(struct super_block *sb) struct inode *bd_inode = sb->s_bdev->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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + if (block_device_ejected(sb)) { if (!(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 0; } @@ -113,7 +113,7 @@ s32 bdev_readahead(struct super_block *sb, u32 secno, u32 num_secs) struct blk_plug plug; u32 i; - if (!fsi->bd_opened) + if (!fsi->bd_opened) return -EIO; blk_start_plug(&plug); @@ -135,11 +135,11 @@ s32 bdev_mread(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 n struct sdfat_sb_info *sbi = SDFAT_SB(sb); long flags = sbi->debug_flags; - if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) + if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) return -EIO; #endif /* CONFIG_SDFAT_DBG_IOCTL */ - if (!fsi->bd_opened) + if (!fsi->bd_opened) return -EIO; brelse(*bh); @@ -153,17 +153,16 @@ s32 bdev_mread(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 n if (*bh) return 0; - /* + /* * 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; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); sdfat_debug_warn_on(1); } return -EIO; - } s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync) @@ -175,11 +174,11 @@ s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 n struct sdfat_sb_info *sbi = SDFAT_SB(sb); long flags = sbi->debug_flags; - if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) + if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) return -EIO; #endif /* CONFIG_SDFAT_DBG_IOCTL */ - if (!fsi->bd_opened) + if (!fsi->bd_opened) return -EIO; if (secno == bh->b_blocknr) { @@ -206,14 +205,12 @@ s32 bdev_mwrite(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 n } __brelse(bh2); } - return 0; - no_bh: - /* + /* * 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; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); sdfat_debug_warn_on(1); @@ -229,11 +226,11 @@ s32 bdev_sync_all(struct super_block *sb) struct sdfat_sb_info *sbi = SDFAT_SB(sb); long flags = sbi->debug_flags; - if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) + if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) return -EIO; #endif /* CONFIG_SDFAT_DBG_IOCTL */ - if (!fsi->bd_opened) + if (!fsi->bd_opened) return -EIO; return sync_blockdev(sb->s_bdev); @@ -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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - BUG_ON(!bh); - if ( (sec >= fsi->num_sectors) - && (fsi->num_sectors > 0) ) { - sdfat_fs_error_ratelimit(sb, "%s: out of range (sect:%u)", - __func__, sec); + BUG_ON(!bh); + if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) { + sdfat_fs_error_ratelimit(sb, + "%s: out of range (sect:%u)", __func__, sec); return -EIO; } if (bdev_mread(sb, sec, bh, 1, read)) { - sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)", - __func__, sec); + sdfat_fs_error_ratelimit(sb, + "%s: I/O error (sect:%u)", __func__, sec); return -EIO; } return 0; -} /* end of read_sect */ +} s32 write_sect(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - BUG_ON(!bh); - if ( (sec >= fsi->num_sectors) - && (fsi->num_sectors > 0) ) { - sdfat_fs_error_ratelimit(sb, "%s: out of range (sect:%u)", - __func__, sec); + BUG_ON(!bh); + if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) { + sdfat_fs_error_ratelimit(sb, + "%s: out of range (sect:%u)", __func__, sec); return -EIO; } if (bdev_mwrite(sb, sec, bh, 1, sync)) { sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u)", - __func__, sec); + __func__, sec); return -EIO; } return 0; -} /* end of write_sect */ +} 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); - 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)", - __func__ ,sec, num_secs); + __func__, sec, num_secs); return -EIO; } if (bdev_mread(sb, sec, bh, num_secs, read)) { sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)", - __func__,sec, num_secs); + __func__, sec, num_secs); return -EIO; } return 0; -} /* end of read_msect */ +} 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); - 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)", - __func__ ,sec, num_secs); + __func__, sec, num_secs); return -EIO; } if (bdev_mwrite(sb, sec, bh, num_secs, sync)) { sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%u len:%d)", - __func__,sec, num_secs); + __func__, sec, num_secs); return -EIO; } return 0; -} /* end of write_msect */ +} 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) { -#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512) - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; s32 nr_bhs = MAX_BUF_PER_PAGE; 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); - 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)", - __func__ ,sec, num_secs); + __func__, sec, num_secs); return -EIO; } /* Just return -EAGAIN if it is failed */ - if ( __buffer_zeroed(sb, sec, num_secs)) + if (__buffer_zeroed(sb, sec, num_secs)) return -EAGAIN; return 0; diff --git a/cache.c b/cache.c index 328b5e3..33901fa 100644 --- a/cache.c +++ b/cache.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -48,9 +46,9 @@ /*----------------------------------------------------------------------*/ /* Local Variable Definitions */ /*----------------------------------------------------------------------*/ -#define LOCKBIT 0x01 -#define DIRTYBIT 0x02 -#define KEEPBIT 0x04 +#define LOCKBIT (0x01) +#define DIRTYBIT (0x02) +#define KEEPBIT (0x04) /*----------------------------------------------------------------------*/ /* Cache handling function declarations */ @@ -74,7 +72,7 @@ static void push_to_mru(cache_ent_t *bp, cache_ent_t *list) bp->prev = list; list->next->prev = bp; list->next = bp; -} /* end of __dcache_push_to_mru */ +} 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; list->prev->next = bp; list->prev = bp; -} /* end of __dcache_push_to_lru */ +} static void move_to_mru(cache_ent_t *bp, cache_ent_t *list) { bp->prev->next = bp->next; bp->next->prev = bp->prev; push_to_mru(bp, list); -} /* end of __dcache_move_to_mru */ +} static void move_to_lru(cache_ent_t *bp, cache_ent_t *list) { bp->prev->next = bp->next; bp->next->prev = bp->prev; push_to_lru(bp, list); -} /* end of __dcache_move_to_lru */ +} static inline s32 __check_hash_valid(cache_ent_t *bp) { #ifdef DEBUG_HASH_LIST - if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) || - (bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) { + if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) || + (bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) { return -EINVAL; } #endif - if ( (bp->hash.next == bp) || (bp->hash.prev == bp) ) + if ((bp->hash.next == bp) || (bp->hash.prev == bp)) return -EINVAL; return 0; @@ -119,15 +117,15 @@ static inline void __remove_from_hash(cache_ent_t *bp) bp->hash.next = bp; bp->hash.prev = bp; #ifdef DEBUG_HASH_LIST - bp->hash.next = (cache_ent_t*)DEBUG_HASH_NEXT; - bp->hash.prev = (cache_ent_t*)DEBUG_HASH_PREV; + bp->hash.next = (cache_ent_t *)DEBUG_HASH_NEXT; + bp->hash.prev = (cache_ent_t *)DEBUG_HASH_PREV; #endif } -/* Do FAT mirroring (don't sync) - sec: sector No. in FAT1 - bh: bh of sec. -*/ +/* Do FAT mirroring (don't sync) + * sec: sector No. in FAT1 + * bh: bh of sec. + */ static inline s32 __fat_copy(struct super_block *sb, u32 sec, struct buffer_head *bh, int sync) { #ifdef CONFIG_SDFAT_FAT_MIRRORING @@ -150,7 +148,7 @@ static inline s32 __fat_copy(struct super_block *sb, u32 sec, struct buffer_head /* * returns 1, if bp is flushed - * returns 0, if bp is not dirty + * returns 0, if bp is not dirty * returns -1, if error occurs */ static s32 __fcache_ent_flush(struct super_block *sb, cache_ent_t *bp, u32 sync) @@ -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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + __fcache_remove_hash(bp); bp->sec = ~0; bp->flag = 0; - if(bp->bh) { + if (bp->bh) { __brelse(bp->bh); bp->bh = NULL; } @@ -202,11 +201,10 @@ u8 *fcache_getblk(struct super_block *sb, u32 sec) return NULL; } move_to_mru(bp, &fsi->fcache.lru_list); - return(bp->bh->b_data); + return bp->bh->b_data; } bp = __fcache_get(sb, sec); - if (!__check_hash_valid(bp)) __fcache_remove_hash(bp); @@ -218,10 +216,10 @@ u8 *fcache_getblk(struct super_block *sb, u32 sec) if ((sec & (page_ra_count - 1)) == 0) bdev_readahead(sb, sec, page_ra_count); - /* + /* * patch 1.2.4 : buffer_head null pointer exception problem. * - * When read_sect is failed, fcache should be moved to + * When read_sect is failed, fcache should be moved to * EMPTY hash_list and the first of lru_list. */ if (read_sect(sb, sec, &(bp->bh), 1)) { @@ -236,9 +234,10 @@ static inline int __mark_delayed_dirty(struct super_block *sb, cache_ent_t *bp) { #ifdef CONFIG_SDFAT_DELAYED_META_DIRTY FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + if (fsi->vol_type == EXFAT) return -ENOTSUPP; - + bp->flag |= DIRTYBIT; return 0; #else @@ -253,8 +252,10 @@ s32 fcache_modify(struct super_block *sb, u32 sec) cache_ent_t *bp; bp = __fcache_find(sb, sec); - if (!bp) + if (!bp) { + sdfat_fs_error(sb, "Can`t find fcache (sec 0x%08x)", sec); return -EIO; + } if (!__mark_delayed_dirty(sb, bp)) return 0; @@ -346,15 +347,16 @@ s32 fcache_release_all(struct super_block *sb) bp = fsi->fcache.lru_list.next; while (bp != &fsi->fcache.lru_list) { s32 ret_tmp = __fcache_ent_flush(sb, bp, 0); + if (ret_tmp < 0) ret = ret_tmp; else dirtycnt += ret_tmp; - + bp->sec = ~0; bp->flag = 0; - if(bp->bh) { + if (bp->bh) { __brelse(bp->bh); bp->bh = NULL; } @@ -383,7 +385,7 @@ s32 fcache_flush(struct super_block *sb, u32 sync) dirtycnt += ret; bp = bp->next; } - + MMSG("BD: flush / dirty fat cache: %d (err:%d)\n", dirtycnt, ret); return ret; } @@ -395,11 +397,9 @@ static cache_ent_t *__fcache_find(struct super_block *sb, u32 sec) FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); off = (sec + (sec >> fsi->sect_per_clus_bits)) & (FAT_CACHE_HASH_SIZE - 1); - hp = &(fsi->fcache.hash_list[off]); for (bp = hp->hash.next; bp != hp; bp = bp->hash.next) { if (bp->sec == sec) { - /* * 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"); touch_buffer(bp->bh); - return(bp); + return bp; } } - return(NULL); -} /* end of __fcache_find */ + return NULL; +} 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); bp = fsi->fcache.lru_list.prev; - #ifdef CONFIG_SDFAT_DELAYED_META_DIRTY while (bp->flag & DIRTYBIT) { 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); move_to_mru(bp, &fsi->fcache.lru_list); - return(bp); -} /* end of __fcache_get */ + return 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; hp->hash.next->hash.prev = bp; hp->hash.next = bp; -} /* end of __fcache_insert_hash */ +} static void __fcache_remove_hash(cache_ent_t *bp) { #ifdef DEBUG_HASH_LIST - if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) || - (bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) { + if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) || + (bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) { EMSG("%s: FATAL: tried to remove already-removed-cache-entry" "(bp:%p)\n", __func__, bp); return; @@ -468,7 +467,7 @@ static void __fcache_remove_hash(cache_ent_t *bp) #endif WARN_ON(bp->flag & DIRTYBIT); __remove_from_hash(bp); -} /* end of __fcache_remove_hash */ +} /*======================================================================*/ /* Buffer Read/Write Functions */ @@ -483,12 +482,12 @@ s32 dcache_readahead(struct super_block *sb, u32 sec) u32 adj_ra_count = max(fsi->sect_per_clus, page_ra_count); u32 ra_count = min(adj_ra_count, max_ra_count); - /* Read-ahead is not required */ + /* Read-ahead is not required */ if (fsi->sect_per_clus == 1) return 0; if (sec < fsi->data_start_sector) { - EMSG("BD: %s: requested sector is invalid(sect:%u, root:%u)\n", + EMSG("BD: %s: requested sector is invalid(sect:%u, root:%u)\n", __func__, sec, fsi->data_start_sector); return -EIO; } @@ -508,7 +507,7 @@ s32 dcache_readahead(struct super_block *sb, u32 sec) /* * returns 1, if bp is flushed - * returns 0, if bp is not dirty + * returns 0, if bp is not dirty * returns -1, if error occurs */ static s32 __dcache_ent_flush(struct super_block *sb, cache_ent_t *bp, u32 sync) @@ -533,15 +532,15 @@ static s32 __dcache_ent_discard(struct super_block *sb, cache_ent_t *bp) FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); MMSG("%s : bp[%p] (sec:%08x flag:%08x bh:%p) list(prev:%p next:%p) " - "hash(prev:%p next:%p)\n", __func__, + "hash(prev:%p next:%p)\n", __func__, bp, bp->sec, bp->flag, bp->bh, bp->prev, bp->next, bp->hash.prev, bp->hash.next); - + __dcache_remove_hash(bp); bp->sec = ~0; bp->flag = 0; - if(bp->bh) { + if (bp->bh) { __brelse(bp->bh); bp->bh = NULL; } @@ -568,7 +567,7 @@ u8 *dcache_getblk(struct super_block *sb, u32 sec) if (!(bp->flag & KEEPBIT)) // already in keep list move_to_mru(bp, &fsi->dcache.lru_list); - return(bp->bh->b_data); + return bp->bh->b_data; } bp = __dcache_get(sb, sec); @@ -597,20 +596,21 @@ s32 dcache_modify(struct super_block *sb, u32 sec) set_sb_dirty(sb); bp = __dcache_find(sb, sec); - if (likely(bp)) { -#ifdef CONFIG_SDFAT_DELAYED_META_DIRTY - FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - if (fsi->vol_type != EXFAT) { - bp->flag |= DIRTYBIT; - return 0; - } -#endif - ret = write_sect(sb, sec, bp->bh, 0); + if (unlikely(!bp)) { + sdfat_fs_error(sb, "Can`t find dcache (sec 0x%08x)", sec); + return -EIO; } +#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) { DMSG("%s : failed to modify buffer(err:%d, sec:%u, bp:0x%p)\n", - __func__, ret, sec, bp); + __func__, ret, sec, bp); } return ret; @@ -621,7 +621,7 @@ s32 dcache_lock(struct super_block *sb, u32 sec) cache_ent_t *bp; bp = __dcache_find(sb, sec); - if (likely(bp)) { + if (likely(bp)) { bp->flag |= LOCKBIT; return 0; } @@ -662,7 +662,7 @@ s32 dcache_release(struct super_block *sb, u32 sec) bp->sec = ~0; bp->flag = 0; - if(bp->bh) { + if (bp->bh) { __brelse(bp->bh); bp->bh = NULL; } @@ -678,9 +678,10 @@ s32 dcache_release_all(struct super_block *sb) FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); s32 dirtycnt = 0; - /* Connect list elements */ - /* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) */ - while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list){ + /* Connect list elements: + * LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) + */ + while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list) { cache_ent_t *bp_keep = fsi->dcache.keep_list.prev; // bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later move_to_mru(bp_keep, &fsi->dcache.lru_list); @@ -695,11 +696,10 @@ s32 dcache_release_all(struct super_block *sb) ret = -EIO; } #endif - bp->sec = ~0; bp->flag = 0; - if(bp->bh) { + if (bp->bh) { __brelse(bp->bh); bp->bh = NULL; } @@ -719,14 +719,14 @@ s32 dcache_flush(struct super_block *sb, u32 sync) s32 dirtycnt = 0; s32 keepcnt = 0; - /* Connect list elements */ - /* LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) */ - // XXX: optimization - while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list){ + /* Connect list elements: + * LRU list : (A - B - ... - bp_front) + (bp_first + ... + bp_last) + */ + while (fsi->dcache.keep_list.prev != &fsi->dcache.keep_list) { cache_ent_t *bp_keep = fsi->dcache.keep_list.prev; + bp_keep->flag &= ~(KEEPBIT); // Will be 0-ed later move_to_mru(bp_keep, &fsi->dcache.lru_list); - keepcnt++; } @@ -750,7 +750,7 @@ s32 dcache_flush(struct super_block *sb, u32 sync) bp = bp->next; } - MMSG("BD: flush / dirty dentry cache: %d (%d from keeplist, err:%d)\n", + MMSG("BD: flush / dirty dentry cache: %d (%d from keeplist, err:%d)\n", dirtycnt, keepcnt, ret); return ret; } @@ -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) { if (bp->sec == sec) { touch_buffer(bp->bh); - return(bp); + return bp; } } return NULL; -} /* end of __dcache_find */ +} 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; move_to_mru(bp, &fsi->dcache.keep_list); } - bp = bp_prev; /* If all dcaches are dirty */ @@ -799,15 +798,15 @@ static cache_ent_t *__dcache_get(struct super_block *sb, u32 sec) } } #else - while (bp->flag & LOCKBIT) + while (bp->flag & LOCKBIT) bp = bp->prev; #endif // if (bp->flag & DIRTYBIT) // sync_dirty_buffer(bp->bh); move_to_mru(bp, &fsi->dcache.lru_list); - return(bp); -} /* end of __dcache_get */ + return 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; hp->hash.next->hash.prev = bp; hp->hash.next = bp; -} /* end of __dcache_insert_hash */ +} static void __dcache_remove_hash(cache_ent_t *bp) { #ifdef DEBUG_HASH_LIST - if ( (bp->hash.next == (cache_ent_t*)DEBUG_HASH_NEXT) || - (bp->hash.prev == (cache_ent_t*)DEBUG_HASH_PREV) ) { + if ((bp->hash.next == (cache_ent_t *)DEBUG_HASH_NEXT) || + (bp->hash.prev == (cache_ent_t *)DEBUG_HASH_PREV)) { EMSG("%s: FATAL: tried to remove already-removed-cache-entry" "(bp:%p)\n", __func__, bp); return; @@ -837,7 +836,7 @@ static void __dcache_remove_hash(cache_ent_t *bp) #endif WARN_ON(bp->flag & DIRTYBIT); __remove_from_hash(bp); -} /* end of __dcache_remove_hash */ +} /* end of cache.c */ diff --git a/config.h b/config.h index e786fe8..6e2a4e8 100644 --- a/config.h +++ b/config.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_CONFIG_H @@ -65,7 +63,7 @@ #ifndef CONFIG_SDFAT_FAT32_SHORTNAME_SEQ /* Shortname ~1, ... ~9 have higher * priority (WIN32/VFAT-like) */ -//#define CONFIG_SDFAT_FAT32_SHORTNAME_SEQ +//#define CONFIG_SDFAT_FAT32_SHORTNAME_SEQ #endif #ifndef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE @@ -101,7 +99,7 @@ #endif #ifndef CONFIG_SDFAT_VIRTUAL_XATTR -#define CONFIG_SDFAT_VIRTUAL_XATTR +//#define CONFIG_SDFAT_VIRTUAL_XATTR #endif #ifndef CONFIG_SDFAT_SUPPORT_STLOG @@ -114,7 +112,7 @@ #ifndef CONFIG_SDFAT_DBG_IOCTL //#define CONFIG_SDFAT_DBG_IOCTL -#endif +#endif #ifndef CONFIG_SDFAT_DBG_MSG //#define CONFIG_SDFAT_DBG_MSG diff --git a/core.c b/core.c index b38909f..4384816 100644 --- a/core.c +++ b/core.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -46,18 +44,19 @@ /*----------------------------------------------------------------------*/ 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; -#else +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */ struct sdfat_sb_info *sbi = SDFAT_SB(sb); - sbi->s_dirt = 1; // XXX: really needed? + sbi->s_dirt = 1; /* Insert work */ spin_lock(&sbi->work_lock); if (!sbi->write_super_queued) { unsigned long delay; + 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; } spin_unlock(&sbi->work_lock); @@ -99,41 +98,32 @@ static s8 *reserved_names[] = { static s32 check_type_size(void) { /* 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; - } - if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } - if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) { + if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) return -EINVAL; - } return 0; } @@ -150,8 +140,9 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s fsi->vol_flag = new_flag; - /* skip updating volume dirty flag, - * if this volume has been mounted with read-only */ + /* skip updating volume dirty flag, + * if this volume has been mounted with read-only + */ if (sb->s_flags & MS_RDONLY) 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) { - 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); } 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; - } else { + } else { /* FAT16/12 */ pbr16_t *bpb = (pbr16_t *) fsi->pbr_bh->b_data; bpb->bpb.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00; } @@ -202,7 +193,7 @@ static inline s32 __fs_meta_sync(struct super_block *sb, s32 do_sync) { #ifdef CONFIG_SDFAT_DELAYED_META_DIRTY FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - + if (fsi->vol_type != EXFAT) { MMSG("meta flush in fs_sync(sync=%d)\n", do_sync); fcache_flush(sb, 0); @@ -218,14 +209,14 @@ static s32 fs_sync(struct super_block *sb, s32 do_sync) { s32 err; - if (!do_sync) + if (!do_sync) return 0; err = __fs_meta_sync(sb, do_sync); if (!err) err = bdev_sync_all(sb); - + if (err) EMSG("%s : failed to sync. (err:%d)\n", __func__, err); @@ -280,17 +271,17 @@ out: return ret; } /* 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; s32 count = 0; - next = p_chain->dir; + next = p_chain->dir; if (p_chain->flags == 0x03) { *ret_clu = next + p_chain->size - 1; return 0; } - + do { count++; clu = next; @@ -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; u32 clu; @@ -326,7 +317,7 @@ static s32 __count_num_clusters(struct super_block *sb, CHAIN_T *p_chain, s32* r *ret_count = p_chain->size; return 0; } - + clu = p_chain->dir; count = 0; for (i = CLUS_BASE; i < fsi->num_clusters; i++) { @@ -351,15 +342,15 @@ static void free_upcase_table(struct super_block *sb) u16 **upcase_table; upcase_table = fsi->vol_utbl; - for(i = 0 ; i < UTBL_COL_COUNT ; i ++) { - if (upcase_table[i]) - kfree(upcase_table[i]); + for (i = 0 ; i < UTBL_COL_COUNT ; i++) { + /* kfree(NULL) is safe */ + kfree(upcase_table[i]); + upcase_table[i] = NULL; } - if (fsi->vol_utbl) { - kfree(fsi->vol_utbl); - fsi->vol_utbl = NULL; - } + /* kfree(NULL) is safe */ + kfree(fsi->vol_utbl); + fsi->vol_utbl = NULL; } 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; u32 index = 0; u32 checksum = 0; - u16 **upcase_table = (u16 **)kzalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL); - if(!upcase_table) + u16 **upcase_table = kzalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL); + + if (!upcase_table) return -ENOMEM; /* thanks for kzalloc * memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); @@ -383,28 +375,28 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto fsi->vol_utbl = upcase_table; num_sectors += sector; - while(sector < num_sectors) { + while (sector < num_sectors) { ret = read_sect(sb, sector, &tmp_bh, 1); if (ret) { - EMSG("%s: failed to read sector(0x%x)\n", + EMSG("%s: failed to read sector(0x%x)\n", __func__, sector); goto error; } 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? */ //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 >> 1) + *(((u8*)tmp_bh->b_data)+i); - checksum = ((checksum & 1) ? 0x80000000 : 0 ) + - (checksum >> 1) + *(((u8*)tmp_bh->b_data)+(i+1)); + checksum = ((checksum & 1) ? 0x80000000 : 0) + + (checksum >> 1) + *(((u8 *)tmp_bh->b_data)+i); + checksum = ((checksum & 1) ? 0x80000000 : 0) + + (checksum >> 1) + *(((u8 *)tmp_bh->b_data)+(i+1)); if (skip) { MMSG("skip from 0x%X to 0x%X(amount of 0x%X)\n", - index, index+uni, uni); + index, index+uni, uni); index += uni; skip = false; } else if (uni == index) { @@ -413,17 +405,19 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto skip = true; } else { /* uni != index , uni != 0xFFFF */ u16 col_index = get_col_index(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]) { EMSG("failed to allocate memory" - " for column 0x%X\n", + " for column 0x%X\n", col_index); ret = -ENOMEM; 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; } @@ -434,22 +428,22 @@ static s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_secto } if (index >= 0xFFFF && utbl_checksum == checksum) { DMSG("%s: load upcase table successfully" - "(idx:0x%08x, utbl_chksum:0x%08x)\n", - __func__, index, utbl_checksum); - if(tmp_bh) + "(idx:0x%08x, utbl_chksum:0x%08x)\n", + __func__, index, utbl_checksum); + if (tmp_bh) brelse(tmp_bh); return 0; } EMSG("%s: failed to load upcase table" - "(idx:0x%08x, chksum:0x%08x, utbl_chksum:0x%08x)\n", + "(idx:0x%08x, chksum:0x%08x, utbl_chksum:0x%08x)\n", __func__, index, checksum, utbl_checksum); ret = -EINVAL; error: - if(tmp_bh) + if (tmp_bh) brelse(tmp_bh); - free_upcase_table(sb); + free_upcase_table(sb); return ret; } @@ -459,36 +453,36 @@ static s32 __load_default_upcase_table(struct super_block *sb) u32 j; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - u8 skip = false; - u32 index = 0; - u16 uni = 0; + u8 skip = false; + u32 index = 0; + u16 uni = 0; u16 **upcase_table; - upcase_table = (u16 **) kmalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL); - if(!upcase_table) + upcase_table = kmalloc((UTBL_COL_COUNT * sizeof(u16 *)), GFP_KERNEL); + if (!upcase_table) return -ENOMEM; - + fsi->vol_utbl = upcase_table; 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? */ //uni = le16_to_cpu(((__le16*)uni_def_upcase)[i>>1]); - uni = get_unaligned_le16((u8*)uni_def_upcase+i); - if(skip) { + uni = get_unaligned_le16((u8 *)uni_def_upcase+i); + if (skip) { MMSG("skip from 0x%x ", index); index += uni; MMSG("to 0x%x (amount of 0x%x)\n", index, uni); skip = false; - } else if(uni == index) + } else if (uni == index) { index++; - else if(uni == 0xFFFF) + } else if (uni == 0xFFFF) { skip = true; - else { /* uni != index , uni != 0xFFFF */ + } else { /* uni != index , uni != 0xFFFF */ u16 col_index = get_col_index(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]) { EMSG("failed to allocate memory for " "new column 0x%x\n", col_index); @@ -496,21 +490,21 @@ static s32 __load_default_upcase_table(struct super_block *sb) 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][get_row_index(index)] = uni; - index ++; + index++; } } - if(index >= 0xFFFF) + if (index >= 0xFFFF) return 0; error: /* FATAL error: default upcase table has error */ - free_upcase_table(sb); + free_upcase_table(sb); return ret; } @@ -548,7 +542,7 @@ static s32 load_upcase_table(struct super_block *sb) sector = CLUS_TO_SECT(fsi, tbl_clu); num_sectors = ((tbl_size-1) >> blksize_bits) + 1; - ret = __load_upcase_table(sb, sector, num_sectors, + ret = __load_upcase_table(sb, sector, num_sectors, le32_to_cpu(ep->checksum)); if (ret && (ret != -EIO)) @@ -607,7 +601,7 @@ static s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 { s32 ret; u32 off, clu = 0; - u32 blksize_mask = (u32)(sb->s_blocksize-1); + u32 blksize_mask = (u32)(sb->s_blocksize-1); u8 blksize_bits = sb->s_blocksize_bits; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); @@ -620,19 +614,19 @@ static s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 *sector += fsi->root_start_sector; return 0; } - - ret =walk_fat_chain(sb, p_dir, off, &clu); + + ret = walk_fat_chain(sb, p_dir, off, &clu); if (ret) return ret; /* byte offset in cluster */ - off &= (fsi->cluster_size - 1); + off &= (fsi->cluster_size - 1); /* byte offset in sector */ *offset = off & blksize_mask; /* sector offset in cluster */ - *sector = off >> blksize_bits; + *sector = off >> blksize_bits; *sector += CLUS_TO_SECT(fsi, clu); return 0; } /* end of find_location */ @@ -832,10 +826,8 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries if (dentry == -EIO) break; - if ((fid->size >> DENTRY_SIZE_BITS) >= MAX_FAT_DENTRIES) { - /* FAT spec allows a dir to grow upto 65536 dentries */ + if (fsi->fs_func->check_max_dentries(fid)) return -ENOSPC; - } /* we trust p_dir->size regardless of FAT type */ if (__find_last_cluster(sb, p_dir, &last_clu)) @@ -848,9 +840,10 @@ static s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries clu.size = 0; /* UNUSED */ clu.flags = p_dir->flags; - /* (0) check if there are reserved clusters - (create_dir 의 주석 참고) */ - if (!IS_CLUS_EOF(fsi->used_clusters) && \ + /* (0) check if there are reserved clusters + * (create_dir 의 주석 참고) + */ + if (!IS_CLUS_EOF(fsi->used_clusters) && ((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2))) 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; hint_femp.cur.flags = 0x01; } + if (clu.flags == 0x01) if (fat_ent_set(sb, last_clu, clu.dir)) 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 * should be allocated from the start of new cluster */ - hint_femp.eidx = p_dir->size << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); 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; } /* end of find_empty_entry */ - #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 dentries_per_clu; @@ -1022,19 +1014,21 @@ s32 check_dir_empty(struct super_block *sb, CHAIN_T *p_dir) if (type == TYPE_UNUSED) return 0; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) 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; - } else { - if (fsi->vol_type == EXFAT) - return -ENOTEMPTY; - if ((p_dir->dir == fsi->root_dir) || ((++count) > 2)) - return -ENOTEMPTY; - } } - + /* FAT16 root_dir */ if (IS_CLUS_FREE(p_dir->dir)) return -ENOTEMPTY; @@ -1102,8 +1096,11 @@ static inline void preprocess_ext_only_sfn(s32 lookup, u16 first_char, DOS_NAME_ } /* input : dir, uni_name - 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) + * 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) { s32 ret, num_entries, lossy = NLS_NAME_NO_LOSSY; 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; 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) { - return __resolve_path(inode, path, p_dir, p_uniname, 1); +static inline s32 resolve_path(struct inode *inode, const u8 *path, CHAIN_T *dir, UNI_NAME_T *uni) +{ + 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) @@ -1254,10 +1253,10 @@ static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname clu.flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01; /* (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))) return -ENOSPC; - + /* (1) allocate a cluster */ ret = fsi->fs_func->alloc_cluster(sb, 1, &clu, ALLOC_HOT); @@ -1274,8 +1273,9 @@ static s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname size = fsi->cluster_size; if (fsi->vol_type != EXFAT) { /* initialize the . and .. entry - Information for . points to itself - Information for .. points to parent dir */ + * Information for . points to itself + * Information for .. points to parent dir + */ dot_name.name_case = 0x0; 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->start_clu = clu.dir; - fid->type= TYPE_DIR; + fid->type = TYPE_DIR; fid->rwoffset = 0; 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 */ /* 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); if (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->start_clu = CLUS_EOF; - fid->type= TYPE_FILE; + fid->type = TYPE_FILE; fid->rwoffset = 0; 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; } /* 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; u32 sector_mov, sector_new; @@ -1627,10 +1629,11 @@ s32 fscore_shutdown(void) static bool is_exfat(pbr_t *pbr) { int i = 53; + do { if (pbr->bpb.f64.res_zero[i-1]) break; - } while(--i); + } while (--i); return i ? false : true; } @@ -1663,7 +1666,7 @@ inline pbr_t *read_pbr_with_logical_sector(struct super_block *sb, struct buffer } if (logical_sect < sb->s_blocksize) { - sdfat_log_msg(sb, KERN_ERR, + sdfat_log_msg(sb, KERN_ERR, "logical sector size too small for device" " (logical sector size = %u)", logical_sect); return NULL; @@ -1676,13 +1679,13 @@ inline pbr_t *read_pbr_with_logical_sector(struct super_block *sb, struct buffer *prev_bh = NULL; if (!sb_set_blocksize(sb, logical_sect)) { - sdfat_log_msg(sb, KERN_ERR, + sdfat_log_msg(sb, KERN_ERR, "unable to set blocksize %u", logical_sect); return NULL; } bh = sb_bread(sb, 0); if (!bh) { - sdfat_log_msg(sb, KERN_ERR, + sdfat_log_msg(sb, KERN_ERR, "unable to read boot sector " "(logical sector size = %lu)", sb->s_blocksize); return NULL; @@ -1691,8 +1694,8 @@ inline pbr_t *read_pbr_with_logical_sector(struct super_block *sb, struct buffer *prev_bh = bh; p_pbr = (pbr_t *) bh->b_data; } - - sdfat_log_msg(sb, KERN_INFO, + + sdfat_log_msg(sb, KERN_INFO, "set logical sector size : %lu", sb->s_blocksize); return p_pbr; @@ -1704,6 +1707,7 @@ s32 fscore_mount(struct super_block *sb) s32 ret; pbr_t *p_pbr; struct buffer_head *tmp_bh = NULL; + struct gendisk *disk = sb->s_bdev->bd_disk; struct sdfat_mount_options *opts = &(SDFAT_SB(sb)->options); FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); @@ -1746,8 +1750,8 @@ s32 fscore_mount(struct super_block *sb) /* fill fs_struct */ if (is_exfat(p_pbr)) { - if(opts->fs_type && opts->fs_type != FS_TYPE_EXFAT) { - sdfat_log_msg(sb, KERN_ERR, + if (opts->fs_type && opts->fs_type != FS_TYPE_EXFAT) { + sdfat_log_msg(sb, KERN_ERR, "not specified filesystem type " "(media:exfat, opts:%s)", FS_TYPE_STR[opts->fs_type]); @@ -1759,9 +1763,9 @@ s32 fscore_mount(struct super_block *sb) opts->improved_allocation = 0; opts->defrag = 0; ret = mount_exfat(sb, p_pbr); - } else if(is_fat32(p_pbr)) { - if(opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { - sdfat_log_msg(sb, KERN_ERR, + } else if (is_fat32(p_pbr)) { + if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { + sdfat_log_msg(sb, KERN_ERR, "not specified filesystem type " "(media:vfat, opts:%s)", FS_TYPE_STR[opts->fs_type]); @@ -1772,8 +1776,8 @@ s32 fscore_mount(struct super_block *sb) sb->s_maxbytes = 0xffffffff; ret = mount_fat32(sb, p_pbr); } else { - if(opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { - sdfat_log_msg(sb, KERN_ERR, + if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { + sdfat_log_msg(sb, KERN_ERR, "not specified filesystem type " "(media:vfat, opts:%s)", FS_TYPE_STR[opts->fs_type]); @@ -1802,8 +1806,13 @@ free_bh: (fsi->data_start_sector & (fsi->sect_per_clus - 1)) ? "misaligned" : "aligned"); - ret = load_upcase_table(sb); - if (ret) { + sdfat_log_msg(sb, KERN_INFO, + "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"); goto bd_close; } @@ -1831,7 +1840,7 @@ s32 fscore_umount(struct super_block *sb) { s32 ret = 0; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - + if (fs_sync(sb, 0)) ret = -EIO; @@ -1886,7 +1895,7 @@ s32 fscore_sync_fs(struct super_block *sb, s32 do_sync) if (fs_set_vol_flags(sb, VOL_CLEAN)) return -EIO; - + return 0; } @@ -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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + if (fsi->fs_func->get_au_stat) 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; DOS_NAME_T dos_name; DENTRY_T *ep, *ep2; - ENTRY_SET_CACHE_T *es=NULL; + ENTRY_SET_CACHE_T *es = NULL; struct super_block *sb = inode->i_sb; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); FILE_ID_T *dir_fid = &(SDFAT_I(inode)->fid); @@ -2236,7 +2246,7 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou } else { if (new_clu.flags != fid->flags) { /* no-fat-chain bit is disabled, - * so fat-chain should be synced with + * so fat-chain should be synced with * alloc-bmp */ chain_cont_cluster(sb, fid->start_clu, num_clusters); @@ -2261,9 +2271,9 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou /* byte offset in cluster */ offset = (s32)(fid->rwoffset & (fsi->cluster_size-1)); /* sector offset in cluster */ - sec_offset = offset >> blksize_bits; + sec_offset = offset >> blksize_bits; /* byte offset in sector */ - offset &= blksize_mask; + offset &= blksize_mask; LogSector = CLUS_TO_SECT(fsi, clu) + sec_offset; oneblkwrite = (u64)(blksize - offset); @@ -2275,9 +2285,9 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou if (ret) goto err_out; - memcpy( ((s8 *) tmp_bh->b_data), - ((s8 *) buffer)+write_bytes, - (s32) oneblkwrite); + memcpy(((s8 *)tmp_bh->b_data), + ((s8 *)buffer)+write_bytes, + (s32)oneblkwrite); ret = write_sect(sb, LogSector, tmp_bh, 0); if (ret) { @@ -2387,9 +2397,9 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) struct super_block *sb = inode->i_sb; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 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; - + /* check if the given file ID is opened */ if ((fid->type != TYPE_FILE) && (fid->type != TYPE_DIR)) return -EPERM; @@ -2403,7 +2413,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) /* It can be when write failed */ #if 0 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); 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?) */ BUG_ON(num_clusters_da < num_clusters_phys); - if ( (num_clusters_da != num_clusters_phys) && - (num_clusters_new < num_clusters_da) ) { + if ((num_clusters_da != num_clusters_phys) && + (num_clusters_new < num_clusters_da)) { /* 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) ? \ - (num_clusters_da - num_clusters_new) : \ + int n_reserved = (num_clusters_new > num_clusters_phys) ? + (num_clusters_da - num_clusters_new) : (num_clusters_da - num_clusters_phys); fsi->reserved_clusters -= n_reserved; @@ -2444,22 +2454,24 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) clu.dir = fid->start_clu; /* In no-da case, num_clusters_phys is equal to below value - * clu.size = (s32)((old_size-1) >> fsi->cluster_size_bits) + 1; + * clu.size = (s32)((old_size-1) >> fsi->cluster_size_bits) + 1; */ clu.size = num_clusters_phys; clu.flags = fid->flags; + /* For bigdata */ + sdfat_statistics_set_trunc(clu.flags, &clu); + if (new_size > 0) { /* 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; /* 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) { clu.dir += 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)) { s32 fclus_tmp = 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); if (err) return -EIO; @@ -2499,20 +2512,18 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) } } - /* - Optimization avialable - + /* Optimization avialable: */ +#if 0 if (num_clusters_new < num_clusters) { - - + < loop > } else { - // num_clusters_new >= num_clusters_phys + // num_clusters_new >= num_clusters_phys // FAT truncation is not necessary clu.dir = CLUS_EOF; clu.size = 0; } - */ +#endif } else if (new_size == 0) { fid->flags = (fsi->vol_type == EXFAT) ? 0x03 : 0x01; 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; /* - clu.dir: free from - clu.size: # of clusters to free (exFAT, 0x03 only) - if 0, no fat_free - clu.flags: fid->flags (exFAT only) - */ + * clu.dir: free from + * clu.size: # of clusters to free (exFAT, 0x03 only), no fat_free if 0 + * clu.flags: fid->flags (exFAT only) + */ /* (1) update the directory entry */ 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_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 */ 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 */ if ((fid->flags == 0x01) && (!IS_CLUS_FREE(last_clu)) && (!IS_CLUS_EOF(last_clu))) { - if (fat_ent_set(sb, last_clu, CLUS_EOF)) - return -EIO; + if (fat_ent_set(sb, last_clu, CLUS_EOF)) + return -EIO; } /* (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; } /* 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); /* @@ -2625,18 +2637,19 @@ static void update_parent_info( FILE_ID_T *fid, struct inode *parent_inode) fid->dir.dir = parent_fid->start_clu; fid->dir.flags = parent_fid->flags; - fid->dir.size = ((parent_fid->size + (fsi->cluster_size-1)) + fid->dir.size = ((parent_fid->size + (fsi->cluster_size-1)) >> fsi->cluster_size_bits); } } /* 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 dentry; CHAIN_T olddir, newdir; - CHAIN_T *p_dir=NULL; + CHAIN_T *p_dir = NULL; UNI_NAME_T uni_name; DENTRY_T *ep; 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; FILE_ID_T *new_fid = NULL; u32 new_entry_type = TYPE_UNUSED; - s32 new_entry=0; + s32 new_entry = 0; /* check the validity of pointer parameters */ if ((new_path == NULL) || (strlen(new_path) == 0)) @@ -2691,7 +2704,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode * goto out; } - /* patch 1.2.4 : + /* patch 1.2.4 : * the problem that FILE_ID_T caches wrong parent info. * * FIXME : is needed? @@ -2711,6 +2724,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode * if (new_entry_type == TYPE_DIR) { CHAIN_T new_clu; + new_clu.dir = new_fid->start_clu; new_clu.size = (s32)((new_fid->size-1) >> fsi->cluster_size_bits) + 1; 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) { /* new_fid, new_clu_to_free */ CHAIN_T new_clu_to_free; + 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.flags = new_fid->flags; @@ -2772,7 +2787,7 @@ s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode * } del_out: /* Update new_inode fid - * Prevent syncing removed new_inode + * Prevent syncing removed new_inode * (new_fid is already initialized above code ("if (new_inode)") */ new_fid->dir.dir = DIR_DELETED; @@ -2836,7 +2851,7 @@ s32 fscore_remove(struct inode *inode, FILE_ID_T *fid) /* (3) update FILE_ID_T */ fid->size = 0; 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; 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; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 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; 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); /* 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; memset((s8 *) &info->CreateTimestamp, 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; } else { s32 num_clu; + if (__count_num_clusters(sb, &dir, &num_clu)) return -EIO; 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) { u32 dotcnt = 0; + dir.dir = fid->start_clu; dir.flags = fid->flags; dir.size = fid->size >> fsi->cluster_size_bits; @@ -2958,18 +2975,19 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info) * NOTE : * If "dir.flags" has 0x01, "dir.size" is meaningless. */ +#if 0 + if (info->Size == 0) { + s32 num_clu; -// if (info->Size == 0) { -// s32 num_clu; -// if (__count_num_clusters(sb, &dir, &num_clu)) -// return -EIO; -// info->Size = (u64)num_clu << fsi->cluster_size_bits; -// } - + if (__count_num_clusters(sb, &dir, &num_clu)) + return -EIO; + info->Size = (u64)num_clu << fsi->cluster_size_bits; + } +#endif count = __count_dos_name_entries(sb, &dir, TYPE_DIR, &dotcnt); if (count < 0) return -EIO; - + if (fsi->vol_type == EXFAT) { count += SDFAT_MIN_SUBDIR; } else { @@ -3001,7 +3019,7 @@ s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, s32 sync) u32 sector; TIMESTAMP_T tm; DENTRY_T *ep, *ep2; - ENTRY_SET_CACHE_T *es=NULL; + ENTRY_SET_CACHE_T *es = NULL; struct super_block *sb = inode->i_sb; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 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); if (is_dir && fsi->vol_type != EXFAT) { - /* if FAT32, and dir size != 0 - overwrite dirsize */ + /* overwirte dirsize if FAT32 and dir size != 0 */ if (fsi->fs_func->get_entry_size(ep2)) fsi->fs_func->set_entry_size(ep2, 0); } else { /* File size should be zero if there is no cluster allocated */ u64 on_disk_size = info->Size; + if (IS_CLUS_EOF(fid->start_clu)) 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_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; 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; /* 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 ((clu_offset > 0) && (!IS_CLUS_EOF(*clu))) { last_clu += clu_offset - 1; @@ -3129,7 +3148,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) else *clu += clu_offset; } - } else if (fid->type == TYPE_FILE){ + } else if (fid->type == TYPE_FILE) { s32 fclus = 0; s32 err = extent_get_clus(inode, clu_offset, &fclus, clu, &last_clu, 1); @@ -3172,7 +3191,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) "fid->hint_clu(%u) fid->rwoffset(%llu) " "modified_clu_off(%d) last_clu(%08x) " "new_clu(%08x)", __func__, inode, - num_to_be_allocated, + num_to_be_allocated, (SDFAT_I(inode)->i_size_ondisk), fid->flags, fid->start_clu, fid->hint_bmap.off, fid->hint_bmap.clu, @@ -3190,7 +3209,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) ASSERT(!num_alloced); } else { DMSG("%s : ENOSPC (requested:%d, alloced:%d)\n", - __func__, num_alloced, + __func__, num_alloced, num_to_be_allocated); } return -ENOSPC; @@ -3255,7 +3274,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) if (fsi->fs_func->get_entry_flag(ep) != fid->flags) fsi->fs_func->set_entry_flag(ep, fid->flags); - + if (fsi->fs_func->get_entry_clu0(ep) != fid->start_clu) fsi->fs_func->set_entry_clu0(ep, fid->start_clu); @@ -3274,7 +3293,7 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) } } /* end of if != DIR_DELETED */ - + /* add number of new blocks to inode (non-DA only) */ if (!(SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_DELAY)) { @@ -3283,10 +3302,10 @@ s32 fscore_map_clus(struct inode *inode, s32 clu_offset, u32 *clu, int dest) // DA의 경우, i_blocks가 이미 증가해있어야 함. BUG_ON(clu_offset >= (inode->i_blocks >> (fsi->cluster_size_bits - sb->s_blocksize_bits))); } - /* fs_sync(sb, 0); - fs_set_vol_flags(sb, VOL_CLEAN); */ - - +#if 0 + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif /* (4) Move *clu pointer along FAT chains (hole care) * because the caller of this function expect *clu to be the last cluster. * This only works when num_to_be_allocated >= 2, @@ -3326,15 +3345,14 @@ s32 fscore_reserve_clus(struct inode *inode) return -EIO; } - if ((fsi->used_clusters + fsi->reserved_clusters) >= - (fsi->num_clusters - 2)) + if ((fsi->used_clusters + fsi->reserved_clusters) >= (fsi->num_clusters - 2)) return -ENOSPC; if (bdev_check_bdi_valid(sb)) return -EIO; fsi->reserved_clusters++; - + /* inode->i_blocks update */ inode->i_blocks += 1 << (fsi->cluster_size_bits - sb->s_blocksize_bits); @@ -3629,8 +3647,8 @@ s32 fscore_rmdir(struct inode *inode, FILE_ID_T *fid) ret = check_dir_empty(sb, &clu_to_free); if (ret) { if (ret == -EIO) - EMSG("%s : failed to check_dir_empty : err(%d)\n", - __func__,ret); + EMSG("%s : failed to check_dir_empty : err(%d)\n", + __func__, ret); return ret; } diff --git a/core.h b/core.h index 8f3c367..303f02d 100644 --- a/core.h +++ b/core.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #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_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_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_read_inode(struct inode *inode, DIR_ENTRY_T *info); 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); /* 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 */ s32 meta_cache_init(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_release_all(struct super_block *sb); 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_lock(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); 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); -void release_dentry_set (ENTRY_SET_CACHE_T *es); +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); +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_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); 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 */ 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 */ /* amap_smart.c : misc (for defrag) */ diff --git a/core_exfat.c b/core_exfat.c index 35b79c4..f88c488 100644 --- a/core_exfat.c +++ b/core_exfat.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -94,46 +92,44 @@ static u32 exfat_get_entry_type(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; - } else if (ep->type < 0x80) { + if (ep->type < 0x80) return TYPE_DELETED; - } else if (ep->type == 0x80) { + if (ep->type == 0x80) return TYPE_INVALID; - } else if (ep->type < 0xA0) { - if (ep->type == 0x81) { + if (ep->type < 0xA0) { + if (ep->type == 0x81) return TYPE_BITMAP; - } else if (ep->type == 0x82) { + if (ep->type == 0x82) return TYPE_UPCASE; - } else if (ep->type == 0x83) { + if (ep->type == 0x83) return TYPE_VOLUME; - } else if (ep->type == 0x85) { + if (ep->type == 0x85) { if (le16_to_cpu(ep->attr) & ATTR_SUBDIR) return TYPE_DIR; - else - return TYPE_FILE; + return TYPE_FILE; } return TYPE_CRITICAL_PRI; - } else if (ep->type < 0xC0) { - if (ep->type == 0xA0) { + } + if (ep->type < 0xC0) { + if (ep->type == 0xA0) return TYPE_GUID; - } else if (ep->type == 0xA1) { + if (ep->type == 0xA1) return TYPE_PADDING; - } else if (ep->type == 0xA2) { + if (ep->type == 0xA2) return TYPE_ACLTAB; - } return TYPE_BENIGN_PRI; - } else if (ep->type < 0xE0) { - if (ep->type == 0xC0) { + } + if (ep->type < 0xE0) { + if (ep->type == 0xC0) return TYPE_STREAM; - } else if (ep->type == 0xC1) { + if (ep->type == 0xC1) return TYPE_EXTEND; - } else if (ep->type == 0xC2) { + if (ep->type == 0xC2) return TYPE_ACL; - } return TYPE_CRITICAL_SEC; } - return TYPE_BENIGN_SEC; } /* 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) { - FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; - return((u32) le16_to_cpu(ep->attr)); + FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry; + + return (u32)le16_to_cpu(ep->attr); } /* end of exfat_get_entry_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); } /* end of exfat_set_entry_attr */ static u8 exfat_get_entry_flag(DENTRY_T *p_entry) { - STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; - return(ep->flags); + STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry; + + return ep->flags; } /* end of exfat_get_entry_flag */ 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; } /* end of exfat_set_entry_flag */ static u32 exfat_get_entry_clu0(DENTRY_T *p_entry) { - STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; - return le32_to_cpu(ep->start_clu); + STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry; + + return (u32)le32_to_cpu(ep->start_clu); } /* end of exfat_get_entry_clu0 */ 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); } /* end of exfat_set_entry_clu0 */ 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); } /* end of exfat_get_entry_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->size = cpu_to_le64(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) { 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) { 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) { 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); 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; } -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); 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); num_entries = count; - while(num_entries) { - // white per sector base + while (num_entries) { + /* write per sector base */ 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); if (!buf) goto err_out; @@ -484,18 +489,18 @@ err_out: /* write back all entries in entry set */ 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; u16 chksum = 0; s32 chksum_type = CS_DIR_ENTRY, i; ep = (DENTRY_T *)&(es->__buf); - for (i=0; i < es->num_entries; i++) { - MMSG ("%s %p\n", __func__, ep); + for (i = 0; i < es->num_entries; i++) { + MMSG("%s %p\n", __func__, ep); chksum = calc_chksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type); ep++; 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_NAME_ENTRY 3 #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; - u32 clu=0; + u32 clu = 0; u32 sec, entry_type; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 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); - while(num_entries) { + while (num_entries) { // 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); if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) goto err_out; - switch(mode) { + switch (mode) { case ES_MODE_STARTED: if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) 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) break; - if ( ((off + DENTRY_SIZE) & (u32)(sb->s_blocksize - 1)) < - (off & (u32)(sb->s_blocksize - 1)) ) { + if (((off + DENTRY_SIZE) & (u32)(sb->s_blocksize - 1)) < + (off & (u32)(sb->s_blocksize - 1))) { // get the next sector if (IS_LAST_SECT_IN_CLUS(fsi, sec)) { 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; err_out: TMSG("%s exited (return NULL) (es %p)\n", __func__, es); - if (es) { - kfree(es); - es = NULL; - } + + /* kfree(NULL) is safe */ + kfree(es); + es = 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); - if (es) { - kfree(es); - es = NULL; - } + + /* kfree(NULL) is safe */ + kfree(es); + es = NULL; } 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? */ *uniname = le16_to_cpu(ep->unicode_0_14[i]); if (*uniname == 0x0) - return(len); + return len; uniname++; len++; } *uniname = 0x0; - return(len); - + return len; } /* end of __extract_uni_name_from_name_entry */ #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 * -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 order, step, name_len; @@ -909,6 +915,7 @@ found: /* next dentry we'll find is out of this cluster */ if (!((dentry + 1) & (dentries_per_clu-1))) { int ret = 0; + if (clu.flags == 0x03) { if ((--clu.size) > 0) clu.dir++; @@ -945,11 +952,10 @@ static s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 e return -EIO; type = exfat_get_entry_type(ext_ep); - if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) { + if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) count++; - } else { + else 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 */ +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 @@ -1013,7 +1028,7 @@ static s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname) s32 load_alloc_bmp(struct super_block *sb) { s32 i, j, ret; - u32 map_size; + u32 map_size, need_map_size; u32 type, sector; CHAIN_T clu; 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); map_size = (u32) le64_to_cpu(ep->size); - fsi->map_sectors = ((map_size-1) >> (sb->s_blocksize_bits)) + 1; - fsi->vol_amap = (struct buffer_head **) kmalloc((sizeof(struct buffer_head *) * fsi->map_sectors), GFP_KERNEL); + need_map_size = (((fsi->num_clusters - CLUS_BASE) - 1) >> 3) + 1; + 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) 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); if (ret) { /* release all buffers and free vol_amap */ - i=0; + i = 0; while (i < j) brelse(fsi->vol_amap[i++]); - if (fsi->vol_amap) { - kfree(fsi->vol_amap); - fsi->vol_amap = NULL; - } + /* kfree(NULL) is safe */ + kfree(fsi->vol_amap); + fsi->vol_amap = NULL; return ret; } } @@ -1082,14 +1106,12 @@ void free_alloc_bmp(struct super_block *sb) 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]); - } - if(fsi->vol_amap) { - kfree(fsi->vol_amap); - fsi->vol_amap = NULL; - } + /* kfree(NULL) is safe */ + kfree(fsi->vol_amap); + fsi->vol_amap = NULL; } /* WARN : @@ -1106,8 +1128,7 @@ static s32 set_alloc_bitmap(struct super_block *sb, u32 clu) b = clu & (u32)((sb->s_blocksize << 3) - 1); 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); } /* 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; - 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); if (opts->discard) { s32 ret_discard; + TMSG("discard cluster(%08x)\n", clu+2); ret_discard = sb_issue_discard(sb, CLUS_TO_SECT(fsi, clu+2), (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); hint_clu = 2; 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; 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; while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUS_EOF) { - if ( (new_clu != hint_clu) && (p_chain->flags == 0x03) ) { - if (exfat_chain_cont_cluster( sb, p_chain->dir, num_clusters)) + if ((new_clu != hint_clu) && (p_chain->flags == 0x03)) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters)) return -EIO; p_chain->flags = 0x01; } @@ -1395,7 +1417,7 @@ out: return ret; } /* 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 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) { 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) { map_i++; 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, .count_ext_entries = exfat_count_ext_entries, .calc_num_entries = exfat_calc_num_entries, + .check_max_dentries = exfat_check_max_dentries, .get_entry_type = exfat_get_entry_type, .set_entry_type = exfat_set_entry_type, @@ -1496,7 +1519,7 @@ s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr) fsi->fs_func = &exfat_fs_func; fat_ent_ops_init(sb); - + if (p_bpb->bsx.vol_flags & VOL_DIRTY) { fsi->vol_flag |= VOL_DIRTY; sdfat_log_msg(sb, KERN_WARNING, "Volume was not properly " diff --git a/core_fat.c b/core_fat.c index 4bbfd22..fc40c6e 100644 --- a/core_fat.c +++ b/core_fat.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -141,7 +139,7 @@ static u32 __calc_default_au_size(struct super_block *sb) out: if (sb->s_blocksize != 512) { ASSERT(sb->s_blocksize_bits > 9); - sdfat_log_msg(sb, KERN_INFO, + sdfat_log_msg(sb, KERN_INFO, "adjustment est_au_size by logical block size(%lu)", sb->s_blocksize); est_au_sect >>= (sb->s_blocksize_bits - 9); @@ -250,26 +248,31 @@ static s32 fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_rel goto out; } } - + prev = clu; - if (get_next_clus(sb, &clu)) - goto out; - - /* FAT validity check */ - if (IS_CLUS_FREE(clu)) { - /* GRACEFUL ERROR HANDLING */ - /* Broken FAT chain (Already FREE) */ - sdfat_fs_error(sb, "%s : deleting FAT entry beyond EOF (clu[%u]->0)", __func__, prev); + if (get_next_clus_safe(sb, &clu)) { + /* print more helpful log */ + if (IS_CLUS_BAD(clu)) { + sdfat_log_msg(sb, KERN_ERR, "%s : " + "deleting bad cluster (clu[%u]->BAD)", + __func__, prev); + } else if (IS_CLUS_FREE(clu)) { + sdfat_log_msg(sb, KERN_ERR, "%s : " + "deleting free cluster (clu[%u]->FREE)", + __func__, prev); + } goto out; } /* Free FAT chain */ if (fat_ent_set(sb, prev, CLUS_FREE)) goto out; - + /* Update AMAP if needed */ - if (fsi->amap) - amap_release_cluster(sb, prev); + if (fsi->amap) { + if (amap_release_cluster(sb, prev)) + return -EIO; + } num_clusters++; @@ -283,7 +286,7 @@ out: return ret; } /* 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; 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) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; /* first byte of 32bytes dummy */ 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) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; if (type == TYPE_UNUSED) *(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) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; - return((u32) ep->attr); + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; + + return (u32)ep->attr; } /* end of fat_get_entry_attr */ static void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; - ep->attr = (u8) attr; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; + + ep->attr = (u8)attr; } /* end of fat_set_entry_attr */ 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) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; /* FIXME : is ok? */ return(((u32)(le16_to_cpu(ep->start_clu_hi)) << 16) | le16_to_cpu(ep->start_clu_lo)); } /* end of fat_get_entry_clu0 */ 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_hi = cpu_to_le16(CLUSTER_16(start_clu >> 16)); } /* end of fat_set_entry_clu0 */ static u64 fat_get_entry_size(DENTRY_T *p_entry) { - DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; - return((u64) le32_to_cpu(ep->size)); + DOS_DENTRY_T *ep = (DOS_DENTRY_T *)p_entry; + + return (u64)le32_to_cpu(ep->size); } /* end of fat_get_entry_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); } /* 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 */ - for (i = 0; i < 6; i ++) { + for (i = 0; i < 6; i++) { if (!end) { ep->unicode_5_10[i] = cpu_to_le16(*uniname); 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; } -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 chksum = 0, lfn_ord = 0, lfn_len = 0; @@ -685,8 +694,8 @@ rewind: } /* invalid lfn order */ - if ( !cur_ord || (cur_ord > MAX_LFN_ORDER) || - ((cur_ord + 1) != lfn_ord) ) + if (!cur_ord || (cur_ord > MAX_LFN_ORDER) || + ((cur_ord + 1) != lfn_ord)) goto reset_dentry_set; /* check checksum of directory entry set */ @@ -702,7 +711,7 @@ rewind: continue; } - if(!uniname) { + if (!uniname) { sdfat_fs_error(sb, "%s : abnormal dentry " "(start_clu[%u], " @@ -760,16 +769,16 @@ rewind: */ if (!lfn_len || (cur_chksum != chksum)) { /* check shortname */ - if ( (p_dosname->name[0] != '\0') && + if ((p_dosname->name[0] != '\0') && !nls_cmp_sfn(sb, p_dosname->name, - dos_ep->name) ) { + dos_ep->name)) { goto found; } /* check name length */ - } else if ( (lfn_len > 0) && + } else if ((lfn_len > 0) && ((s32)p_uniname->name_len == - lfn_len) ) { + lfn_len)) { 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); 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) return -EIO; - if ( (fat_get_entry_type((DENTRY_T*)ext_ep) == TYPE_EXTEND) && - (ext_ep->checksum == chksum) ) { + if ((fat_get_entry_type((DENTRY_T *)ext_ep) == TYPE_EXTEND) && + (ext_ep->checksum == chksum)) { count++; if (ext_ep->order > MSDOS_LAST_LFN) 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++) { *uniname = get_unaligned_le16(&(ep->unicode_0_4[i<<1])); if (*uniname == 0x0) - return(len); + return len; uniname++; len++; } @@ -910,7 +919,7 @@ static s32 __extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 /* FIXME : unaligned? */ *uniname = le16_to_cpu(ep->unicode_5_10[i]); if (*uniname == 0x0) - return(len); + return len; uniname++; len++; } @@ -919,25 +928,25 @@ static s32 __extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 /* FIXME : unaligned? */ *uniname = le16_to_cpu(ep->unicode_5_10[i]); if (*uniname == 0x0) - return(len); + return len; uniname++; len++; } *uniname = 0x0; /* uniname[MAX_NAME_LENGTH] */ - return(len); + return len; } for (i = 0; i < 2; i++) { /* FIXME : unaligned? */ *uniname = le16_to_cpu(ep->unicode_11_12[i]); if (*uniname == 0x0) - return(len); + return len; uniname++; len++; } *uniname = 0x0; - return(len); + return len; } /* 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++) { EXT_DENTRY_T *ep; + ep = (EXT_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, NULL); if (!ep) 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: *uniname = (u16)0x0; - return; } /* end of fat_get_uniname_from_ext_entry */ /* Find if the shortname exists - 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) + * 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) { u32 type; s32 i, dentry = 0; @@ -1004,7 +1014,7 @@ static s32 __fat_find_shortname_entry(struct super_block *sb, CHAIN_T *p_dir, u8 else 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++) { ep = get_dentry_in_dir(sb, &clu, i, NULL); 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); 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) baselen = 6; @@ -1091,7 +1102,7 @@ s32 fat_generate_dos_name_new(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T /* void return */ __fat_attach_count_to_dos_name(p_dosname->name, i); return 0; - } + } /* any other error */ if (err) @@ -1141,6 +1152,14 @@ static s32 fat_calc_num_entries(UNI_NAME_T *p_uniname) } /* 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, .count_ext_entries = fat_count_ext_entries, .calc_num_entries = fat_calc_num_entries, + .check_max_dentries = fat_check_max_dentries, .get_entry_type = fat_get_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, .count_ext_entries = fat_count_ext_entries, .calc_num_entries = fat_calc_num_entries, + .check_max_dentries = fat_check_max_dentries, .get_entry_type = fat_get_entry_type, .set_entry_type = fat_set_entry_type, @@ -1348,7 +1369,7 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr) fsi->num_clusters = ((fsi->num_sectors-num_reserved) >> fsi->sect_per_clus_bits) + 2; /* because the cluster index starts with 2 */ - + fsi->vol_type = FAT32; fsi->vol_id = get_unaligned_le32(p_bpb->bsx.vol_serial); @@ -1382,23 +1403,23 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr) "sector : bpb(%u) != ondisk(%u)", hidden_sectors, calc_hid_sect); if (SDFAT_SB(sb)->options.adj_hidsect) { - sdfat_log_msg(sb, KERN_INFO, + sdfat_log_msg(sb, KERN_INFO, "adjustment hidden sector : " - "bpb(%u) -> ondisk(%u)", + "bpb(%u) -> ondisk(%u)", hidden_sectors, calc_hid_sect); hidden_sectors = calc_hid_sect; } } SDFAT_SB(sb)->options.amap_opt.misaligned_sect = hidden_sectors; - + /* calculate AU size if it's not set */ if (!SDFAT_SB(sb)->options.amap_opt.sect_per_au) { - SDFAT_SB(sb)->options.amap_opt.sect_per_au = + SDFAT_SB(sb)->options.amap_opt.sect_per_au = __calc_default_au_size(sb); } - - ret = amap_create(sb, + + ret = amap_create(sb, SDFAT_SB(sb)->options.amap_opt.pack_ratio, SDFAT_SB(sb)->options.amap_opt.sect_per_au, SDFAT_SB(sb)->options.amap_opt.misaligned_sect); @@ -1412,8 +1433,8 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr) } /* Check dependency of mount options */ - if (SDFAT_SB(sb)->options.improved_allocation != - (SDFAT_ALLOC_DELAY | SDFAT_ALLOC_SMART) ) { + if (SDFAT_SB(sb)->options.improved_allocation != + (SDFAT_ALLOC_DELAY | SDFAT_ALLOC_SMART)) { sdfat_log_msg(sb, KERN_INFO, "disabling defragmentation because" " smart, delay options are disabled"); SDFAT_SB(sb)->options.defrag = 0; diff --git a/dfr.c b/dfr.c index aed7544..b06ae84 100644 --- a/dfr.c +++ b/dfr.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -62,7 +60,7 @@ defrag_get_info( arg->total_sec = fsi->num_sectors; arg->fat_offset_sec = fsi->FAT1_start_sector; 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->hidden_sectors = amap->option.au_align_factor % amap->option.au_size; @@ -139,7 +137,7 @@ error: * @return 0 on success, -errno otherwise * @param sb super block * @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 defrag_scan_dir( @@ -149,7 +147,7 @@ defrag_scan_dir( struct sdfat_sb_info *sbi = NULL; FS_INFO_T *fsi = NULL; struct defrag_trav_header *header = NULL; - IN DOS_DENTRY_T *dos_ep; + DOS_DENTRY_T *dos_ep; CHAIN_T chain; int dot_found = 0, args_idx = DFR_TRAV_HEADER_IDX + 1, clus = 0, index = 0; int err = 0, j = 0; @@ -186,9 +184,9 @@ defrag_scan_dir( } /* For more-scan case */ - if ((header->stat == DFR_TRAV_STAT_MORE) && - (header->start_clus == sbi->dfr_hint_clus) && - (sbi->dfr_hint_idx > 0) ) { + if ((header->stat == DFR_TRAV_STAT_MORE) && + (header->start_clus == sbi->dfr_hint_clus) && + (sbi->dfr_hint_idx > 0)) { index = sbi->dfr_hint_idx; 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]); if (!err) { /* 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_idx = clus * fsi->dentries_per_clu + index + 1; @@ -252,10 +250,10 @@ scan_fat_chain: /* End case */ } else if (err == -ENOENT) { sbi->dfr_hint_clus = sbi->dfr_hint_idx = 0; - err = 0; + err = 0; goto done; } else { - ; + /* DO NOTHING */ } err = 0; } @@ -299,7 +297,7 @@ __defrag_validate_cluster_prev( dir.flags = 0x1; // Assume non-continuous entry = GET64_LO(chunk->i_pos); - + FAT32_CHECK_CLUSTER(fsi, dir.dir, err); ERR_HANDLE(err); ep = get_dentry_in_dir(sb, &dir, entry, NULL); @@ -369,7 +367,7 @@ __defrag_check_au( { 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) { AMAP_T *amap = SDFAT_SB(sb)->fsi.amap; 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); } #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) return -ENOENT; - /* Skip working-AU */ - err = amap_check_working(sb, chunk->d_clus); - if (err) - return -EBUSY; + /* Skip working-AU */ + err = amap_check_working(sb, chunk->d_clus); + if (err) + return -EBUSY; /* Check # of free_clus of belonged AU */ - err = __defrag_check_au(inode->i_sb, chunk->d_clus, CLUS_PER_AU(sb) - chunk->au_clus); - if (err) - return -EINVAL; + err = __defrag_check_au(inode->i_sb, chunk->d_clus, CLUS_PER_AU(sb) - chunk->au_clus); + if (err) + return -EINVAL; /* Check chunk's clusters */ for (i = 0; i < chunk->nr_clus; i++) { @@ -457,7 +454,7 @@ defrag_reserve_clusters( struct sdfat_sb_info *sbi = SDFAT_SB(sb); 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 */ return 0; @@ -519,8 +516,6 @@ defrag_unmark_ignore_all(struct super_block *sb) { if (SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART) amap_unmark_ignore_all(sb); - - return; } @@ -535,7 +530,7 @@ defrag_unmark_ignore_all(struct super_block *sb) */ int defrag_map_cluster( - struct inode *inode, + struct inode *inode, unsigned int clu_offset, unsigned int *clu) { @@ -596,11 +591,10 @@ defrag_map_cluster( /* Make FAT-chain for new_clus */ for (i = 0; i < chunk->nr_clus; i++) { #if 0 - if (sbi->dfr_new_clus[chunk->new_idx + i]) { + if (sbi->dfr_new_clus[chunk->new_idx + i]) nr_new++; - } else { + else break; - } #else if (!sbi->dfr_new_clus[chunk->new_idx + i]) break; @@ -611,7 +605,7 @@ defrag_map_cluster( for (i = 0; i < chunk->nr_clus - 1; i++) { FAT32_CHECK_CLUSTER(fsi, sbi->dfr_new_clus[chunk->new_idx + i], err); BUG_ON(err); - if (fat_ent_set(sb, + if (fat_ent_set(sb, sbi->dfr_new_clus[chunk->new_idx + i], sbi->dfr_new_clus[chunk->new_idx + i + 1])) return -EIO; @@ -654,11 +648,11 @@ defrag_writepage_end_io( chunk_start = chunk->f_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; - clear_bit( (page->index & (PAGES_PER_CLUS(sb) - 1)), - (volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + off]) ); + clear_bit((page->index & (PAGES_PER_CLUS(sb) - 1)), + (volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + off])); } } } @@ -683,7 +677,7 @@ __defrag_check_wb( /* Check WB complete status first */ 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; break; } @@ -700,7 +694,7 @@ __defrag_check_wb( if (nr_new == chunk->nr_clus) { 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)", chunk->nr_clus, wb_i); @@ -741,9 +735,9 @@ __defrag_check_fat_old( err = fat_ent_get(sb, clus, &clus); 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, " - "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); BUG_ON(idx < max_idx - 1); goto error; @@ -804,14 +798,13 @@ __defrag_check_fat_new( BUG_ON(err); err = fat_ent_get(sb, sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], &clus); 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); err = EIO; } error: BUG_ON(err); - return; } @@ -872,7 +865,7 @@ defrag_update_fat_prev( struct defrag_info *sb_dfr = &sbi->dfr_info, *ino_dfr = NULL; int skip = 0, done = 0; - /* Check if FS_ERROR occured */ + /* Check if FS_ERROR occurred */ if (sb->s_flags & MS_RDONLY) { dfr_err("RDONLY partition (err %d)", -EPERM); goto out; @@ -885,7 +878,7 @@ defrag_update_fat_prev( int i = 0, j = 0; 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++) { struct defrag_chunk_info *chunk = NULL; int err = 0; @@ -906,15 +899,16 @@ defrag_update_fat_prev( } /* Double-check clusters */ - if ( chunk_prev && + if (chunk_prev && (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); /* Handle continuous chunks in a file */ 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", 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. * 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) { err = -EPERM; dfr_err("Skip case: inode %p, stat %x, f_clus %d, err %d", @@ -1014,13 +1008,13 @@ error: out: if (skip) { - dfr_debug("%s skipped (nr_reqs %d, done %d, skip %d)", + dfr_debug("%s skipped (nr_reqs %d, done %d, skip %d)", __func__, sb_dfr->nr_chunks - 1, done, skip); } else { /* Make dfr_reserved_clus zero */ if (sbi->dfr_reserved_clus > 0) { if (fsi->reserved_clusters < sbi->dfr_reserved_clus) { - dfr_err("Reserved count: reserved_clus %d, dfr_reserved_clus %d", + dfr_err("Reserved count: reserved_clus %d, dfr_reserved_clus %d", fsi->reserved_clusters, sbi->dfr_reserved_clus); BUG_ON(fsi->reserved_clusters < sbi->dfr_reserved_clus); } @@ -1050,7 +1044,7 @@ defrag_update_fat_next( struct defrag_chunk_info *chunk = NULL; 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) { dfr_err("RDONLY partition (err %d)", -EROFS); goto out; @@ -1063,7 +1057,7 @@ defrag_update_fat_next( 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) continue; if (chunk->stat & DFR_CHUNK_STAT_FAT) { @@ -1083,7 +1077,7 @@ defrag_update_fat_next( /* Update chunk's next cluster */ 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); if (fat_ent_set(sb, sbi->dfr_new_clus[chunk->new_idx + chunk->nr_clus - 1], @@ -1126,8 +1120,8 @@ defrag_check_discard( BUG_ON(!amap); - if ( !(SDFAT_SB(sb)->options.discard) || - !(SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART) ) + if (!(SDFAT_SB(sb)->options.discard) || + !(SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART)) return; 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)); /* Send DISCARD for free AU */ - if ( (IS_AU_IGNORED(au, amap)) && - (amap_get_freeclus(sb, chunk->d_clus) == CLUS_PER_AU(sb)) ) { + if ((IS_AU_IGNORED(au, amap)) && + (amap_get_freeclus(sb, chunk->d_clus) == CLUS_PER_AU(sb))) { sector_t blk = 0, nr_blks = 0; unsigned int au_align_factor = amap->option.au_align_factor % amap->option.au_size; @@ -1157,11 +1151,11 @@ defrag_check_discard( continue; /* Send DISCARD cmd */ - blk = (sector_t) ( ((au->idx * CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits) - - au_align_factor ); + blk = (sector_t) (((au->idx * CLUS_PER_AU(sb)) << fsi->sect_per_clus_bits) + - au_align_factor); 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); /* Save previous AU's index */ @@ -1204,7 +1198,7 @@ defrag_free_cluster( dfr_err("Free: Already freed, clus %08x, val %08x", clus, val); BUG_ON(!val); } - + set_sb_dirty(sb); fsi->used_clusters--; if (fsi->amap) @@ -1236,14 +1230,14 @@ defrag_check_defrag_required( int clean_ratio = 0, frag_ratio = 0; int ret = 0; - if( !(sb) || !(SDFAT_SB(sb)->options.defrag) ) + if (!sb || !(SDFAT_SB(sb)->options.defrag)) return 0; /* Check DFR_DEFAULT_STOP_RATIO first */ fsi = &(SDFAT_SB(sb)->fsi); if (fsi->used_clusters == (unsigned int)(~0)) { - if (fsi->fs_func->count_used_clusters(sb, &fsi->used_clusters)) - return -EIO; + if (fsi->fs_func->count_used_clusters(sb, &fsi->used_clusters)) + return -EIO; } 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); @@ -1262,12 +1256,11 @@ defrag_check_defrag_required( (fsi->used_clusters * CLUS_PER_AU(sb)); /* - * Wake-up defrag_daemon - * when # of clean AUs too small, - * or frag_ratio exceeds the limit + * Wake-up defrag_daemon: + * when # of clean AUs too small, or frag_ratio exceeds the limit */ - if ( (clean_ratio < DFR_DEFAULT_WAKEUP_RATIO) || - ((clean_ratio < DFR_DEFAULT_CLEAN_RATIO) && (frag_ratio >= DFR_DEFAULT_FRAG_RATIO)) ) { + if ((clean_ratio < DFR_DEFAULT_WAKEUP_RATIO) || + ((clean_ratio < DFR_DEFAULT_CLEAN_RATIO) && (frag_ratio >= DFR_DEFAULT_FRAG_RATIO))) { if (totalau) *totalau = amap->n_au; @@ -1315,8 +1308,8 @@ defrag_check_defrag_on( if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) { clus_start = start >> (fsi->cluster_size_bits); - clus_end = (end >> (fsi->cluster_size_bits)) + - ((end & (fsi->cluster_size - 1))? 1:0); + clus_end = (end >> (fsi->cluster_size_bits)) + + ((end & (fsi->cluster_size - 1)) ? 1 : 0); if (!ino_dfr->chunks) goto error; @@ -1326,18 +1319,17 @@ defrag_check_defrag_on( struct defrag_chunk_info *chunk = &(ino_dfr->chunks[i]); 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)) continue; chunk_start = chunk->f_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_start < chunk_start) && (clus_end > chunk_end)) ) { - ret = 1; - + ((clus_start < chunk_start) && (clus_end > chunk_end))) { + ret = 1; if (cancel) { chunk->stat = DFR_CHUNK_STAT_ERR; 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); - if( !(sb) || !(SDFAT_SB(sb)->options.defrag) ) + if (!sb || !(SDFAT_SB(sb)->options.defrag)) return; if (flag == sbi->dfr_spo_flag) { dfr_err("Defrag SPO test (flag %d, caller %s)", flag, caller); panic("Defrag SPO test"); } - - return; } #endif /* CONFIG_SDFAT_DFR_DEBUG */ diff --git a/dfr.h b/dfr.h index 38f0bdd..19edab3 100644 --- a/dfr.h +++ b/dfr.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_DEFRAG_H @@ -23,45 +21,47 @@ #ifdef CONFIG_SDFAT_DFR /* Tuning parameters */ -#define DFR_MIN_TIMEOUT (1 * HZ) // Minimum timeout for forced-sync -#define DFR_DEFAULT_TIMEOUT (10 * HZ) // Default 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_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_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_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_FULL_RATIO (100) +#define DFR_DEFAULT_STOP_RATIO (98) // Stop defrag_daemon when disk used ratio over 98% +#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*/ -#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 -#define dfr_debug(fmt, args...) DMSG("DFR: " fmt "\n", args) +#define dfr_debug(fmt, args...) pr_debug("DFR: " fmt "\n", args) #else #define dfr_debug(fmt, args...) #endif /* Error handling */ -#define ERR_HANDLE(err) \ - if (err) { \ - dfr_debug("err %d", err); \ - goto error; \ - } +#define ERR_HANDLE(err) { \ + if (err) { \ + dfr_debug("err %d", err); \ + goto error; \ + } \ +} -#define ERR_HANDLE2(cond, err, val) \ - if (cond) { \ - err = val; \ - dfr_debug("err %d", err); \ - goto error; \ - } +#define ERR_HANDLE2(cond, err, val) { \ + if (cond) { \ + err = val; \ + dfr_debug("err %d", err); \ + goto error; \ + } \ +} /* Arguments IN-OUT */ @@ -91,16 +91,16 @@ (SDFAT_SB(sb)->options.amap_opt.sect_per_au) >> (SDFAT_SB(sb)->fsi.sect_per_clus_bits) \ ) #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 \ ) #define PAGES_PER_CLUS(sb) ((SDFAT_SB(sb)->fsi.cluster_size) >> PAGE_SHIFT) #define FAT32_CHECK_CLUSTER(fsi, clus, err) \ { \ - if ( ((clus) < FAT32_UNUSED_CLUS) || \ + if (((clus) < FAT32_UNUSED_CLUS) || \ ((clus) > (fsi)->num_clusters) || \ - ((clus) >= FAT32_RESERVED) ) { \ + ((clus) >= FAT32_RESERVED)) { \ dfr_err("clus %08x, fsi->num_clusters %08x", (clus), (fsi)->num_clusters); \ err = -EINVAL; \ } else { \ @@ -143,7 +143,7 @@ struct defrag_trav_arg { char dummy1; int dummy2; }; - + #define DFR_TRAV_STAT_DONE (0x1) #define DFR_TRAV_STAT_MORE (0x2) #define DFR_TRAV_STAT_ERR (0xFF) @@ -156,7 +156,7 @@ struct defrag_trav_header { char stat; unsigned int nr_entries; }; - + /* IOC_DFR_REQ */ #define REQ_HEADER_IDX (0) diff --git a/extent.c b/extent.c index 276f18e..9349a59 100644 --- a/extent.c +++ b/extent.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /* @@ -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, - u32 *dclus, u32 *last_dclus, s32 allow_eof) + u32 *dclus, u32 *last_dclus, s32 allow_eof) { struct super_block *sb = inode->i_sb; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); @@ -347,11 +345,11 @@ s32 extent_get_clus(struct inode *inode, s32 cluster, s32 *fclus, break; } - + if (!cache_contiguous(&cid, *dclus)) cache_init(&cid, *fclus, *dclus); } - + extent_cache_add(inode, &cid); return 0; } diff --git a/fatent.c b/fatent.c index 8fb88a5..71d3653 100644 --- a/fatent.c +++ b/fatent.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -53,7 +51,7 @@ static s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content) { u32 sec, off, _content; - u8 *fat_sector; + u8 *fat_sector; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); /* fsi->vol_type == EXFAT */ @@ -64,12 +62,11 @@ static s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content) if (!fat_sector) return -EIO; - _content = le32_to_cpu(*(__le32*)(&fat_sector[off])); - if (_content >= CLUSTER_32(0xFFFFFFF8)) { - //return 0xFFFFFFFF to simplify code - *content = CLUS_EOF; - return 0; - } + _content = le32_to_cpu(*(__le32 *)(&fat_sector[off])); + + /* remap reserved clusters to simplify code */ + if (_content >= CLUSTER_32(0xFFFFFFF8)) + _content = CLUS_EOF; *content = CLUSTER_32(_content); return 0; @@ -78,7 +75,7 @@ static s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content) static s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content) { u32 sec, off; - u8 *fat_sector; + u8 *fat_sector; __le32 *fat_entry; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); @@ -95,10 +92,12 @@ static s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content) 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) { u32 sec, off, _content; - u8 *fat_sector; + u8 *fat_sector; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); @@ -108,14 +107,14 @@ static s32 fat32_ent_get(struct super_block *sb, u32 loc, u32 *content) if (!fat_sector) return -EIO; - _content = le32_to_cpu(*(__le32*)(&fat_sector[off])); - _content &= 0x0FFFFFFF; + _content = le32_to_cpu(*(__le32 *)(&fat_sector[off])); + _content &= FATENT_FAT32_VALID_MASK; - if (_content >= CLUSTER_32(0x0FFFFFF8)) { - //return 0xFFFFFFFF to simplify code - *content = CLUS_EOF; - return 0; - } + /* remap reserved clusters to simplify code */ + if (_content == CLUSTER_32(0x0FFFFFF7U)) + _content = CLUS_BAD; + else if (_content >= CLUSTER_32(0x0FFFFFF8U)) + _content = CLUS_EOF; *content = CLUSTER_32(_content); return 0; @@ -128,7 +127,7 @@ static s32 fat32_ent_set(struct super_block *sb, u32 loc, u32 content) __le32 *fat_entry; 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)); off = (loc << 2) & (u32)(sb->s_blocksize - 1); @@ -138,34 +137,35 @@ static s32 fat32_ent_set(struct super_block *sb, u32 loc, u32 content) return -EIO; 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); return fcache_modify(sb, sec); } +#define FATENT_FAT16_VALID_MASK (0x0000FFFFU) static s32 fat16_ent_get(struct super_block *sb, u32 loc, u32 *content) { u32 sec, off, _content; - u8 *fat_sector; + u8 *fat_sector; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-1)); off = (loc << 1) & (u32)(sb->s_blocksize - 1); fat_sector = fcache_getblk(sb, sec); - if(!fat_sector) + if (!fat_sector) return -EIO; - _content = (u32)le16_to_cpu(*(__le16*)(&fat_sector[off])); - _content &= 0x0000FFFF; + _content = (u32)le16_to_cpu(*(__le16 *)(&fat_sector[off])); + _content &= FATENT_FAT16_VALID_MASK; + + /* remap reserved clusters to simplify code */ + if (_content == CLUSTER_16(0xFFF7U)) + _content = CLUS_BAD; + else if (_content >= CLUSTER_16(0xFFF8U)) + _content = CLUS_EOF; - if (_content >= CLUSTER_16(0xFFF8)) { - // return 0x0FFFFFFF to simplify code - *content = CLUS_EOF; - return 0; - } - *content = CLUSTER_32(_content); return 0; } @@ -177,7 +177,7 @@ static s32 fat16_ent_set(struct super_block *sb, u32 loc, u32 content) __le16 *fat_entry; 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)); off = (loc << 1) & (u32)(sb->s_blocksize - 1); @@ -186,16 +186,17 @@ static s32 fat16_ent_set(struct super_block *sb, u32 loc, u32 content) if (!fat_sector) return -EIO; - fat_entry = (__le16*)&(fat_sector[off]); + fat_entry = (__le16 *)&(fat_sector[off]); *fat_entry = cpu_to_le16(content); return fcache_modify(sb, sec); } +#define FATENT_FAT12_VALID_MASK (0x00000FFFU) static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content) { u32 sec, off, _content; - u8 *fat_sector; + u8 *fat_sector; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); sec = fsi->FAT1_start_sector + ((loc + (loc >> 1)) >> sb->s_blocksize_bits); @@ -217,15 +218,16 @@ static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content) _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)) { - /* return 0xFFFFFFFF to simplify code */ - *content = CLUS_EOF; - return 0; - } + /* remap reserved clusters to simplify code */ + if (_content == CLUSTER_16(0x0FF7U)) + _content = CLUS_BAD; + else if (_content >= CLUSTER_16(0x0FF8U)) + _content = CLUS_EOF; *content = CLUSTER_32(_content); return 0; @@ -237,7 +239,7 @@ static s32 fat12_ent_set(struct super_block *sb, u32 loc, u32 content) u8 *fat_sector, *fat_entry; 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); 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); } else { fat_entry = &(fat_sector[off]); - content |= 0x000F & - get_unaligned_le16(fat_entry); - + content |= 0x000F & get_unaligned_le16(fat_entry); put_unaligned_le16(content, fat_entry); } } 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)); } else { fat_entry = &(fat_sector[off]); - content |= 0xF000 & - get_unaligned_le16(fat_entry); - + content |= 0xF000 & get_unaligned_le16(fat_entry); put_unaligned_le16(content, fat_entry); } } @@ -338,12 +336,30 @@ s32 fat_ent_ops_init(struct super_block *sb) 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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 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); return -EIO; } @@ -355,8 +371,7 @@ s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content) return err; } - if (*content && !IS_CLUS_EOF(*content) && - (*content < CLUS_BASE || fsi->num_clusters <= *content)) { + if (!is_reserved_clus(*content) && !is_valid_clus(fsi, *content)) { sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x) " "bogus content (0x%08x)", loc, *content); 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) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + return fsi->fatent_ops->ent_set(sb, loc, content); } s32 fat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content) { s32 err = fat_ent_get(sb, loc, content); + if (err) return err; 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); return -EIO; } diff --git a/misc.c b/misc.c index 8cab489..566f99b 100644 --- a/misc.c +++ b/misc.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /* @@ -70,7 +68,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; 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); #ifdef CONFIG_SDFAT_SUPPORT_STLOG if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { @@ -82,11 +80,11 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) } if (opts->errors == SDFAT_ERRORS_PANIC) { - panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n", + panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); } else if (opts->errors == SDFAT_ERRORS_RO && !(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)); #ifdef CONFIG_SDFAT_SUPPORT_STLOG 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); /** - * __sdfat_msg() - print preformated FAT specific messages. - * Every thing what is not sdfat_fs_error() should be __sdfat_msg(). - * If 'st' is set to 1, it means that this message should be saved on ST_LOG. + * __sdfat_msg() - print preformated SDFAT specific messages. + * All logs except what uses sdfat_fs_error() should be written by __sdfat_msg() + * 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, ...) { @@ -111,11 +109,12 @@ void __sdfat_msg(struct super_block *sb, const char *level, int st, const char * va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; + /* level means KERN_ pacility level */ printk("%s[SDFAT](%s[%d:%d]): %pV\n", level, sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); #ifdef CONFIG_SDFAT_SUPPORT_STLOG if (st) { - ST_LOG("[SDFAT](%s[%d:%d]): %pV\n", + ST_LOG("[SDFAT](%s[%d:%d]): %pV\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); } #endif @@ -125,15 +124,16 @@ EXPORT_SYMBOL(__sdfat_msg); 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 ST_LOG("[SDFAT] Filesystem version %s\n", SDFAT_VERSION); #endif } EXPORT_SYMBOL(sdfat_log_version); -extern struct timezone sys_tz; - +/* externs sys_tz + * extern struct timezone sys_tz; + */ #define UNIX_SECS_1980 315532800L #if BITS_PER_LONG == 64 @@ -154,15 +154,15 @@ extern struct timezone sys_tz; do { \ /* 2100 isn't leap year */ \ if (unlikely(year > NO_LEAP_YEAR_2100)) \ - leap_year = ((year + 3) / 4) - 1; \ + leap_year = ((year + 3) / 4) - 1; \ else \ - leap_year = ((year + 3) / 4); \ - } while(0) + leap_year = ((year + 3) / 4); \ + } while (0) /* Linear day numbers of the respective 1sts in non-leap years. */ static time_t accum_days_in_year[] = { - /* Month : 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, + /* 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, }; /* 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 + 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; - if(!sbi->options.tz_utc) + if (!sbi->options.tz_utc) ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN; 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; DATE_TIME_T dt; + sdfat_time_unix2fat(sbi, &ts, &dt); 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->sec = dt.Second; - return(tp); + return tp; } 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++) chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; - return(chksum); + return chksum; } 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 /* 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; volatile uint32_t tmp_fat_chain[50]; 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; - if (clu.flags == 0x03) return; + if (clu.flags == 0x03) + return; while (num_clusters > 0) { /* FAT chain logging */ @@ -357,6 +360,7 @@ void __sdfat_dmsg(int level, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; + /* fmt already includes KERN_ pacility level */ printk("[%u] %pV", current->pid, &vaf); va_end(args); #else @@ -367,6 +371,7 @@ void __sdfat_dmsg(int level, const char *fmt, ...) return; va_start(args, fmt); + /* fmt already includes KERN_ pacility level */ vprintk(fmt, args); va_end(args); #endif diff --git a/mpage.c b/mpage.c index cfda066..8a0ce7f 100644 --- a/mpage.c +++ b/mpage.c @@ -26,9 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -64,7 +62,7 @@ #include /* for mark_page_accessed() */ #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) #include #endif @@ -80,30 +78,43 @@ static void __mpage_write_end_io(struct bio *bio, int err); /************************************************************************* * 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) { __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) { if (test_bit(BIO_UPTODATE, &bio->bi_flags)) err = 0; __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) { return BIO_MAX_PAGES; } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) */ /* EMPTY */ #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) { 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; } -#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) { - return bio->bi_sector; + return bio->bi_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) { - return bio->bi_size; + return bio->bi_size; } static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int 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 - * sdfat.c. - * Each function should be same perfectly +/* __check_dfr_on() and __dfr_writepage_end_io() functions + * are copied from sdfat.c + * Each function should be same perfectly */ 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); - if ( (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) && - fsapi_dfr_check_dfr_on(inode, start, end, 0, fname) ) + if ((atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) && + fsapi_dfr_check_dfr_on(inode, start, end, 0, fname)) return 1; #endif 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) { -#ifdef CONFIG_SDFAT_DFR +#ifdef CONFIG_SDFAT_DFR struct defrag_info *ino_dfr = &(SDFAT_I(page->mapping->host)->dfr_info); + if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) fsapi_dfr_writepage_endio(page); #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 gendisk *disk; @@ -180,7 +192,7 @@ static inline unsigned int __calc_size_to_align(struct super_block* sb) struct queue_limits *limit; unsigned int max_sectors; unsigned int aligned = 0; - + disk = bdev->bd_disk; if (!disk) goto out; @@ -203,8 +215,8 @@ struct mpage_data { struct bio *bio; sector_t last_block_in_bio; get_block_t *get_block; - unsigned use_writepage; - unsigned size_to_align; + unsigned int use_writepage; + unsigned int size_to_align; }; /* @@ -235,7 +247,7 @@ static void __mpage_write_end_io(struct bio *bio, int err) if (page->mapping) mapping_set_error(page->mapping, err); } - + __dfr_writepage_end_io(page); end_page_writeback(page); @@ -243,10 +255,10 @@ static void __mpage_write_end_io(struct bio *bio, int err) 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; - submit_bio(rw, bio); + __sdfat_submit_bio_write2(flags, bio); return NULL; } @@ -271,20 +283,20 @@ mpage_alloc(struct block_device *bdev, return bio; } -static int sdfat_mpage_writepage(struct page *page, +static int sdfat_mpage_writepage(struct page *page, struct writeback_control *wbc, void *data) { struct mpage_data *mpd = data; struct bio *bio = mpd->bio; struct address_space *mapping = page->mapping; struct inode *inode = page->mapping->host; - const unsigned blkbits = inode->i_blkbits; - const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; + const unsigned int blkbits = inode->i_blkbits; + const unsigned int blocks_per_page = PAGE_SIZE >> blkbits; sector_t last_block; sector_t block_in_file; sector_t blocks[MAX_BUF_PER_PAGE]; - unsigned page_block; - unsigned first_unmapped = blocks_per_page; + unsigned int page_block; + unsigned int first_unmapped = blocks_per_page; struct block_device *bdev = NULL; int boundary = 0; sector_t boundary_block = 0; @@ -292,7 +304,7 @@ static int sdfat_mpage_writepage(struct page *page, int length; struct buffer_head map_bh; 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; 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 */ if (buffer_delay(bh)) { - sector_t blk_in_file = (sector_t)(page->index << (PAGE_CACHE_SHIFT - blkbits)) + page_block; - BUG_ON(bh->b_size != (1 << blkbits)); + sector_t blk_in_file = + (sector_t)(page->index << (PAGE_SHIFT - blkbits)) + page_block; + BUG_ON(bh->b_size != (1 << blkbits)); if (page->index > end_index) { MMSG("%s(inode:%p) " "over end with delayed buffer" @@ -351,7 +364,7 @@ static int sdfat_mpage_writepage(struct page *page, unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); } } - + if (page_block) { if (bh->b_blocknr != blocks[page_block-1] + 1) { MMSG("%s(inode:%p) pblk(%d) " @@ -387,7 +400,7 @@ static int sdfat_mpage_writepage(struct page *page, * The page has no buffers: map it to disk */ 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; map_bh.b_page = page; for (page_block = 0; page_block < blocks_per_page; ) { @@ -396,7 +409,7 @@ static int sdfat_mpage_writepage(struct page *page, map_bh.b_size = 1 << blkbits; if (mpd->get_block(inode, block_in_file, &map_bh, 1)) goto confused; - + if (buffer_new(&map_bh)) unmap_underlying_metadata(map_bh.b_bdev, map_bh.b_blocknr); @@ -430,7 +443,7 @@ page_is_mapped: * is zeroed when mapped, and writes to that region are not * 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) { MMSG("%s(inode:%p) over end " @@ -439,7 +452,7 @@ page_is_mapped: (u32)end_index, (u32)offset); 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 (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) { - unsigned mask = mpd->size_to_align - 1; - sector_t max_end_block = + unsigned int mask = mpd->size_to_align - 1; + sector_t max_end_block = (__sdfat_bio_sector(bio) & ~(mask)) + mask; - if ( (__sdfat_bio_size(bio) != (1 << (mask + 1))) && - (mpd->last_block_in_bio == max_end_block) ) { + if ((__sdfat_bio_size(bio) != (1 << (mask + 1))) && + (mpd->last_block_in_bio == max_end_block)) { MMSG("%s(inode:%p) alignment mpage_bio_submit" "(start:%u, len:%u aligned:%u)\n", __func__, inode, - (unsigned)__sdfat_bio_sector(bio), - (unsigned)(mpd->last_block_in_bio - + (unsigned int)__sdfat_bio_sector(bio), + (unsigned int)(mpd->last_block_in_bio - __sdfat_bio_sector(bio) + 1), - (unsigned)mpd->size_to_align); - bio = mpage_bio_submit(WRITE | REQ_NOMERGE, bio); + (unsigned int)mpd->size_to_align); + bio = mpage_bio_submit_write(REQ_NOMERGE, bio); } } } @@ -484,7 +497,7 @@ alloc_new: */ length = first_unmapped << blkbits; 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; } @@ -495,7 +508,7 @@ alloc_new: if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; - unsigned buffer_counter = 0; + unsigned int buffer_counter = 0; do { if (buffer_counter++ == first_unmapped) @@ -516,28 +529,29 @@ alloc_new: BUG_ON(PageWriteback(page)); set_page_writeback(page); - /* + /* * FIXME FOR DEFRAGMENTATION : CODE REVIEW IS REQUIRED * * Turn off MAPPED flag in victim's bh if defrag on. - * Another write_begin can starts after get_block for defrag victims + * Another write_begin can starts after get_block for defrag victims * called. - * In this case, write_begin calls get_block and get original block + * In this case, write_begin calls get_block and get original block * number and previous defrag will be canceled. */ if (unlikely(__check_dfr_on(inode, (loff_t)(page->index << PAGE_SHIFT), (loff_t)((page->index + 1) << PAGE_SHIFT), __func__))) { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; + do { clear_buffer_mapped(bh); bh = bh->b_this_page; } while (bh != head); } - + unlock_page(page); if (boundary || (first_unmapped != blocks_per_page)) { - bio = mpage_bio_submit(WRITE, bio); + bio = mpage_bio_submit_write(0, bio); if (boundary_block) { write_boundary_block(boundary_bdev, boundary_block, 1 << blkbits); @@ -550,7 +564,7 @@ alloc_new: confused: if (bio) - bio = mpage_bio_submit(WRITE, bio); + bio = mpage_bio_submit_write(0, bio); if (mpd->use_writepage) { ret = mapping->a_ops->writepage(page, wbc); @@ -579,14 +593,12 @@ int sdfat_mpage_writepages(struct address_space *mapping, .use_writepage = 1, .size_to_align = __calc_size_to_align(mapping->host->i_sb), }; - - BUG_ON(!get_block); - - blk_start_plug(&plug); + BUG_ON(!get_block); + blk_start_plug(&plug); ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd); if (mpd.bio) - mpage_bio_submit(WRITE, mpd.bio); + mpage_bio_submit_write(0, mpd.bio); blk_finish_plug(&plug); return ret; } diff --git a/nls.c b/nls.c index 439fc02..b656344 100644 --- a/nls.c +++ b/nls.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -52,7 +50,7 @@ static u16 bad_dos_chars[] = { /* * Allow full-width illegal characters : * "MS windows 7" supports full-width-invalid-name-characters. - * So we should check half-width-invalid-name-characters(ASCII) only + * So we should check half-width-invalid-name-characters(ASCII) only * for compatibility. * * " * / : < > ? \ | @@ -62,10 +60,10 @@ static u16 bad_dos_chars[] = { static u16 bad_uni_chars[] = { 0x0022, 0x002A, 0x002F, 0x003A, 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, - /* +#if 0 /* allow full-width characters */ 0x201C, 0x201D, 0xFF0A, 0xFF0F, 0xFF1A, 0xFF1C, 0xFF1E, 0xFF1F, 0xFF3C, 0xFF5C, - */ +#endif 0 }; @@ -101,7 +99,7 @@ u16 *nls_wstrchr(u16 *str, u16 wchar) 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) @@ -109,10 +107,10 @@ s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b) s32 i; for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { - if (nls_upper(sb, *a) != nls_upper(sb, *b)) - return 1; - if (*a == 0x0) - return 0; + if (nls_upper(sb, *a) != nls_upper(sb, *b)) + return 1; + if (*a == 0x0) + 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; while (i < DOS_NAME_LENGTH) { if (i == 8) { - if (last_period == NULL) break; + if (last_period == NULL) + break; 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); if (len > 1) { - if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) { + if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) break; - } + if ((i < 8) && ((i+len) > 8)) { i = 8; continue; @@ -182,9 +181,8 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T lower = 0xFF; - for (j = 0; j < len; j++, i++) { + for (j = 0; j < len; j++, i++) *(dosname+i) = *(buf+j); - } } else { /* len == 1 */ if ((*buf >= 'a') && (*buf <= 'z')) { *(dosname+i) = *buf - ('a' - 'A'); @@ -208,18 +206,18 @@ s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T uniname++; } - if (*dosname == 0xE5) - *dosname = 0x05; - if (*uniname != 0x0) - lossy |= NLS_NAME_OVERLEN; + if (*dosname == 0xE5) + *dosname = 0x05; + if (*uniname != 0x0) + lossy |= NLS_NAME_OVERLEN; - if (upper & lower) - p_dosname->name_case = 0xFF; - else - p_dosname->name_case = lower; + if (upper & lower) + p_dosname->name_case = 0xFF; + else + p_dosname->name_case = lower; - if (p_lossy) - *p_lossy = lossy; + if (p_lossy) + *p_lossy = lossy; return i; } @@ -266,7 +264,7 @@ s32 nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T i = j = 0; while (j < MAX_NAME_LENGTH) { - if (*(buf+i) == '\0') + if (*(buf+i) == '\0') break; i += convert_ch_to_uni(nls, (buf+i), uniname, NULL); @@ -291,7 +289,8 @@ static s32 __nls_utf16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname 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; 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; } - if (unilen > MAX_NAME_LENGTH ) { + if (unilen > MAX_NAME_LENGTH) { MMSG("%s: failed to vfsname_to_utf16(estr:ENAMETOOLONG) " "vfsnamelen:%d, unilen:%d>%d", __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); - for (i=0; iname_len = unilen; p_uniname->name_hash = calc_chksum_2byte((void *) upname, unilen<<1, 0, CS_DEFAULT); - if (p_lossy) + if (p_lossy) *p_lossy = lossy; return unilen; @@ -435,16 +435,16 @@ static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy 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 */ - DMSG("%s: fail to use nls \n", __func__); + DMSG("%s: fail to use nls\n", __func__); if (lossy != NULL) *lossy |= NLS_NAME_LOSSY; *uni = (u16) '_'; - if (!strcmp(nls->charset, "utf8")) + if (!strcmp(nls->charset, "utf8")) return 1; - else - return 2; + return 2; } return len; @@ -461,9 +461,10 @@ static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy) 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 */ - DMSG("%s: fail to use nls \n", __func__); + DMSG("%s: fail to use nls\n", __func__); if (lossy != NULL) *lossy |= NLS_NAME_LOSSY; ch[0] = '_'; diff --git a/sdfat.c b/sdfat.c index 4cb1cff..49bc22f 100644 --- a/sdfat.c +++ b/sdfat.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -56,11 +54,11 @@ #include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) #include #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) #error SDFAT only supports linux kernel version 3.0 or higher #endif @@ -71,7 +69,7 @@ #define ITER_POS_FILLED_DOTS (2) /* type index declare at sdfat.h */ -const char* FS_TYPE_STR[] = { +const char *FS_TYPE_STR[] = { "auto", "exfat", "vfat" @@ -80,7 +78,6 @@ const char* FS_TYPE_STR[] = { static struct kset *sdfat_kset; static struct kmem_cache *sdfat_inode_cachep; - static int sdfat_default_codepage = CONFIG_SDFAT_DEFAULT_CODEPAGE; static char sdfat_default_iocharset[] = CONFIG_SDFAT_DEFAULT_IOCHARSET; static const char sdfat_iocharset_with_utf8[] = "iso8859-1"; @@ -104,9 +101,9 @@ static int sdfat_write_inode(struct inode *inode, struct writeback_control *wbc) static void sdfat_write_super(struct super_block *sb); static void sdfat_write_failed(struct address_space *mapping, loff_t to); -static void sdfat_init_namebuf(DENTRY_NAMEBUF_T* nb); -static int sdfat_alloc_namebuf(DENTRY_NAMEBUF_T* nb); -static void sdfat_free_namebuf(DENTRY_NAMEBUF_T* nb); +static void sdfat_init_namebuf(DENTRY_NAMEBUF_T *nb); +static int sdfat_alloc_namebuf(DENTRY_NAMEBUF_T *nb); +static void sdfat_free_namebuf(DENTRY_NAMEBUF_T *nb); /************************************************************************* * INNER FUNCTIONS FOR FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY @@ -118,62 +115,126 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry); static int __sdfat_revalidate(struct dentry *dentry); static int __sdfat_revalidate_ci(struct dentry *dentry, unsigned int flags); static int __sdfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync); -static struct dentry* __sdfat_lookup(struct inode *dir, struct dentry *dentry); +static struct dentry *__sdfat_lookup(struct inode *dir, struct dentry *dentry); static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry); +static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); static int __sdfat_show_options(struct seq_file *m, struct super_block *sb); static inline ssize_t __sdfat_blkdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, unsigned long nr_segs); static inline ssize_t __sdfat_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, - loff_t count); + loff_t count, unsigned long nr_segs); static int __sdfat_d_hash(const struct dentry *dentry, struct qstr *qstr); static int __sdfat_d_hashi(const struct dentry *dentry, struct qstr *qstr); -static int __sdfat_cmp(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name); -static int __sdfat_cmpi(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name); +static int __sdfat_cmp(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name); +static int __sdfat_cmpi(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name); /************************************************************************* * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +static int sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + /* + * The VFS already checks for existence, so for local filesystems + * the RENAME_NOREPLACE implementation is equivalent to plain rename. + * Don't support any other flags + */ + if (flags & ~RENAME_NOREPLACE) + return -EINVAL; + return __sdfat_rename(old_dir, old_dentry, new_dir, new_dentry); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */ +static int sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + return __sdfat_rename(old_dir, old_dentry, new_dir, new_dentry); +} + +static int setattr_prepare(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + + return inode_change_ok(inode, attr); +} +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) +static inline void __sdfat_submit_bio_write(struct bio *bio) +{ + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + submit_bio(bio); +} + +static inline unsigned int __sdfat_full_name_hash(const struct dentry *dentry, const char *name, unsigned int len) +{ + return full_name_hash(dentry, name, len); +} + +static inline unsigned long __sdfat_init_name_hash(const struct dentry *dentry) +{ + return init_name_hash(dentry); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */ +static inline void __sdfat_submit_bio_write(struct bio *bio) +{ + submit_bio(WRITE, bio); +} + +static inline unsigned int __sdfat_full_name_hash(const struct dentry *unused, const char *name, unsigned int len) +{ + return full_name_hash(name, len); +} + +static inline unsigned long __sdfat_init_name_hash(const struct dentry *unused) +{ + return init_name_hash(); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 21) + /* EMPTY */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 21) */ +static inline void inode_lock(struct inode *inode) +{ + mutex_lock(&inode->i_mutex); +} + +static inline void inode_unlock(struct inode *inode) +{ + mutex_unlock(&inode->i_mutex); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) static void sdfat_writepage_end_io(struct bio *bio) { __sdfat_writepage_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 sdfat_writepage_end_io(struct bio *bio, int err) { if (test_bit(BIO_UPTODATE, &bio->bi_flags)) err = 0; __sdfat_writepage_end_io(bio, err); } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) -static const char *sdfat_follow_link(struct dentry *dentry, void **cookie) -{ - return simple_follow_link(dentry, cookie); -} -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) */ -static void *sdfat_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); - nd_set_link(nd, (char *)(ei->target)); - return NULL; -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) */ - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static inline int sdfat_remount_syncfs(struct super_block *sb) { sync_filesystem(sb); return 0; } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) */ static inline int sdfat_remount_syncfs(struct super_block *sb) { /* @@ -182,25 +243,27 @@ static inline int sdfat_remount_syncfs(struct super_block *sb) */ return 0; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) */ +#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) { return bio->bi_iter.bi_sector; } -static inline void __sdfat_set_bio_iterate(struct bio *bio, sector_t sector, unsigned int size, unsigned int idx, unsigned int done) +static inline void __sdfat_set_bio_iterate(struct bio *bio, sector_t sector, + unsigned int size, unsigned int idx, unsigned int done) { - struct bvec_iter* iter = &(bio->bi_iter); + struct bvec_iter *iter = &(bio->bi_iter); + iter->bi_sector = sector; iter->bi_size = size; iter->bi_idx = idx; iter->bi_bvec_done = done; } -static void __sdfat_truncate_pagecache(struct inode *inode, +static void __sdfat_truncate_pagecache(struct inode *inode, loff_t to, loff_t newsize) { truncate_pagecache(inode, newsize); @@ -216,18 +279,6 @@ static int sdfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) return __sdfat_d_hashi(dentry, qstr); } -static int sdfat_cmp(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) -{ - return __sdfat_cmp(parent, dentry, len, str, name); -} - -static int sdfat_cmpi(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) -{ - return __sdfat_cmpi(parent, dentry, len, str, name); -} - //instead of sdfat_readdir static int sdfat_iterate(struct file *filp, struct dir_context *ctx) { @@ -294,8 +345,8 @@ get_new: } else { loff_t i_pos = ((loff_t) SDFAT_I(inode)->fid.start_clu << 32) | ((SDFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); - struct inode *tmp = sdfat_iget(sb, i_pos); + if (tmp) { inum = tmp->i_ino; iput(tmp); @@ -331,20 +382,21 @@ out_unlocked: sdfat_free_namebuf(nb); return err; } -#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) { return bio->bi_sector; } -static inline void __sdfat_set_bio_iterate(struct bio *bio, sector_t sector, unsigned int size, unsigned int idx, unsigned int done) +static inline void __sdfat_set_bio_iterate(struct bio *bio, sector_t sector, + unsigned int size, unsigned int idx, unsigned int done) { bio->bi_sector = sector; bio->bi_idx = idx; - bio->bi_size = size; //PAGE_CACHE_SIZE; + bio->bi_size = size; //PAGE_SIZE; } -static void __sdfat_truncate_pagecache(struct inode *inode, +static void __sdfat_truncate_pagecache(struct inode *inode, loff_t to, loff_t newsize) { truncate_pagecache(inode, to, newsize); @@ -362,20 +414,6 @@ static int sdfat_d_hashi(const struct dentry *dentry, return __sdfat_d_hashi(dentry, qstr); } -static int sdfat_cmp(const struct dentry *parent, const struct inode *pinode, - const struct dentry *dentry, const struct inode *inode, - unsigned int len, const char *str, const struct qstr *name) -{ - return __sdfat_cmp(parent, dentry, len, str, name); -} - -static int sdfat_cmpi(const struct dentry *parent, const struct inode *pinode, - const struct dentry *dentry, const struct inode *inode, - unsigned int len, const char *str, const struct qstr *name) -{ - return __sdfat_cmpi(parent, dentry, len, str, name); -} - static int sdfat_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *inode = filp->f_path.dentry->d_inode; @@ -453,8 +491,8 @@ get_new: } else { loff_t i_pos = ((loff_t) SDFAT_I(inode)->fid.start_clu << 32) | ((SDFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); - struct inode *tmp = sdfat_iget(sb, i_pos); + if (tmp) { inum = tmp->i_ino; iput(tmp); @@ -490,23 +528,23 @@ out_unlocked: sdfat_free_namebuf(nb); return err; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) */ +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) /* EMPTY */ -#else +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */ static inline struct inode *file_inode(const struct file *f) { return f->f_dentry->d_inode; } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) static inline int __is_sb_dirty(struct super_block *sb) { - return SDFAT_SB(sb)->s_dirt; + return SDFAT_SB(sb)->s_dirt; } static inline void __set_sb_clean(struct super_block *sb) @@ -542,9 +580,9 @@ static void __write_super_delayed(struct work_struct *work) static void setup_sdfat_sync_super_wq(struct super_block *sb) { - struct sdfat_sb_info* sbi = SDFAT_SB(sb); - mutex_init(&sbi->s_lock); + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + mutex_init(&sbi->s_lock); spin_lock_init(&sbi->work_lock); INIT_DELAYED_WORK(&sbi->write_super_work, __write_super_delayed); sbi->host_sb = sb; @@ -558,12 +596,14 @@ static inline bool __cancel_delayed_work_sync(struct sdfat_sb_info *sbi) static inline void lock_super(struct super_block *sb) { struct sdfat_sb_info *sbi = SDFAT_SB(sb); + mutex_lock(&sbi->s_lock); } static inline void unlock_super(struct super_block *sb) { struct sdfat_sb_info *sbi = SDFAT_SB(sb); + mutex_unlock(&sbi->s_lock); } @@ -583,7 +623,8 @@ static int sdfat_revalidate_ci(struct dentry *dentry, unsigned int flags) return __sdfat_revalidate_ci(dentry, flags); } -static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) { +static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) +{ struct sdfat_sb_info *sbi = SDFAT_SB(sb); struct sdfat_inode_info *info; struct hlist_head *head = sbi->inode_hashtable + sdfat_hash(i_pos); @@ -602,10 +643,10 @@ static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) { spin_unlock(&sbi->inode_hash_lock); return inode; } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) */ static inline int __is_sb_dirty(struct super_block *sb) { - return sb->s_dirt; + return sb->s_dirt; } static inline void __set_sb_clean(struct super_block *sb) @@ -615,7 +656,8 @@ static inline void __set_sb_clean(struct super_block *sb) static void setup_sdfat_sync_super_wq(struct super_block *sb) { - struct sdfat_sb_info* sbi = SDFAT_SB(sb); + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + sbi->host_sb = sb; } @@ -634,7 +676,7 @@ static int sdfat_revalidate(struct dentry *dentry, struct nameidata *nd) { if (nd && nd->flags & LOOKUP_RCU) return -ECHILD; - + return __sdfat_revalidate(dentry); } @@ -647,7 +689,8 @@ static int sdfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) } -static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) { +static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) +{ struct sdfat_sb_info *sbi = SDFAT_SB(sb); struct sdfat_inode_info *info; struct hlist_node *node; @@ -667,27 +710,27 @@ static struct inode *sdfat_iget(struct super_block *sb, loff_t i_pos) { spin_unlock(&sbi->inode_hash_lock); return inode; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) static struct dentry *sdfat_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { return __sdfat_lookup(dir, dentry); } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */ static struct dentry *sdfat_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { return __sdfat_lookup(dir, dentry); } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) /* NOTHING NOW */ -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */ #define GLOBAL_ROOT_UID (0) #define GLOBAL_ROOT_GID (0) @@ -720,21 +763,21 @@ static inline gid_t make_kgid(struct user_namespace *from, gid_t gid) { return gid; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) -static struct dentry* __d_make_root(struct inode *root_inode) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +static struct dentry *__d_make_root(struct inode *root_inode) { return d_make_root(root_inode); } static void __sdfat_do_truncate(struct inode *inode, loff_t old, loff_t new) { - down_write(&SDFAT_I(inode)->truncate_lock); - truncate_setsize(inode, new); - sdfat_truncate(inode, old); - up_write(&SDFAT_I(inode)->truncate_lock); + down_write(&SDFAT_I(inode)->truncate_lock); + truncate_setsize(inode, new); + sdfat_truncate(inode, old); + up_write(&SDFAT_I(inode)->truncate_lock); } static sector_t sdfat_aop_bmap(struct address_space *mapping, sector_t block) @@ -757,13 +800,13 @@ static int sdfat_show_options(struct seq_file *m, struct dentry *root) { return __sdfat_show_options(m, root->d_sb); } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ static inline void set_nlink(struct inode *inode, unsigned int nlink) { inode->i_nlink = nlink; } -static struct dentry* __d_make_root(struct inode *root_inode) +static struct dentry *__d_make_root(struct inode *root_inode) { return d_alloc_root(root_inode); } @@ -794,10 +837,10 @@ static int sdfat_show_options(struct seq_file *m, struct vfsmount *mnt) { return __sdfat_show_options(m, mnt->mnt_sb); } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) */ +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) #define __sdfat_generic_file_fsync(filp, start, end, datasync) \ generic_file_fsync(filp, start, end, datasync) @@ -805,17 +848,97 @@ static int sdfat_file_fsync(struct file *filp, loff_t start, loff_t end, int dat { return __sdfat_file_fsync(filp, start, end, datasync); } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ #define __sdfat_generic_file_fsync(filp, start, end, datasync) \ generic_file_fsync(filp, datasync) static int sdfat_file_fsync(struct file *filp, int datasync) { return __sdfat_file_fsync(filp, 0, 0, datasync); } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) */ +#endif + +/************************************************************************* + * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY + *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) +static int sdfat_cmp(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmp(dentry, len, str, name); +} + +static int sdfat_cmpi(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmpi(dentry, len, str, name); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) +static int sdfat_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmp(dentry, len, str, name); +} + +static int sdfat_cmpi(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmpi(dentry, len, str, name); +} +#else +static int sdfat_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmp(dentry, len, str, name); +} + +static int sdfat_cmpi(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +{ + return __sdfat_cmpi(dentry, len, str, name); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) +static const char *sdfat_follow_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + struct sdfat_inode_info *ei = SDFAT_I(inode); + + return (char *)(ei->target); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) +static const char *sdfat_follow_link(struct dentry *dentry, void **cookie) +{ + struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); + + return *cookie = (char *)(ei->target); +} +#else +static void *sdfat_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); + + nd_set_link(nd, (char *)(ei->target)); + return NULL; +} +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) +static ssize_t sdfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + size_t count = iov_iter_count(iter); + int rw = iov_iter_rw(iter); + loff_t offset = iocb->ki_pos; + + return __sdfat_direct_IO(rw, iocb, inode, + (void *)iter, offset, count, 0 /* UNUSED */); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) static ssize_t sdfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) @@ -826,9 +949,10 @@ static ssize_t sdfat_direct_IO(struct kiocb *iocb, size_t count = iov_iter_count(iter); int rw = iov_iter_rw(iter); - return __sdfat_direct_IO(rw, iocb, inode, (void*)iter, offset, count); + return __sdfat_direct_IO(rw, iocb, inode, + (void *)iter, offset, count, 0 /* UNUSED */); } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static ssize_t sdfat_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t offset) @@ -838,7 +962,8 @@ static ssize_t sdfat_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = mapping->host; size_t count = iov_iter_count(iter); - return __sdfat_direct_IO(rw, iocb, inode, (void*)iter, offset, count); + return __sdfat_direct_IO(rw, iocb, inode, + (void *)iter, offset, count, 0 /* UNUSED */); } #else static ssize_t sdfat_direct_IO(int rw, struct kiocb *iocb, @@ -849,35 +974,47 @@ static ssize_t sdfat_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = mapping->host; size_t count = iov_length(iov, nr_segs); - return __sdfat_direct_IO(rw, iocb, inode, (void*)iov, offset, count); + return __sdfat_direct_IO(rw, iocb, inode, + (void *)iov, offset, count, nr_segs); } #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) +static inline ssize_t __sdfat_blkdev_direct_IO(int unused, struct kiocb *iocb, + struct inode *inode, void *iov_u, loff_t unused_1, + unsigned long nr_segs) +{ + struct iov_iter *iter = (struct iov_iter *)iov_u; + + return blockdev_direct_IO(iocb, inode, iter, sdfat_get_block); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) static inline ssize_t __sdfat_blkdev_direct_IO(int unused, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, unsigned long nr_segs) { struct iov_iter *iter = (struct iov_iter *)iov_u; - return blockdev_direct_IO(iocb, inode, iter, - offset, sdfat_get_block); + + return blockdev_direct_IO(iocb, inode, iter, offset, sdfat_get_block); } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static inline ssize_t __sdfat_blkdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, unsigned long nr_segs) { struct iov_iter *iter = (struct iov_iter *)iov_u; - return blockdev_direct_IO(rw, iocb, inode, iter, + + return blockdev_direct_IO(rw, iocb, inode, iter, offset, sdfat_get_block); } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) static inline ssize_t __sdfat_blkdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, unsigned long nr_segs) { const struct iovec *iov = (const struct iovec *)iov_u; + return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, sdfat_get_block); } @@ -887,27 +1024,28 @@ static inline ssize_t __sdfat_blkdev_direct_IO(int rw, struct kiocb *iocb, unsigned long nr_segs) { const struct iovec *iov = (const struct iovec *)iov_u; - return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + + return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, sdfat_get_block, NULL); } #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,00) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) static int sdfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool excl) + bool excl) { return __sdfat_create(dir, dentry); } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) static int sdfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, - struct nameidata *nd) + struct nameidata *nd) { return __sdfat_create(dir, dentry); } #else static int sdfat_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) + struct nameidata *nd) { return __sdfat_create(dir, dentry); } @@ -929,7 +1067,7 @@ static inline void __unlock_super(struct super_block *sb) int time = ((jiffies - __lock_jiffies) * 1000 / HZ); /* FIXME : error message should be modified */ if (time > 10) - EMSG("lock_super in %s (%d ms) \n", __func__, time); + EMSG("lock_super in %s (%d ms)\n", __func__, time); unlock_super(sb); } @@ -956,7 +1094,7 @@ static inline loff_t sdfat_make_i_pos(FILE_ID_T *fid) /*======================================================================*/ /* Directory Entry Name Buffer Operations */ /*======================================================================*/ -static void sdfat_init_namebuf(DENTRY_NAMEBUF_T* nb) +static void sdfat_init_namebuf(DENTRY_NAMEBUF_T *nb) { nb->lfn = NULL; nb->sfn = NULL; @@ -964,7 +1102,7 @@ static void sdfat_init_namebuf(DENTRY_NAMEBUF_T* nb) nb->sfnbuf_len = 0; } -static int sdfat_alloc_namebuf(DENTRY_NAMEBUF_T* nb) +static int sdfat_alloc_namebuf(DENTRY_NAMEBUF_T *nb) { nb->lfn = __getname(); if (!nb->lfn) @@ -975,7 +1113,7 @@ static int sdfat_alloc_namebuf(DENTRY_NAMEBUF_T* nb) return 0; } -static void sdfat_free_namebuf(DENTRY_NAMEBUF_T* nb) +static void sdfat_free_namebuf(DENTRY_NAMEBUF_T *nb) { if (!nb->lfn) return; @@ -1024,6 +1162,7 @@ static inline int __check_dstate_locked(struct dentry *dentry) static int __sdfat_revalidate_common(struct dentry *dentry) { int ret = 1; + spin_lock(&dentry->d_lock); if ((!dentry->d_inode) && (!__check_dstate_locked(dentry) && (dentry->d_time != dentry->d_parent->d_inode->i_version))) { @@ -1095,7 +1234,9 @@ static unsigned int sdfat_striptail_len(const struct qstr *qstr) */ static int __sdfat_d_hash(const struct dentry *dentry, struct qstr *qstr) { - qstr->hash = full_name_hash(qstr->name, sdfat_striptail_len(qstr)); + unsigned int len = sdfat_striptail_len(qstr); + + qstr->hash = __sdfat_full_name_hash(dentry, qstr->name, len); return 0; } @@ -1115,7 +1256,7 @@ static int __sdfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) name = qstr->name; len = sdfat_striptail_len(qstr); - hash = init_name_hash(); + hash = __sdfat_init_name_hash(dentry); while (len--) hash = partial_name_hash(nls_tolower(t, *name++), hash); qstr->hash = end_name_hash(hash); @@ -1126,8 +1267,8 @@ static int __sdfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) /* * Case sensitive compare of two sdfat names. */ -static int __sdfat_cmp(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) +static int __sdfat_cmp(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) { unsigned int alen, blen; @@ -1144,10 +1285,10 @@ static int __sdfat_cmp(const struct dentry *parent, const struct dentry *dentry, /* * Case insensitive compare of two sdfat names. */ -static int __sdfat_cmpi(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) +static int __sdfat_cmpi(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) { - struct nls_table *t = SDFAT_SB(parent->d_sb)->nls_io; + struct nls_table *t = SDFAT_SB(dentry->d_sb)->nls_io; unsigned int alen, blen; /* A filename cannot end in '.' or we treat it like it has none */ @@ -1234,7 +1375,7 @@ static void defrag_cleanup_reqs(INOUT struct super_block *sb, IN int error) * @return 0 on success, -errno otherwise * @param inode inode * @param chunk given chunk - * @remark protected by i_mutex and super_lock + * @remark protected by inode_lock and super_lock */ static int defrag_validate_pages( @@ -1249,14 +1390,15 @@ defrag_validate_pages( i_size = i_size_read(inode); page_off = chunk->f_clus * PAGES_PER_CLUS(sb); - page_nr = (i_size / PAGE_SIZE) + ((i_size % PAGE_SIZE)? 1 : 0); - if ( (i_size <= 0) || (page_nr <= 0) ) { + page_nr = (i_size / PAGE_SIZE) + ((i_size % PAGE_SIZE) ? 1 : 0); + if ((i_size <= 0) || (page_nr <= 0)) { dfr_err("inode %p, i_size %d, page_nr %d", inode, i_size, page_nr); return -EINVAL; } /* Get victim pages - * and check its dirty/writeback/mapped state */ + * and check its dirty/writeback/mapped state + */ for (i = 0; i < min((int)(page_nr - page_off), (int)(chunk->nr_clus * PAGES_PER_CLUS(sb))); i++) { @@ -1274,16 +1416,19 @@ defrag_validate_pages( } sbi->dfr_pagep[buf_i++] = page; - if (PageError(page) || !PageUptodate(page) || PageDirty(page) || PageWriteback(page) || page_mapped(page)) { - dfr_debug("page %p, err %d, uptodate %d, dirty %d, wb %d, mapped %d", - page, PageError(page), PageUptodate(page), PageDirty(page), - PageWriteback(page), page_mapped(page)); + if (PageError(page) || !PageUptodate(page) || PageDirty(page) || + PageWriteback(page) || page_mapped(page)) { + dfr_debug("page %p, err %d, uptodate %d, " + "dirty %d, wb %d, mapped %d", + page, PageError(page), PageUptodate(page), + PageDirty(page), PageWriteback(page), + page_mapped(page)); err = -EINVAL; goto error; } - set_bit( (page->index & (PAGES_PER_CLUS(sb) - 1)), - (volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + i/PAGES_PER_CLUS(sb)]) ); + set_bit((page->index & (PAGES_PER_CLUS(sb) - 1)), + (volatile unsigned long *)&(sbi->dfr_page_wb[chunk->new_idx + i / PAGES_PER_CLUS(sb)])); page = NULL; } @@ -1291,9 +1436,8 @@ defrag_validate_pages( /** * All pages in the chunks are valid. */ - - i_size -= (chunk->f_clus * (sbi->fsi.cluster_size)); - BUG_ON( ((i_size/PAGE_SIZE) + ((i_size % PAGE_SIZE)? 1 : 0)) != (page_nr - page_off) ); + i_size -= (chunk->f_clus * (sbi->fsi.cluster_size)); + BUG_ON(((i_size / PAGE_SIZE) + ((i_size % PAGE_SIZE) ? 1 : 0)) != (page_nr - page_off)); for (i = 0; i < buf_i; i++) { struct buffer_head *bh = NULL, *head = NULL; @@ -1314,7 +1458,7 @@ defrag_validate_pages( bh = head = page_buffers(page); BUG_ON(!bh && !i_size); do { - if ( (bh_idx >= 1) && (bh_idx >= (i_size >> inode->i_blkbits)) ) { + if ((bh_idx >= 1) && (bh_idx >= (i_size >> inode->i_blkbits))) { clear_buffer_dirty(bh); } else { if (PageUptodate(page)) @@ -1392,14 +1536,14 @@ defrag_validate_reqs( i, inode, chunk->i_pos, chunk->f_clus, chunk->d_clus, chunk->nr_clus, chunk->prev_clus, chunk->next_clus); /** - * Lock ordering: i_mutex -> lock_super + * Lock ordering: inode_lock -> lock_super */ - mutex_lock(&inode->i_mutex); + inode_lock(inode); __lock_super(sb); /* Check if enough buffers exist for chunk->new_idx */ - if ( (sbi->dfr_new_idx + chunk->nr_clus) >= (PAGE_SIZE/sizeof(int)) ) { - dfr_err("dfr_new_idx %d, chunk->nr_clus %d", + if ((sbi->dfr_new_idx + chunk->nr_clus) >= (PAGE_SIZE / sizeof(int))) { + dfr_err("dfr_new_idx %d, chunk->nr_clus %d", sbi->dfr_new_idx, chunk->nr_clus); err = -ENOSPC; goto unlock; @@ -1460,7 +1604,7 @@ unlock: } iput(inode); __unlock_super(sb); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); } /* Return error if all chunks are invalid */ @@ -1547,8 +1691,9 @@ sdfat_ioctl_defrag_req( ERR_HANDLE(err); /* If FS busy, cancel defrag */ - if ( !(head.mode == DFR_MODE_TEST) ) { + if (!(head.mode == DFR_MODE_TEST)) { int reserved_clus = 0, queued_pages = 0; + err = defrag_check_fs_busy(sb, &reserved_clus, &queued_pages); if (err) { dfr_debug("FS busy, cancel defrag (reserved_clus %d, queued_pages %d)", @@ -1563,8 +1708,8 @@ sdfat_ioctl_defrag_req( ERR_HANDLE2(!len, err, -EINVAL); dfr_debug("IOC_DFR_REQ started (mode %d, nr_req %d)", head.mode, len - 1); - if ( get_order(len * sizeof(struct defrag_chunk_info)) > MAX_ORDER) { - dfr_debug("len %d, sizeof(struct defrag_chunk_info) %d, MAX_ORDER %d", + if (get_order(len * sizeof(struct defrag_chunk_info)) > MAX_ORDER) { + dfr_debug("len %u, sizeof(struct defrag_chunk_info) %lu, MAX_ORDER %d", len, sizeof(struct defrag_chunk_info), MAX_ORDER); err = -EINVAL; goto error; @@ -1702,7 +1847,7 @@ sdfat_ioctl_defrag_trav( * Check args. * ROOT directory has i_pos = 0 and start_clus = 0 . */ - if ( !(header->type & DFR_TRAV_TYPE_HEADER) ) { + if (!(header->type & DFR_TRAV_TYPE_HEADER)) { err = -EINVAL; dfr_debug("type %d, i_pos %08llx, start_clus %08x", header->type, header->i_pos, header->start_clus); @@ -1710,7 +1855,7 @@ sdfat_ioctl_defrag_trav( } /* If FS busy, cancel defrag */ - if ( !(header->type & DFR_TRAV_TYPE_TEST) ) { + if (!(header->type & DFR_TRAV_TYPE_TEST)) { unsigned int reserved_clus = 0, queued_pages = 0; err = defrag_check_fs_busy(sb, &reserved_clus, &queued_pages); @@ -1723,11 +1868,11 @@ sdfat_ioctl_defrag_trav( } /* Scan given directory and gather info */ - mutex_lock(&inode->i_mutex); + inode_lock(inode); __lock_super(sb); err = fsapi_dfr_scan_dir(sb, (void *)args); __unlock_super(sb); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); ERR_HANDLE(err); /* Copy the result to user */ @@ -1772,7 +1917,7 @@ error: #endif /* CONFIG_SDFAT_DFR */ -static inline int __do_dfr_map_cluster(struct inode *inode, u32 clu_offset, unsigned int* clus_ptr) +static inline int __do_dfr_map_cluster(struct inode *inode, u32 clu_offset, unsigned int *clus_ptr) { #ifdef CONFIG_SDFAT_DFR return fsapi_dfr_map_clus(inode, clu_offset, clus_ptr); @@ -1786,8 +1931,8 @@ static inline int __check_dfr_on(struct inode *inode, loff_t start, loff_t end, #ifdef CONFIG_SDFAT_DFR struct defrag_info *ino_dfr = &(SDFAT_I(inode)->dfr_info); - if ( (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) && - fsapi_dfr_check_dfr_on(inode, start, end, 0, fname) ) + if ((atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) && + fsapi_dfr_check_dfr_on(inode, start, end, 0, fname)) return 1; #endif return 0; @@ -1808,6 +1953,7 @@ static inline int __dfr_writepage_end_io(struct page *page) { #ifdef CONFIG_SDFAT_DFR struct defrag_info *ino_dfr = &(SDFAT_I(page->mapping->host)->dfr_info); + if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) fsapi_dfr_writepage_endio(page); #endif @@ -1848,7 +1994,7 @@ static inline int __alloc_dfr_mem_if_required(struct super_block *sb) return -ENOMEM; } - sbi->dfr_pagep = alloc_pages_exact( sizeof(struct page *) * + sbi->dfr_pagep = alloc_pages_exact(sizeof(struct page *) * PAGES_PER_AU(sb), GFP_KERNEL | __GFP_ZERO); if (!sbi->dfr_pagep) { dfr_debug("error %d", -ENOMEM); @@ -1867,25 +2013,24 @@ static void __free_dfr_mem_if_required(struct super_block *sb) free_pages_exact(sbi->dfr_pagep, sizeof(struct page *) * PAGES_PER_AU(sb)); sbi->dfr_pagep = NULL; } - if (sbi->dfr_page_wb) { - kfree(sbi->dfr_page_wb); - sbi->dfr_page_wb = NULL; - } - if (sbi->dfr_new_clus) { - kfree(sbi->dfr_new_clus); - sbi->dfr_new_clus = NULL; - } + + /* thanks for kfree */ + kfree(sbi->dfr_page_wb); + sbi->dfr_page_wb = NULL; + + kfree(sbi->dfr_new_clus); + sbi->dfr_new_clus = NULL; #endif } -static int sdfat_file_mmap( struct file *file, struct vm_area_struct *vm_struct) +static int sdfat_file_mmap(struct file *file, struct vm_area_struct *vm_struct) { __cancel_dfr_work(file->f_mapping->host, (loff_t)vm_struct->vm_start, (loff_t)(vm_struct->vm_end - 1), __func__); - + return generic_file_mmap(file, vm_struct); } @@ -1917,7 +2062,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, } /* Check if SB's defrag option enabled */ - if ( !(SDFAT_SB(sb)->options.defrag) ) { + if (!(SDFAT_SB(sb)->options.defrag)) { dfr_err("Defrag not supported, sbi->options.defrag %d", SDFAT_SB(sb)->options.defrag); __unlock_super(sb); return -EPERM; @@ -1949,7 +2094,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, } /* Check if SB's defrag option enabled */ - if ( !(SDFAT_SB(sb)->options.defrag) ) { + if (!(SDFAT_SB(sb)->options.defrag)) { dfr_err("Defrag not supported, sbi->options.defrag %d", SDFAT_SB(sb)->options.defrag); __unlock_super(sb); return -EPERM; @@ -1965,7 +2110,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, __lock_super(sb); - /* Check if FS_ERROR occured */ + /* Check if FS_ERROR occurred */ if (sb->s_flags & MS_RDONLY) { dfr_err("RDONLY partition (err %d)", -EPERM); __unlock_super(sb); @@ -1981,7 +2126,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, } /* Check if SB's defrag option enabled */ - if ( !(SDFAT_SB(sb)->options.defrag) ) { + if (!(SDFAT_SB(sb)->options.defrag)) { dfr_err("Defrag not supported, sbi->options.defrag %d", SDFAT_SB(sb)->options.defrag); __unlock_super(sb); return -EPERM; @@ -2041,10 +2186,10 @@ static int sdfat_dbg_ioctl(struct inode *inode, struct file *filp, __unlock_super(sb); return 0; case SDFAT_IOCTL_PANIC: - panic("ioctl panic for test"); + panic("ioctl panic for test"); /* COULD NOT REACH HEAR */ - return 0; + return 0; } #endif /* CONFIG_SDFAT_DBG_IOCTL */ return -ENOTTY; @@ -2073,9 +2218,9 @@ static void __sdfat_writepage_end_io(struct bio *bio, int err) struct super_block *sb = page->mapping->host->i_sb; ASSERT(bio->bi_vcnt == 1); /* Single page endio */ - ASSERT(bio->bi_rw & 1); /* Write */ + ASSERT(bio_data_dir(bio)); /* Write */ - if (err){ + if (err) { SetPageError(page); mapping_set_error(page->mapping, err); } @@ -2092,8 +2237,9 @@ static void __sdfat_writepage_end_io(struct bio *bio, int err) sbi->stat_n_bdev_pages_written++; /* 4 MB = 1024 pages => 0.4 sec (approx.) - 32 KB = 64 pages => 0.025 sec - Min. average latency b/w msgs. ~= 0.025 sec */ + * 32 KB = 64 pages => 0.025 sec + * Min. average latency b/w msgs. ~= 0.025 sec + */ if ((sbi->stat_n_pages_written & 63) == 0) { DMSG("STAT:%u, %u, %u, %u (Sector #: %u)\n", sbi->stat_n_pages_added, sbi->stat_n_pages_written, @@ -2110,11 +2256,13 @@ static void __sdfat_writepage_end_io(struct bio *bio, int err) atomic_dec(&SDFAT_SB(sb)->stat_n_pages_queued); } + static int __support_write_inode_sync(struct super_block *sb) { #ifdef CONFIG_SDFAT_SUPPORT_DIR_SYNC #ifdef CONFIG_SDFAT_DELAYED_META_DIRTY struct sdfat_sb_info *sbi = SDFAT_SB(sb); + if (sbi->fsi.vol_type != EXFAT) return 0; #endif @@ -2132,7 +2280,7 @@ static int __sdfat_file_fsync(struct file *filp, loff_t start, loff_t end, int d res = __sdfat_generic_file_fsync(filp, start, end, datasync); - if(!__support_write_inode_sync(sb)) + if (!__support_write_inode_sync(sb)) err = fsapi_sync_fs(sb, 1); return res ? res : err; @@ -2142,9 +2290,9 @@ static int __sdfat_file_fsync(struct file *filp, loff_t start, loff_t end, int d static const struct file_operations sdfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,00) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) .iterate = sdfat_iterate, -#else +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ .readdir = sdfat_readdir, #endif .fsync = sdfat_file_fsync, @@ -2194,6 +2342,8 @@ out: __unlock_d_revalidate(dentry); __unlock_super(sb); TMSG("%s exited with err(%d)\n", __func__, err); + if (!err) + sdfat_statistics_set_create(fid.flags); return err; } @@ -2217,7 +2367,7 @@ static int sdfat_d_anon_disconn(struct dentry *dentry) return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); } -static struct dentry* __sdfat_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *__sdfat_lookup(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -2247,7 +2397,7 @@ static struct dentry* __sdfat_lookup(struct inode *dir, struct dentry *dentry) } i_mode = inode->i_mode; - if (S_ISLNK(i_mode)) { + if (S_ISLNK(i_mode) && !SDFAT_I(inode)->target) { SDFAT_I(inode)->target = kmalloc((i_size_read(inode)+1), GFP_KERNEL); if (!SDFAT_I(inode)->target) { err = -ENOMEM; @@ -2292,9 +2442,8 @@ static struct dentry* __sdfat_lookup(struct inode *dir, struct dentry *dentry) __unlock_super(sb); TMSG("%s exited\n", __func__); return alias; - } else { - dput(alias); } + dput(alias); out: /* initialize d_time even though it is positive dentry */ dentry->d_time = dir->i_version; @@ -2365,7 +2514,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t /* symlink option check */ if (!SDFAT_SB(sb)->options.symlink) - return -ENOTSUPP; + return -ENOTSUPP; __lock_super(sb); @@ -2464,6 +2613,8 @@ out: __unlock_d_revalidate(dentry); __unlock_super(sb); TMSG("%s exited with err(%d)\n", __func__, err); + if (!err) + sdfat_statistics_set_mkdir(fid.flags); return err; } @@ -2508,8 +2659,8 @@ out: return err; } -static int sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) +static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode, *new_inode; struct super_block *sb = old_dir->i_sb; @@ -2554,7 +2705,8 @@ static int sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { drop_nlink(old_dir); - if (!new_inode) inc_nlink(new_dir); + if (!new_inode) + inc_nlink(new_dir); } old_dir->i_version++; @@ -2606,7 +2758,7 @@ static int sdfat_cont_expand(struct inode *inode, loff_t size) if (!IS_SYNC(inode)) return 0; - + err = filemap_fdatawrite_range(mapping, start, start + count - 1); err2 = sync_mapping_buffers(mapping); err = (err)?(err):(err2); @@ -2648,7 +2800,7 @@ static int sdfat_sanitize_mode(const struct sdfat_sb_info *sbi, perm = *mode_ptr & ~(S_IFMT | mask); /* Of the r and x bits, all (subject to umask) must be present.*/ - if ((perm & (S_IRUGO | S_IXUGO)) != (i_mode & (S_IRUGO|S_IXUGO))) + if ((perm & (S_IRUGO | S_IXUGO)) != (i_mode & (S_IRUGO | S_IXUGO))) return -EPERM; if (sdfat_mode_can_hold_ro(inode)) { @@ -2685,18 +2837,17 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~ATTR_SIZE; } + /* Check for setting the inode time. */ ia_valid = attr->ia_valid; - if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && sdfat_allow_set_time(sbi, inode)) { attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET); } - error = inode_change_ok(inode, attr); + error = setattr_prepare(dentry, attr); attr->ia_valid = ia_valid; - if (error) { + if (error) return error; - } if (((attr->ia_valid & ATTR_UID) && (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || @@ -2723,7 +2874,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr) old_size = i_size_read(inode); /* TO CHECK evicting directory works correctly */ - MMSG("%s: inode(%p) truncate size (%llu->%llu)\n", __func__, + MMSG("%s: inode(%p) truncate size (%llu->%llu)\n", __func__, inode, (u64)old_size, (u64)attr->ia_size); __sdfat_do_truncate(inode, old_size, attr->ia_size); } @@ -2759,11 +2910,13 @@ static const struct inode_operations sdfat_dir_inode_operations = { .setattr = sdfat_setattr, .getattr = sdfat_getattr, #ifdef CONFIG_SDFAT_VIRTUAL_XATTR + .listxattr = sdfat_listxattr, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) .setxattr = sdfat_setxattr, .getxattr = sdfat_getxattr, - .listxattr = sdfat_listxattr, .removexattr = sdfat_removexattr, #endif +#endif }; /*======================================================================*/ @@ -2771,13 +2924,19 @@ static const struct inode_operations sdfat_dir_inode_operations = { /*======================================================================*/ static const struct inode_operations sdfat_symlink_inode_operations = { .readlink = generic_readlink, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) + .get_link = sdfat_follow_link, +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) */ .follow_link = sdfat_follow_link, +#endif #ifdef CONFIG_SDFAT_VIRTUAL_XATTR + .listxattr = sdfat_listxattr, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) .setxattr = sdfat_setxattr, .getxattr = sdfat_getxattr, - .listxattr = sdfat_listxattr, .removexattr = sdfat_removexattr, #endif +#endif }; static int sdfat_file_release(struct inode *inode, struct file *filp) @@ -2796,15 +2955,15 @@ static int sdfat_file_release(struct inode *inode, struct file *filp) static const struct file_operations sdfat_file_operations = { .llseek = generic_file_llseek, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) .read = new_sync_read, .write = new_sync_write, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, -#else +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) */ .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, @@ -2831,13 +2990,10 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size) __lock_super(sb); - if (SDFAT_I(inode)->fid.start_clu == 0) { - /* - ?! Stange statement - Empty start_clu != ~0 (not allocated) - */ - /* FIXME:fata error? */ + /* Stange statement: + * Empty start_clu != ~0 (not allocated) + */ sdfat_fs_error(sb, "tried to truncate zeroed cluster."); goto out; } @@ -2855,18 +3011,17 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size) (void) sdfat_sync_inode(inode); else mark_inode_dirty(inode); - + // FIXME: 확인 요망 // inode->i_blocks = ((SDFAT_I(inode)->i_size_ondisk + (fsi->cluster_size - 1)) - inode->i_blocks = ( (i_size_read(inode) + (fsi->cluster_size - 1)) - & ~((loff_t)fsi->cluster_size - 1) ) >> inode->i_blkbits; - + inode->i_blocks = ((i_size_read(inode) + (fsi->cluster_size - 1)) & + ~((loff_t)fsi->cluster_size - 1)) >> inode->i_blkbits; out: - /* + /* * This protects against truncating a file bigger than it was then * trying to write into the hole. * - * comment by sh.hong: + * comment by sh.hong: * This seems to mean 'intra page/block' truncate and writing. * I couldn't find a reason to change the values prior to fsapi_truncate * Therefore, I switched the order of operations @@ -2879,9 +3034,9 @@ out: aligned_size++; } - if (SDFAT_I(inode)->i_size_ondisk > i_size_read(inode)) { + if (SDFAT_I(inode)->i_size_ondisk > i_size_read(inode)) SDFAT_I(inode)->i_size_ondisk = aligned_size; - } + sdfat_debug_check_clusters(inode); if (SDFAT_I(inode)->i_size_aligned > i_size_read(inode)) @@ -2889,11 +3044,11 @@ out: /* After truncation : * 1) Delayed allocation is OFF - * i_size = i_size_ondisk <= i_size_aligned + * i_size = i_size_ondisk <= i_size_aligned * (useless size var.) * (block-aligned) * 2) Delayed allocation is ON - * i_size = i_size_ondisk = i_size_aligned + * i_size = i_size_ondisk = i_size_aligned * (will be block-aligned after write) * or * i_size_ondisk < i_size <= i_size_aligned (block_aligned) @@ -2907,11 +3062,13 @@ static const struct inode_operations sdfat_file_inode_operations = { .setattr = sdfat_setattr, .getattr = sdfat_getattr, #ifdef CONFIG_SDFAT_VIRTUAL_XATTR + .listxattr = sdfat_listxattr, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) .setxattr = sdfat_setxattr, .getxattr = sdfat_getxattr, - .listxattr = sdfat_listxattr, .removexattr = sdfat_removexattr, #endif +#endif }; /*======================================================================*/ @@ -2938,19 +3095,19 @@ static int sdfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, *mapped_blocks = 0; /* core code should handle EIO */ - /* - if(fsi->prev_eio && BLOCK_ADDED(*create)) +#if 0 + if (fsi->prev_eio && BLOCK_ADDED(*create)) return -EIO; - */ +#endif - if ( ((fsi->vol_type == FAT12) || (fsi->vol_type == FAT16)) && - (inode->i_ino == SDFAT_ROOT_INO) ) { - if (sector < (fsi->dentries_in_root >> - (sb->s_blocksize_bits-DENTRY_SIZE_BITS)) ) { + if (((fsi->vol_type == FAT12) || (fsi->vol_type == FAT16)) && + (inode->i_ino == SDFAT_ROOT_INO)) { + if (sector < (fsi->dentries_in_root >> + (sb->s_blocksize_bits-DENTRY_SIZE_BITS))) { *phys = sector + fsi->root_start_sector; *mapped_blocks = 1; } - return 0; + return 0; } last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; @@ -2963,10 +3120,10 @@ static int sdfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, SDFAT_I(inode)->fid.size = i_size_read(inode); - if ( unlikely(__check_dfr_on(inode, - (loff_t)((loff_t)clu_offset << fsi->cluster_size_bits), + if (unlikely(__check_dfr_on(inode, + (loff_t)((loff_t)clu_offset << fsi->cluster_size_bits), (loff_t)((loff_t)(clu_offset + 1) << fsi->cluster_size_bits), - __func__)) ) { + __func__))) { err = __do_dfr_map_cluster(inode, clu_offset, &cluster); } else { if (*create & BMAP_ADD_CLUSTER) @@ -2981,9 +3138,13 @@ static int sdfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, return err; } + /* FOR BIGDATA */ + sdfat_statistics_set_rw(SDFAT_I(inode)->fid.flags, + clu_offset, *create & BMAP_ADD_CLUSTER); + if (!IS_CLUS_EOF(cluster)) { /* sector offset in cluster */ - sec_offset = sector & (fsi->sect_per_clus - 1); + sec_offset = sector & (fsi->sect_per_clus - 1); *phys = CLUS_TO_SECT(fsi, cluster) + sec_offset; *mapped_blocks = fsi->sect_per_clus - sec_offset; @@ -2998,25 +3159,22 @@ static int sdfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, if (sector < last_block) *create = BMAP_NOT_CREATE; - /* +#if 0 else if (sector >= last_block) *create = non-zero; - */ - /* if (iblock <= last mapped-block) *phys != 0 *create = BMAP_NOT_CREATE else if (iblock <= last cluster) *phys != 0 *create = non-zero - */ - +#endif return 0; } static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) + struct buffer_head *bh_result, int create) { struct super_block *sb = inode->i_sb; struct sdfat_sb_info *sbi = SDFAT_SB(sb); @@ -3038,7 +3196,7 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, if (err) { if (err != -ENOSPC) sdfat_fs_error_ratelimit(sb, "%s: failed to bmap " - "(iblock:%u, err:%d)", __func__, + "(iblock:%u, err:%d)", __func__, (u32)iblock, err); goto unlock_ret; } @@ -3050,7 +3208,7 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, max_blocks = min(mapped_blocks, max_blocks); map_bh(bh_result, sb, phys); - BUG_ON(BLOCK_ADDED(bmap_create) && (sec_offset == 0)); + BUG_ON(BLOCK_ADDED(bmap_create) && (sec_offset == 0)); } else if (create == 1) { /* Not exist: new cluster needed */ @@ -3061,9 +3219,9 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, err = fsapi_reserve_clus(inode); if (err) { if (err != -ENOSPC) - sdfat_fs_error_ratelimit(sb, + sdfat_fs_error_ratelimit(sb, "%s: failed to bmap " - "(iblock:%u, err:%d)", __func__, + "(iblock:%u, err:%d)", __func__, (u32)iblock, err); goto unlock_ret; @@ -3078,11 +3236,11 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, } else { /* get_block on non-existing addr. with create==0 */ /* - * CHECKME: - * i_size_aligned 보다 작으면 delay 매핑을 일단 + * CHECKME: + * i_size_aligned 보다 작으면 delay 매핑을 일단 * 켜줘야되는 게 아닌가? * - 0-fill 을 항상 하기에, FAT 에서는 문제 없음. - * 중간에 영역이 꽉 찼으면, 디스크에 내려가지 않고는 + * 중간에 영역이 꽉 찼으면, 디스크에 내려가지 않고는 * invalidate 될 일이 없음 */ goto unlock_ret; @@ -3099,18 +3257,17 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, #define num_clusters(value) ((value) ? (s32)((value - 1) >> fsi->cluster_size_bits) + 1 : 0) /* FOR GRACEFUL ERROR HANDLING */ - if (num_clusters(SDFAT_I(inode)->i_size_aligned) != + if (num_clusters(SDFAT_I(inode)->i_size_aligned) != num_clusters(SDFAT_I(inode)->i_size_ondisk)) { EMSG("%s: inode(%p) invalid size (create(%d) " "bmap_create(%d) phys(%lld) aligned(%lld) " - "on_disk(%lld) iblock(%u) sec_off(%d))\n", + "on_disk(%lld) iblock(%u) sec_off(%d))\n", __func__, inode, create, bmap_create, (s64)phys, (s64)SDFAT_I(inode)->i_size_aligned, (s64)SDFAT_I(inode)->i_size_ondisk, (u32)iblock, (s32)sec_offset); sdfat_debug_bug_on(1); - } SDFAT_I(inode)->i_size_ondisk = SDFAT_I(inode)->i_size_aligned; } @@ -3132,7 +3289,7 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, /* FOR GRACEFUL ERROR HANDLING */ if (i_size_read(inode) > SDFAT_I(inode)->i_size_aligned) { sdfat_fs_error_ratelimit(sb, "%s: invalid size (inode(%p), " - "size(%llu) > aligned(%llu)\n", __func__, inode, + "size(%llu) > aligned(%llu)\n", __func__, inode, i_size_read(inode), SDFAT_I(inode)->i_size_aligned); sdfat_debug_bug_on(1); } @@ -3189,38 +3346,36 @@ static int sdfat_get_block(struct inode *inode, sector_t iblock, * create == 1 only if iblock > i_size * (in block unit) */ - + /* 20130723 CHECK * Truncate와 동시에 발생할 경우, * i_size < (i_block 위치) 면서 buffer_delay()가 * 켜져있을 수 있다. * * 기존에 할당된 영역을 다시 쓸 뿐이므로 큰 문제 - * 없지만, 그 경우, 미리 i_size_algined 가 확장된 + * 없지만, 그 경우, 미리 i_size_aligned 가 확장된 * 영역이어야 한다. */ - /* FOR GRACEFUL ERROR HANDLING : - * - * sdfat_debug_bug_on(buffer_delay(bh_result) && (pos > SDFAT_I(inode)->i_size_aligned)); - */ - if (buffer_delay(bh_result) && + /* FOR GRACEFUL ERROR HANDLING */ + if (buffer_delay(bh_result) && (pos > SDFAT_I(inode)->i_size_aligned)) { - sdfat_fs_error(sb, "requested for bmap out of range(pos:(%llu)>i_size_aligned(%llu)\n", pos, SDFAT_I(inode)->i_size_aligned); + sdfat_fs_error(sb, "requested for bmap " + "out of range(pos:(%llu)>i_size_aligned(%llu)\n", + pos, SDFAT_I(inode)->i_size_aligned); sdfat_debug_bug_on(1); err = -EIO; goto unlock_ret; } - set_buffer_new(bh_result); - - /* i_size_ondisk 이 i_size_aligned 보다 먼저 - * 움직인 경우, (예: non-DA 상황) - * 두 변수 사이의 관계 유지 + + /* + * adjust i_size_aligned if i_size_ondisk is + * bigger than it. (i.e. non-DA) */ - if (SDFAT_I(inode)->i_size_ondisk > - SDFAT_I(inode)->i_size_aligned) { - SDFAT_I(inode)->i_size_aligned = + if (SDFAT_I(inode)->i_size_ondisk > + SDFAT_I(inode)->i_size_aligned) { + SDFAT_I(inode)->i_size_aligned = SDFAT_I(inode)->i_size_ondisk; } } @@ -3230,18 +3385,18 @@ static int sdfat_get_block(struct inode *inode, sector_t iblock, #if 0 /* Debug purpose */ - if (SDFAT_I(inode)->i_size_ondisk > - SDFAT_I(inode)->i_size_aligned ) { + if (SDFAT_I(inode)->i_size_ondisk > + SDFAT_I(inode)->i_size_aligned) { /* Only after truncate - * and the two size variables should indicate - * same i_block + * and the two size variables should indicate + * same i_block */ unsigned int blocksize = 1 << inode->i_blkbits; - BUG_ON(SDFAT_I(inode)->i_size_ondisk - SDFAT_I(inode)->i_size_aligned >= blocksize); + BUG_ON(SDFAT_I(inode)->i_size_ondisk - + SDFAT_I(inode)->i_size_aligned >= blocksize); } #endif } - map_bh(bh_result, sb, phys); } @@ -3254,24 +3409,27 @@ unlock_ret: static int sdfat_readpage(struct file *file, struct page *page) { int ret; + ret = mpage_readpage(page, sdfat_get_block); return ret; } static int sdfat_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) + struct list_head *pages, unsigned int nr_pages) { int ret; + ret = mpage_readpages(mapping, pages, nr_pages, sdfat_get_block); return ret; } -static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, sector_t sector, unsigned int length, struct page *page) +static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, + sector_t sector, unsigned int length, struct page *page) { /* Single page bio submit */ struct bio *bio; - BUG_ON((length > PAGE_CACHE_SIZE) || (length == 0)); + BUG_ON((length > PAGE_SIZE) || (length == 0)); /* * If __GFP_WAIT is set, then bio_alloc will always be able to allocate @@ -3279,18 +3437,18 @@ static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, sector_t * must never allocate more than 1 bio at a time from this pool. * * #define GFP_NOIO (__GFP_WAIT) - */ + */ bio = bio_alloc(GFP_NOIO, 1); bio->bi_bdev = bdev; bio->bi_vcnt = 1; - bio->bi_io_vec[0].bv_page = page; /* Inline vec */ - bio->bi_io_vec[0].bv_len = length; //PAGE_CACHE_SIZE; + bio->bi_io_vec[0].bv_page = page; /* Inline vec */ + bio->bi_io_vec[0].bv_len = length; /* PAGE_SIZE */ bio->bi_io_vec[0].bv_offset = 0; __sdfat_set_bio_iterate(bio, sector, length, 0, 0); bio->bi_end_io = sdfat_writepage_end_io; - submit_bio(WRITE, bio); + __sdfat_submit_bio_write(bio); } static int sdfat_writepage(struct page *page, struct writeback_control *wbc) @@ -3298,45 +3456,45 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) struct inode * const inode = page->mapping->host; struct super_block *sb = inode->i_sb; loff_t i_size = i_size_read(inode); - const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; - const unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits; + const pgoff_t end_index = i_size >> PAGE_SHIFT; + const unsigned int blocks_per_page = PAGE_SIZE >> inode->i_blkbits; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); struct buffer_head *bh, *head; sector_t block, block_0, last_phys; int ret; unsigned int nr_blocks_towrite = blocks_per_page; - /* Don't distinguish 0-filled/clean block. - * Just write back the whole page + /* Don't distinguish 0-filled/clean block. + * Just write back the whole page */ - if (fsi->cluster_size < PAGE_CACHE_SIZE) + if (fsi->cluster_size < PAGE_SIZE) goto confused; - if (!PageUptodate(page)){ - MMSG("%s: Not up-to-date page -> block_write_full_page\n", + if (!PageUptodate(page)) { + MMSG("%s: Not up-to-date page -> block_write_full_page\n", __func__); goto confused; } if (page->index >= end_index) { /* last page or outside i_size */ - unsigned offset = i_size & (PAGE_CACHE_SIZE-1); + unsigned int offset = i_size & (PAGE_SIZE-1); /* If a truncation is in progress */ if (page->index > end_index || !offset) goto confused; - /* 0-fill after i_size */ - zero_user_segment(page, offset, PAGE_CACHE_SIZE); + /* 0-fill after i_size */ + zero_user_segment(page, offset, PAGE_SIZE); } - if (!page_has_buffers(page)){ + if (!page_has_buffers(page)) { MMSG("WP: No buffers -> block_write_full_page\n"); goto confused; } - block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); - block_0 = block; // first block + block = (sector_t)page->index << (PAGE_SHIFT - inode->i_blkbits); + block_0 = block; /* first block */ head = page_buffers(page); bh = head; @@ -3359,7 +3517,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) block++; continue; } - + if (nr_blocks_towrite != blocks_per_page) // Dirty -> Non-dirty -> Dirty again case goto confused; @@ -3368,9 +3526,8 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) if (!buffer_mapped(bh) || buffer_delay(bh)) { BUG_ON(bh->b_size != (1 << (inode->i_blkbits))); ret = sdfat_get_block(inode, block, bh, 1); - if (ret) { + if (ret) goto confused; - } if (buffer_new(bh)) { clear_buffer_new(bh); @@ -3399,7 +3556,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) do { clear_buffer_dirty(bh); bh = bh->b_this_page; - }while (bh != head); + } while (bh != head); BUG_ON(PageWriteback(page)); set_page_writeback(page); @@ -3410,10 +3567,10 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) * In this case, write_begin calls get_block and get original block number * and previous defrag will be canceled. */ - if ( unlikely(__check_dfr_on(inode, + if (unlikely(__check_dfr_on(inode, (loff_t)(page->index << PAGE_SHIFT), (loff_t)((page->index + 1) << PAGE_SHIFT), - __func__)) ) { + __func__))) { do { clear_buffer_mapped(bh); bh = bh->b_this_page; @@ -3479,6 +3636,7 @@ static int sdfat_writepages(struct address_space *mapping, static void sdfat_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; + if (to > i_size_read(inode)) { __sdfat_truncate_pagecache(inode, to, i_size_read(inode)); sdfat_truncate(inode, SDFAT_I(inode)->i_size_aligned); @@ -3486,51 +3644,50 @@ static void sdfat_write_failed(struct address_space *mapping, loff_t to) } static int __sdfat_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata, - get_block_t *get_block, - loff_t *bytes, - const char *fname) + loff_t pos, unsigned int len, + unsigned int flags, struct page **pagep, + void **fsdata, get_block_t *get_block, + loff_t *bytes, const char *fname) { int ret; __cancel_dfr_work(mapping->host, pos, (loff_t)(pos + len), fname); - + *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, get_block, bytes); if (ret < 0) sdfat_write_failed(mapping, pos+len); - + return ret; } static int sdfat_da_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) + loff_t pos, unsigned int len, unsigned int flags, + struct page **pagep, void **fsdata) { - return __sdfat_write_begin(file, mapping, pos, len, flags, - pagep, fsdata, sdfat_da_prep_block, + return __sdfat_write_begin(file, mapping, pos, len, flags, + pagep, fsdata, sdfat_da_prep_block, &SDFAT_I(mapping->host)->i_size_aligned, __func__); } static int sdfat_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) + loff_t pos, unsigned int len, unsigned int flags, + struct page **pagep, void **fsdata) { - return __sdfat_write_begin(file, mapping, pos, len, flags, + return __sdfat_write_begin(file, mapping, pos, len, flags, pagep, fsdata, sdfat_get_block, &SDFAT_I(mapping->host)->i_size_ondisk, __func__); } static int sdfat_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pagep, void *fsdata) + loff_t pos, unsigned int len, unsigned int copied, + struct page *pagep, void *fsdata) { struct inode *inode = mapping->host; FILE_ID_T *fid = &(SDFAT_I(inode)->fid); @@ -3560,7 +3717,7 @@ static int sdfat_write_end(struct file *file, struct address_space *mapping, static inline ssize_t __sdfat_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, void *iov_u, loff_t offset, - loff_t count) + loff_t count, unsigned long nr_segs) { struct address_space *mapping = inode->i_mapping; loff_t size = offset + count; @@ -3584,7 +3741,7 @@ static inline ssize_t __sdfat_direct_IO(int rw, struct kiocb *iocb, * sdFAT need to use the DIO_LOCKING for avoiding the race * condition of sdfat_get_block() and ->truncate(). */ - ret = __sdfat_blkdev_direct_IO(rw, iocb, inode, iov_u, offset, 0); + ret = __sdfat_blkdev_direct_IO(rw, iocb, inode, iov_u, offset, nr_segs); if (ret < 0 && (rw & WRITE)) sdfat_write_failed(mapping, size); @@ -3660,7 +3817,7 @@ static int sdfat_fill_inode(struct inode *inode, const FILE_ID_T *fid) inode->i_gid = sbi->options.fs_gid; inode->i_version++; inode->i_generation = get_seconds(); - + if (fsapi_read_inode(inode, &info) < 0) { MMSG("%s: failed to read stat!\n", __func__); return -EIO; @@ -3672,7 +3829,7 @@ static int sdfat_fill_inode(struct inode *inode, const FILE_ID_T *fid) inode->i_op = &sdfat_dir_inode_operations; inode->i_fop = &sdfat_dir_operations; - set_nlink(inode,info.NumSubdirs); + set_nlink(inode, info.NumSubdirs); } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ inode->i_op = &sdfat_symlink_inode_operations; inode->i_generation |= 1; @@ -3710,8 +3867,8 @@ static int sdfat_fill_inode(struct inode *inode, const FILE_ID_T *fid) sdfat_save_attr(inode, info.Attr); - inode->i_blocks = ( (i_size_read(inode) + (fsi->cluster_size - 1)) - & ~((loff_t)fsi->cluster_size - 1) ) >> inode->i_blkbits; + inode->i_blocks = ((i_size_read(inode) + (fsi->cluster_size - 1)) + & ~((loff_t)fsi->cluster_size - 1)) >> inode->i_blkbits; sdfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); sdfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); @@ -3749,17 +3906,16 @@ out: return inode; } -static struct inode *sdfat_alloc_inode(struct super_block *sb) { +static struct inode *sdfat_alloc_inode(struct super_block *sb) +{ struct sdfat_inode_info *ei; ei = kmem_cache_alloc(sdfat_inode_cachep, GFP_NOFS); if (!ei) return NULL; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) init_rwsem(&ei->truncate_lock); #endif - return &ei->vfs_inode; } @@ -3820,7 +3976,7 @@ static void sdfat_evict_inode(struct inode *inode) __cancel_dfr_work(inode, 0, (loff_t)old_size, __func__); /* TO CHECK evicting directory works correctly */ - MMSG("%s: inode(%p) evict %s (size(%llu) to zero)\n", + MMSG("%s: inode(%p) evict %s (size(%llu) to zero)\n", __func__, inode, S_ISDIR(inode->i_mode) ? "directory" : "file", (u64)old_size); @@ -3898,9 +4054,8 @@ static void sdfat_write_super(struct super_block *sb) __set_sb_clean(sb); #ifdef CONFIG_SDFAT_DFR - if (atomic_read(&(SDFAT_SB(sb)->dfr_info.stat)) == DFR_SB_STAT_VALID) { - fsapi_dfr_update_fat_next(sb); - } + if (atomic_read(&(SDFAT_SB(sb)->dfr_info.stat)) == DFR_SB_STAT_VALID) + fsapi_dfr_update_fat_next(sb); #endif /* flush delayed FAT/DIR dirty */ @@ -3914,18 +4069,16 @@ static void sdfat_write_super(struct super_block *sb) time = jiffies; /* Issuing bdev requests is needed - to guarantee DIR updates in time - whether w/ or w/o delayed DIR dirty feature. - - (otherwise DIR updates could be delayed for 5 + 5 secs at max.) - */ + * to guarantee DIR updates in time + * whether w/ or w/o delayed DIR dirty feature. + * (otherwise DIR updates could be delayed for 5 + 5 secs at max.) + */ sync_blockdev(sb->s_bdev); #if (defined(CONFIG_SDFAT_DFR) && defined(CONFIG_SDFAT_DFR_DEBUG)) /* SPO test */ fsapi_dfr_spo_test(sb, DFR_SPO_FAT_NEXT, __func__); #endif - MMSG("BD: sdfat_write_super (bdev_sync for %ld ms)\n", (jiffies - time) * 1000 / HZ); } @@ -3935,8 +4088,9 @@ static void __dfr_update_fat_next(struct super_block *sb) { #ifdef CONFIG_SDFAT_DFR struct sdfat_sb_info *sbi = SDFAT_SB(sb); - if ( sbi->options.defrag && - (atomic_read(&sbi->dfr_info.stat) == DFR_SB_STAT_VALID) ) { + + if (sbi->options.defrag && + (atomic_read(&sbi->dfr_info.stat) == DFR_SB_STAT_VALID)) { fsapi_dfr_update_fat_next(sb); } #endif @@ -3948,11 +4102,11 @@ static void __dfr_update_fat_prev(struct super_block *sb, int wait) struct sdfat_sb_info *sbi = SDFAT_SB(sb); struct defrag_info *sb_dfr = &sbi->dfr_info; /* static time available? */ - static int time= 0; + static int time; /* initialized by zero */ int uevent = 0, total = 0, clean = 0, full = 0; int spent = jiffies - time; - if ( !(sbi->options.defrag && wait) ) + if (!(sbi->options.defrag && wait)) return; __lock_super(sb); @@ -3968,8 +4122,8 @@ static void __dfr_update_fat_prev(struct super_block *sb, int wait) fsapi_sync_fs(sb, 1); atomic_set(&sb_dfr->stat, DFR_SB_STAT_REQ); complete_all(&sbi->dfr_complete); - } else if ( ((spent < 0) || (spent > DFR_DEFAULT_TIMEOUT)) && - (atomic_read(&(sbi->dfr_info.stat)) == DFR_SB_STAT_IDLE) ) { + } else if (((spent < 0) || (spent > DFR_DEFAULT_TIMEOUT)) && + (atomic_read(&(sbi->dfr_info.stat)) == DFR_SB_STAT_IDLE)) { uevent = fsapi_dfr_check_dfr_required(sb, &total, &clean, &full); time = jiffies; } @@ -4011,8 +4165,8 @@ static int sdfat_sync_fs(struct super_block *sb, int wait) static int sdfat_statfs(struct dentry *dentry, struct kstatfs *buf) { - /* - * patch 1.2.2 : + /* + * patch 1.2.2 : * fixed the slow-call problem because of volume-lock contention. */ struct super_block *sb = dentry->d_sb; @@ -4059,7 +4213,7 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data) (prev_sb_flags & MS_RDONLY) ? "ro" : "rw", (*flags & MS_RDONLY) ? "ro" : "rw", fsi->prev_eio, orig_data); - kfree(orig_data); + kfree(orig_data); return 0; } @@ -4097,8 +4251,7 @@ static int __sdfat_show_options(struct seq_file *m, struct super_block *sb) if (opts->improved_allocation & SDFAT_ALLOC_DELAY) seq_puts(m, ",delay"); if (opts->improved_allocation & SDFAT_ALLOC_SMART) - seq_printf(m, ",smart,ausize=%u",\ - opts->amap_opt.sect_per_au); + seq_printf(m, ",smart,ausize=%u", opts->amap_opt.sect_per_au); if (opts->defrag) seq_puts(m, ",defrag"); if (opts->adj_hidsect) @@ -4114,8 +4267,8 @@ static int __sdfat_show_options(struct seq_file *m, struct super_block *sb) else seq_puts(m, ",errors=remount-ro"); if (opts->discard) - seq_printf(m, ",discard"); - + seq_puts(m, ",discard"); + return 0; } @@ -4125,7 +4278,7 @@ static const struct super_operations sdfat_sops = { .write_inode = sdfat_write_inode, .evict_inode = sdfat_evict_inode, .put_super = sdfat_put_super, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,00) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) .write_super = sdfat_write_super, #endif .sync_fs = sdfat_sync_fs, @@ -4150,14 +4303,16 @@ static ssize_t sdfat_attr_show(struct kobject *kobj, struct attribute *attr, cha { struct sdfat_sb_info *sbi = container_of(kobj, struct sdfat_sb_info, sb_kobj); struct sdfat_attr *a = container_of(attr, struct sdfat_attr, attr); + return a->show ? a->show(sbi, buf) : 0; } static ssize_t sdfat_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t len) + const char *buf, size_t len) { struct sdfat_sb_info *sbi = container_of(kobj, struct sdfat_sb_info, sb_kobj); struct sdfat_attr *a = container_of(attr, struct sdfat_attr, attr); + return a->store ? a->store(sbi, buf, len) : len; } @@ -4169,14 +4324,16 @@ static const struct sysfs_ops sdfat_attr_ops = { static ssize_t type_show(struct sdfat_sb_info *sbi, char *buf) { - FS_INFO_T *fsi = &(sbi->fsi); + FS_INFO_T *fsi = &(sbi->fsi); + return snprintf(buf, PAGE_SIZE, "%s\n", sdfat_get_vol_type_str(fsi->vol_type)); } SDFAT_ATTR(type, 0444, type_show, NULL); static ssize_t eio_show(struct sdfat_sb_info *sbi, char *buf) { - FS_INFO_T *fsi = &(sbi->fsi); + FS_INFO_T *fsi = &(sbi->fsi); + return snprintf(buf, PAGE_SIZE, "0x%x\n", fsi->prev_eio); } SDFAT_ATTR(eio, 0444, eio_show, NULL); @@ -4196,9 +4353,9 @@ static ssize_t fratio_show(struct sdfat_sb_info *sbi, char *buf) if (!n_dirty_au) fr = 0; - else if(!n_clean_au) + else if (!n_clean_au) fr = 100; - else + else fr = (n_dirty_au * 100) / (n_clean_au + n_dirty_au); return snprintf(buf, PAGE_SIZE, "%u\n", fr); @@ -4326,7 +4483,7 @@ static const match_table_t sdfat_tokens = { {Opt_err, NULL} }; -static int parse_options(struct super_block *sb, char *options, int silent, +static int parse_options(struct super_block *sb, char *options, int silent, int *debug, struct sdfat_mount_options *opts) { char *p; @@ -4345,7 +4502,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, opts->adj_hidsect = 0; opts->tz_utc = 0; opts->improved_allocation = 0; - opts->amap_opt.pack_ratio = 0; // Default packing + opts->amap_opt.pack_ratio = 0; // Default packing opts->amap_opt.sect_per_au = 0; opts->amap_opt.misaligned_sect = 0; opts->symlink = 0; @@ -4358,9 +4515,9 @@ static int parse_options(struct super_block *sb, char *options, int silent, while ((p = strsep(&options, ",")) != NULL) { int token; + if (!*p) continue; - token = match_token(p, sdfat_tokens, args); switch (token) { case Opt_uid: @@ -4404,7 +4561,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_namecase: if (match_int(&args[0], &option)) return 0; - opts->casesensitive = option > 0 ? 1 : 0; + opts->casesensitive = (option > 0) ? 1:0; break; case Opt_utf8: opts->utf8 = 1; @@ -4465,8 +4622,8 @@ static int parse_options(struct super_block *sb, char *options, int silent, tmpstr = match_strdup(&args[0]); if (!tmpstr) return -ENOMEM; - for (i=0; ifs_type = (unsigned char)i; sdfat_log_msg(sb, KERN_ERR, "set fs-type by option : %s", @@ -4491,7 +4648,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, break; default: if (!silent) { - sdfat_msg(sb, KERN_ERR, + sdfat_msg(sb, KERN_ERR, "unrecognized mount option \"%s\" " "or missing value", p); } @@ -4511,6 +4668,7 @@ out: if (opts->discard) { struct request_queue *q = bdev_get_queue(sb->s_bdev); + if (!blk_queue_discard(q)) sdfat_msg(sb, KERN_WARNING, "mounting with \"discard\" option, but " @@ -4569,15 +4727,15 @@ static int sdfat_read_root(struct inode *inode) i_size_write(inode, info.Size); SDFAT_I(inode)->fid.size = info.Size; - inode->i_blocks = ( (i_size_read(inode) + (fsi->cluster_size - 1)) - & ~((loff_t)fsi->cluster_size - 1) ) >> inode->i_blkbits; + inode->i_blocks = ((i_size_read(inode) + (fsi->cluster_size - 1)) + & ~((loff_t)fsi->cluster_size - 1)) >> inode->i_blkbits; SDFAT_I(inode)->i_pos = ((loff_t) fsi->root_dir << 32) | 0xffffffff; SDFAT_I(inode)->i_size_aligned = i_size_read(inode); SDFAT_I(inode)->i_size_ondisk = i_size_read(inode); sdfat_save_attr(inode, ATTR_SUBDIR); inode->i_mtime = inode->i_atime = inode->i_ctime = ts; - set_nlink(inode,info.NumSubdirs + 2); + set_nlink(inode, info.NumSubdirs + 2); return 0; } @@ -4585,10 +4743,10 @@ static int sdfat_read_root(struct inode *inode) static void setup_dops(struct super_block *sb) { - if (SDFAT_SB(sb)->options.casesensitive == 0) - sb->s_d_op = &sdfat_ci_dentry_ops; - else - sb->s_d_op = &sdfat_dentry_ops; + if (SDFAT_SB(sb)->options.casesensitive == 0) + sb->s_d_op = &sdfat_ci_dentry_ops; + else + sb->s_d_op = &sdfat_dentry_ops; } static int sdfat_fill_super(struct super_block *sb, void *data, int silent) @@ -4611,7 +4769,7 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent) */ sbi = kzalloc(sizeof(struct sdfat_sb_info), GFP_KERNEL); if (!sbi) { - sdfat_log_msg(sb, KERN_INFO, + sdfat_log_msg(sb, KERN_INFO, "trying to alloc sbi with vzalloc()"); sbi = vzalloc(sizeof(struct sdfat_sb_info)); if (!sbi) { @@ -4620,20 +4778,21 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent) } sbi->use_vmalloc = 1; } - + mutex_init(&sbi->s_vlock); sb->s_fs_info = sbi; sb->s_flags |= MS_NODIRATIME; sb->s_magic = SDFAT_SUPER_MAGIC; sb->s_op = &sdfat_sops; ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); + DEFAULT_RATELIMIT_BURST); err = parse_options(sb, data, silent, &debug, &sbi->options); if (err) { sdfat_log_msg(sb, KERN_ERR, "failed to parse options"); goto failed_mount; } + setup_sdfat_xattr_handler(sb); setup_sdfat_sync_super_wq(sb); setup_dops(sb); @@ -4711,12 +4870,15 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent) "%s[%d:%d]", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); if (err) { sdfat_msg(sb, KERN_ERR, "Unable to create sdfat attributes for" - " %s[%d:%d](%d)", sb->s_id, + " %s[%d:%d](%d)", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), err); goto failed_mount3; } sdfat_log_msg(sb, KERN_INFO, "mounted successfully!"); + /* FOR BIGDATA */ + sdfat_statistics_set_mnt(&sbi->fsi); + sdfat_statistics_set_vol_size(sb); return 0; failed_mount3: @@ -4759,7 +4921,7 @@ static void init_once(void *foo) static int __init sdfat_init_inodecache(void) { - sdfat_inode_cachep = kmem_cache_create("sdfat_inode_cache", + sdfat_inode_cachep = kmem_cache_create("sdfat_inode_cache", sizeof(struct sdfat_inode_info), 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), init_once); @@ -4786,7 +4948,8 @@ static void sdfat_debug_kill_sb(struct super_block *sb) if (flags & SDFAT_DEBUGFLAGS_INVALID_UMOUNT) { /* invalidate_bdev drops all device cache include dirty. - we use this to simulate device removal */ + * we use this to simulate device removal + */ fsapi_cache_release(sb); invalidate_bdev(bdev); } @@ -4819,32 +4982,37 @@ static int __init init_sdfat_fs(void) sdfat_kset = kset_create_and_add("sdfat", NULL, fs_kobj); if (!sdfat_kset) { - printk(KERN_ERR "[SDFAT] failed to create fs_kobj\n"); + pr_err("[SDFAT] failed to create fs_kobj\n"); err = -ENOMEM; goto error; } err = sysfs_create_group(&sdfat_kset->kobj, &attr_group); if (err) { - printk(KERN_ERR "[SDFAT] failed to create sdfat " - "version attributes\n"); + pr_err("[SDFAT] failed to create sdfat version attributes\n"); goto error; } + err = sdfat_statistics_init(sdfat_kset); + if (err) + goto error; + err = sdfat_init_inodecache(); if (err) { - printk(KERN_ERR "[SDFAT] failed to initialize inode cache\n"); + pr_err("[SDFAT] failed to initialize inode cache\n"); goto error; } err = register_filesystem(&sdfat_fs_type); if (err) { - printk(KERN_ERR "[SDFAT] failed to register filesystem\n"); + pr_err("[SDFAT] failed to register filesystem\n"); goto error; } return 0; error: + sdfat_statistics_uninit(); + if (sdfat_kset) { sysfs_remove_group(&sdfat_kset->kobj, &attr_group); kset_unregister(sdfat_kset); @@ -4854,19 +5022,20 @@ error: sdfat_destroy_inodecache(); fsapi_shutdown(); - printk(KERN_ERR "[SDFAT] failed to initialize FS driver " - "(err:%d)\n", err); + pr_err("[SDFAT] failed to initialize FS driver(err:%d)\n", err); return err; } static void __exit exit_sdfat_fs(void) { + sdfat_statistics_uninit(); + if (sdfat_kset) { sysfs_remove_group(&sdfat_kset->kobj, &attr_group); kset_unregister(sdfat_kset); sdfat_kset = NULL; } - + sdfat_destroy_inodecache(); unregister_filesystem(&sdfat_fs_type); diff --git a/sdfat.h b/sdfat.h index 4dade10..2f10b96 100644 --- a/sdfat.h +++ b/sdfat.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_H @@ -35,28 +33,28 @@ #include "dfr.h" #endif -/* +/* * sdfat error flags */ -#define SDFAT_ERRORS_CONT 1 /* ignore error and continue */ -#define SDFAT_ERRORS_PANIC 2 /* panic on error */ -#define SDFAT_ERRORS_RO 3 /* remount r/o on error */ +#define SDFAT_ERRORS_CONT (1) /* ignore error and continue */ +#define SDFAT_ERRORS_PANIC (2) /* panic on error */ +#define SDFAT_ERRORS_RO (3) /* remount r/o on error */ /* * sdfat allocator flags */ -#define SDFAT_ALLOC_DELAY 1 /* Delayed allocation */ -#define SDFAT_ALLOC_SMART 2 /* Smart allocation */ +#define SDFAT_ALLOC_DELAY (1) /* Delayed allocation */ +#define SDFAT_ALLOC_SMART (2) /* Smart allocation */ /* * sdfat allocator destination for smart allocation */ -#define ALLOC_NOWHERE 0 -#define ALLOC_COLD 1 -#define ALLOC_HOT 16 -#define ALLOC_COLD_ALIGNED 1 -#define ALLOC_COLD_PACKING 2 -#define ALLOC_COLD_SEQ 4 +#define ALLOC_NOWHERE (0) +#define ALLOC_COLD (1) +#define ALLOC_HOT (16) +#define ALLOC_COLD_ALIGNED (1) +#define ALLOC_COLD_PACKING (2) +#define ALLOC_COLD_SEQ (4) /* * sdfat nls lossy flag @@ -71,22 +69,24 @@ #define CLUSTER_16(x) ((u16)((x) & 0xFFFFU)) #define CLUSTER_32(x) ((u32)((x) & 0xFFFFFFFFU)) #define CLUS_EOF CLUSTER_32(~0) +#define CLUS_BAD (0xFFFFFFF7U) #define CLUS_FREE (0) #define CLUS_BASE (2) -#define IS_CLUS_EOF(x) (x == CLUS_EOF) -#define IS_CLUS_FREE(x) (x == CLUS_FREE) -#define IS_LAST_SECT_IN_CLUS(fsi, sec) \ - ( (((sec) - (fsi)->data_start_sector + 1) \ - & ((1 << (fsi)->sect_per_clus_bits) -1)) == 0 ) +#define IS_CLUS_EOF(x) ((x) == CLUS_EOF) +#define IS_CLUS_BAD(x) ((x) == CLUS_BAD) +#define IS_CLUS_FREE(x) ((x) == CLUS_FREE) +#define IS_LAST_SECT_IN_CLUS(fsi, sec) \ + ((((sec) - (fsi)->data_start_sector + 1) \ + & ((1 << (fsi)->sect_per_clus_bits) - 1)) == 0) #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) \ - ((((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 */ -extern const char* FS_TYPE_STR[]; +extern const char *FS_TYPE_STR[]; enum { FS_TYPE_AUTO, @@ -99,12 +99,12 @@ enum { * sdfat mount in-memory data */ struct sdfat_mount_options { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) - uid_t fs_uid; - gid_t fs_gid; -#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) kuid_t fs_uid; kgid_t fs_gid; +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */ + uid_t fs_uid; + gid_t fs_gid; #endif unsigned short fs_fmask; unsigned short fs_dmask; @@ -142,7 +142,7 @@ struct sdfat_sb_info { struct mutex s_vlock; /* volume lock */ int use_vmalloc; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) int s_dirt; struct mutex s_lock; /* superblock lock */ int write_super_queued; /* Write_super work is pending? */ @@ -195,12 +195,12 @@ struct sdfat_sb_info { struct sdfat_inode_info { FILE_ID_T fid; 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_aligned; /* block-aligned i_size (used in cont_write_begin) */ loff_t i_pos; /* on-disk position of directory entry or 0 */ 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 */ #endif #ifdef CONFIG_SDFAT_DFR @@ -218,7 +218,7 @@ static inline const char *sdfat_get_vol_type_str(unsigned int type) { if (type == EXFAT) return "exfat"; - else if (type == FAT32) + else if (type == FAT32) return "vfat:32"; else if (type == FAT16) return "vfat:16"; @@ -230,10 +230,10 @@ static inline const char *sdfat_get_vol_type_str(unsigned int type) 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) { return container_of(inode, struct sdfat_inode_info, vfs_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) { u32 attrs = SDFAT_I(inode)->fid.attr; + if (S_ISDIR(inode->i_mode)) attrs |= ATTR_SUBDIR; 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/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 */ /* NLS management function */ 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_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_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 */ #ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE 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 /* sdfat/xattr.c */ #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_listxattr(struct dentry *dentry, char *list, size_t size); extern int sdfat_removexattr(struct dentry *dentry, const char *name); +#else +static inline void setup_sdfat_xattr_handler(struct super_block *sb) {}; #endif /* sdfat/misc.c */ extern void __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...) \ - __sdfat_fs_error(sb, 1, fmt , ## args) + __sdfat_fs_error(sb, 1, fmt, ## args) #define sdfat_fs_error_ratelimit(sb, 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, ...) - __attribute__ ((format (printf, 4, 5))) __cold; + __printf(4, 5) __cold; #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...) \ - __sdfat_msg(sb, lv, 1, fmt , ## args) + __sdfat_msg(sb, lv, 1, fmt, ## args) extern void sdfat_log_version(void); extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts, DATE_TIME_T *tp); @@ -367,20 +397,16 @@ void sdfat_debug_check_clusters(struct inode *inode); #endif /* CONFIG_SDFAT_DEBUG */ #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 __t2; -#define TIME_GET(tv) sdfat_time_current_usec(tv) -#define TIME_START(s) do {sdfat_time_current_usec(s); } while (0) -#define TIME_END(e) do {sdfat_time_current_usec(e); } while (0) +#define TIME_GET(tv) sdfat_time_current_usec(tv) +#define TIME_START(s) sdfat_time_current_usec(s) +#define TIME_END(e) sdfat_time_current_usec(e) #define TIME_ELAPSED(s, e) ((u32)(((e)->tv_sec - (s)->tv_sec) * 1000000 + \ ((e)->tv_usec - (s)->tv_usec))) -#define PRINT_TIME(n) \ - do { \ - printk("[SDFAT] Elapsed time %d = %d (usec)\n", \ - n, (__t2 - __t1)); \ - } while(0) +#define PRINT_TIME(n) pr_info("[SDFAT] Elapsed time %d = %d (usec)\n", n, (__t2 - __t1)) #else /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */ #define TIME_GET(tv) (0) #define TIME_START(s) @@ -403,11 +429,12 @@ extern struct timeval __t2; #define __S(x) #x #define _S(x) __S(x) -extern void __sdfat_dmsg(int level, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))) __cold; +extern void __sdfat_dmsg(int level, const char *fmt, ...) __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_DMSG_T(level, ...) __sdfat_dmsg(level, KERN_INFO "[" SDFAT_TAG_NAME "] " __VA_ARGS__) +#define SDFAT_EMSG_T(level, ...) \ + __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_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 */ -#define ASSERT(expr) \ - if (!(expr)) { \ - printk(KERN_ERR "Assertion failed! %s\n", #expr); \ - BUG_ON(1); \ - } +#define ASSERT(expr) { \ + if (!(expr)) { \ + pr_err("Assertion failed! %s\n", #expr); \ + BUG_ON(1); \ + } \ +} #endif /* !_SDFAT_H */ diff --git a/sdfat_fs.h b/sdfat_fs.h index 4c273d4..998ca84 100644 --- a/sdfat_fs.h +++ b/sdfat_fs.h @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _SDFAT_FS_H @@ -59,7 +58,7 @@ /* NOTE : * 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, - * 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 */ #define MAX_UNINAME_BUF_SIZE (((MAX_NAME_LENGTH+1)*2)+4) @@ -73,6 +72,7 @@ #define DENTRY_SIZE_BITS 5 #define MAX_FAT_DENTRIES 65536 /* FAT allows 65536 directory entries */ +#define MAX_EXFAT_DENTRIES 8388608 /* exFAT allows 8388608(256MB) directory entries */ /* PBR entries */ #define PBR_SIGNATURE 0xAA55 @@ -100,7 +100,7 @@ #define MSDOS_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_BITMAP 0x81 /* allocation bitmap */ #define EXFAT_UPCASE 0x82 /* upcase table */ @@ -143,17 +143,17 @@ #define CS_PBR_SECTOR 1 #define CS_DEFAULT 2 -/* - * ioctl command +/* + * ioctl command */ #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_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_SPO_FLAG _IOC(_IOC_NONE, 'E', 0x16, sizeof(u32)) #define SDFAT_IOCTL_PANIC _IOC(_IOC_NONE, 'E', 0x17, sizeof(u32)) -/* +/* * ioctl command for debugging */ @@ -162,7 +162,7 @@ * - file systems typically #0~0x1F * - embedded terminal devices #128~ * - 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. * @@ -184,15 +184,15 @@ typedef struct { __u8 sect_size[2]; /* unaligned */ __u8 sect_per_clus; - __le16 num_reserved; /* . */ + __le16 num_reserved; /* . */ __u8 num_fats; - __u8 num_root_entries[2]; /* unaligned */ + __u8 num_root_entries[2]; /* unaligned */ __u8 num_sectors[2]; /* unaligned */ __u8 media_type; __le16 num_fat_sectors; __le16 sectors_in_track; __le16 num_heads; - __le32 num_hid_sectors; /* . */ + __le32 num_hid_sectors; /* . */ __le32 num_huge_sectors; __u8 phy_drv_no; @@ -213,7 +213,7 @@ typedef struct { __u8 sect_per_clus; __le16 num_reserved; __u8 num_fats; - __u8 num_root_entries[2]; /* unaligned */ + __u8 num_root_entries[2]; /* unaligned */ __u8 num_sectors[2]; /* unaligned */ __u8 media_type; __le16 num_fat_sectors; /* zero */ diff --git a/statistics.c b/statistics.c new file mode 100644 index 0000000..cf4baab --- /dev/null +++ b/statistics.c @@ -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]++; +} diff --git a/upcase.h b/upcase.h index 4d3c2ac..386772c 100644 --- a/upcase.h +++ b/upcase.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ #ifndef _UPCASE_H @@ -30,11 +28,11 @@ 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) { - return i & ~HIGH_INDEX_MASK; + return i & ~HIGH_INDEX_MASK; } diff --git a/version.h b/version.h index 33c5804..831475e 100644 --- a/version.h +++ b/version.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -24,4 +22,4 @@ /* PURPOSE : sdFAT File Manager */ /* */ /************************************************************************/ -#define SDFAT_VERSION "1.3.24" +#define SDFAT_VERSION "1.4.16" diff --git a/xattr.c b/xattr.c index e6ed8ca..40bb850 100644 --- a/xattr.c +++ b/xattr.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program; if not, see . */ /************************************************************************/ @@ -48,7 +46,16 @@ static int can_support(const char *name) 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)) return -EOPNOTSUPP; @@ -56,7 +63,7 @@ int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, s 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)) return -EOPNOTSUPP; @@ -67,17 +74,59 @@ ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, siz 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) { - if (can_support(name)) - return -EOPNOTSUPP; - - return 0; + return __sdfat_xattr_check_support(name); } - +void setup_sdfat_xattr_handler(struct super_block *sb) +{ + /* DO NOTHING */ +} +#endif