summaryrefslogtreecommitdiff
path: root/fs/sdfat/dfr.h
blob: da98605020d34582f8affcce9b07fcaa8b95fe77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
 *  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 */