| /* |
| * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * 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, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #ifndef _SDFAT_DEFRAG_H |
| #define _SDFAT_DEFRAG_H |
| |
| #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_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_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_MAX_AU_MOVED (16) // Maximum # of AUs for a request |
| |
| |
| /* Debugging support*/ |
| #define dfr_err(fmt, args...) pr_err("DFR: " fmt "\n", args) |
| |
| #ifdef CONFIG_SDFAT_DFR_DEBUG |
| #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_HANDLE2(cond, err, val) { \ |
| if (cond) { \ |
| err = val; \ |
| dfr_debug("err %d", err); \ |
| goto error; \ |
| } \ |
| } |
| |
| |
| /* Arguments IN-OUT */ |
| #define IN |
| #define OUT |
| #define INOUT |
| |
| |
| /* Macros */ |
| #define GET64_HI(var64) ((unsigned int)((var64) >> 32)) |
| #define GET64_LO(var64) ((unsigned int)(((var64) << 32) >> 32)) |
| #define SET64_HI(dst64, var32) { (dst64) = ((loff_t)(var32) << 32) | ((dst64) & 0x00000000ffffffffLL); } |
| #define SET64_LO(dst64, var32) { (dst64) = ((dst64) & 0xffffffff00000000LL) | ((var32) & 0x00000000ffffffffLL); } |
| |
| #define GET32_HI(var32) ((unsigned short)((var32) >> 16)) |
| #define GET32_LO(var32) ((unsigned short)(((var32) << 16) >> 16)) |
| #define SET32_HI(dst32, var16) { (dst32) = ((unsigned int)(var16) << 16) | ((dst32) & 0x0000ffff); } |
| #define SET32_LO(dst32, var16) { (dst32) = ((dst32) & 0xffff0000) | ((unsigned int)(var16) & 0x0000ffff); } |
| |
| |
| /* FAT32 related */ |
| #define FAT32_EOF (0x0fffffff) |
| #define FAT32_RESERVED (0x0ffffff7) |
| #define FAT32_UNUSED_CLUS (2) |
| |
| #define CLUS_PER_AU(sb) ( \ |
| (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)) \ |
| >> 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) || \ |
| ((clus) > (fsi)->num_clusters) || \ |
| ((clus) >= FAT32_RESERVED)) { \ |
| dfr_err("clus %08x, fsi->num_clusters %08x", (clus), (fsi)->num_clusters); \ |
| err = -EINVAL; \ |
| } else { \ |
| err = 0; \ |
| } \ |
| } |
| |
| |
| /* IOCTL_DFR_INFO */ |
| struct defrag_info_arg { |
| /* PBS info */ |
| unsigned int sec_sz; |
| unsigned int clus_sz; |
| unsigned long long total_sec; |
| unsigned long long fat_offset_sec; |
| unsigned int fat_sz_sec; |
| unsigned int n_fat; |
| unsigned int hidden_sectors; |
| |
| /* AU info */ |
| unsigned int sec_per_au; |
| }; |
| |
| |
| /* IOC_DFR_TRAV */ |
| #define DFR_TRAV_HEADER_IDX (0) |
| |
| #define DFR_TRAV_TYPE_HEADER (0x0000000F) |
| #define DFR_TRAV_TYPE_DIR (1) |
| #define DFR_TRAV_TYPE_FILE (2) |
| #define DFR_TRAV_TYPE_TEST (DFR_TRAV_TYPE_HEADER | 0x10000000) |
| |
| #define DFR_TRAV_ROOT_IPOS (0xFFFFFFFFFFFFFFFFLL) |
| |
| struct defrag_trav_arg { |
| int type; |
| unsigned int start_clus; |
| loff_t i_pos; |
| char name[MAX_DOSNAME_BUF_SIZE]; |
| char dummy1; |
| int dummy2; |
| }; |
| |
| #define DFR_TRAV_STAT_DONE (0x1) |
| #define DFR_TRAV_STAT_MORE (0x2) |
| #define DFR_TRAV_STAT_ERR (0xFF) |
| |
| struct defrag_trav_header { |
| int type; |
| unsigned int start_clus; |
| loff_t i_pos; |
| char name[MAX_DOSNAME_BUF_SIZE]; |
| char stat; |
| unsigned int nr_entries; |
| }; |
| |
| |
| /* IOC_DFR_REQ */ |
| #define REQ_HEADER_IDX (0) |
| |
| #define DFR_CHUNK_STAT_ERR (0xFFFFFFFF) |
| #define DFR_CHUNK_STAT_REQ (0x1) |
| #define DFR_CHUNK_STAT_WB (0x2) |
| #define DFR_CHUNK_STAT_FAT (0x4) |
| #define DFR_CHUNK_STAT_PREP (DFR_CHUNK_STAT_REQ | DFR_CHUNK_STAT_WB | DFR_CHUNK_STAT_FAT) |
| #define DFR_CHUNK_STAT_PASS (0x0000000F) |
| |
| struct defrag_chunk_header { |
| int mode; |
| unsigned int nr_chunks; |
| loff_t dummy1; |
| int dummy2[4]; |
| union { |
| int *dummy3; |
| int dummy4; |
| }; |
| int dummy5; |
| }; |
| |
| struct defrag_chunk_info { |
| int stat; |
| /* File related */ |
| unsigned int f_clus; |
| loff_t i_pos; |
| /* Cluster related */ |
| unsigned int d_clus; |
| unsigned int nr_clus; |
| unsigned int prev_clus; |
| unsigned int next_clus; |
| union { |
| void *dummy; |
| /* req status */ |
| unsigned int new_idx; |
| }; |
| /* AU related */ |
| unsigned int au_clus; |
| }; |
| |
| |
| /* Global info */ |
| #define DFR_MODE_BACKGROUND (0x1) |
| #define DFR_MODE_FOREGROUND (0x2) |
| #define DFR_MODE_ONESHOT (0x4) |
| #define DFR_MODE_BATCHED (0x8) |
| #define DFR_MODE_TEST (DFR_MODE_BACKGROUND | 0x10000000) |
| |
| #define DFR_SB_STAT_IDLE (0) |
| #define DFR_SB_STAT_REQ (1) |
| #define DFR_SB_STAT_VALID (2) |
| |
| #define DFR_INO_STAT_IDLE (0) |
| #define DFR_INO_STAT_REQ (1) |
| struct defrag_info { |
| struct mutex lock; |
| atomic_t stat; |
| struct defrag_chunk_info *chunks; |
| unsigned int nr_chunks; |
| struct list_head entry; |
| }; |
| |
| |
| /* SPO test flags */ |
| #define DFR_SPO_NONE (0) |
| #define DFR_SPO_NORMAL (1) |
| #define DFR_SPO_DISCARD (2) |
| #define DFR_SPO_FAT_NEXT (3) |
| #define DFR_SPO_RANDOM (4) |
| |
| |
| /* Extern functions */ |
| int defrag_get_info(struct super_block *sb, struct defrag_info_arg *arg); |
| |
| int defrag_scan_dir(struct super_block *sb, struct defrag_trav_arg *arg); |
| |
| int defrag_validate_cluster(struct inode *inode, struct defrag_chunk_info *chunk, int skip_prev); |
| int defrag_reserve_clusters(struct super_block *sb, int nr_clus); |
| int defrag_mark_ignore(struct super_block *sb, unsigned int clus); |
| void defrag_unmark_ignore_all(struct super_block *sb); |
| |
| int defrag_map_cluster(struct inode *inode, unsigned int clu_offset, unsigned int *clu); |
| void defrag_writepage_end_io(struct page *page); |
| |
| void defrag_update_fat_prev(struct super_block *sb, int force); |
| void defrag_update_fat_next(struct super_block *sb); |
| void defrag_check_discard(struct super_block *sb); |
| int defrag_free_cluster(struct super_block *sb, unsigned int clus); |
| |
| int defrag_check_defrag_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau); |
| int defrag_check_defrag_on(struct inode *inode, loff_t start, loff_t end, int cancel, const char *caller); |
| |
| #ifdef CONFIG_SDFAT_DFR_DEBUG |
| void defrag_spo_test(struct super_block *sb, int flag, const char *caller); |
| #endif |
| |
| #endif /* CONFIG_SDFAT_DFR */ |
| |
| #endif /* _SDFAT_DEFRAG_H */ |
| |