aboutsummaryrefslogtreecommitdiff
path: root/fs/rawfs/rawfs.h
blob: 3fea6324905d68d13f6fa56f339e23dcf7979feb (plain) (blame)
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#ifndef __RAWFS_H__
#define __RAWFS_H__

#include <asm/byteorder.h>
#include <linux/list.h>

#if defined(CONFIG_MT_ENG_BUILD)  /* log is only enabled in eng load */
#define RAWFS_DBG		 pr_warn
#endif

#define RAWFS_BLOCK_FILE
/* #define RAWFS_RAM_DISK */

#define RAWFS_VERSION  0x01

/* Debug Message Mask */
enum rawfs_debug_level_enum {
	RAWFS_DBG_SUPER  = 0x0001,
	RAWFS_DBG_DEVICE = 0x0002,
	RAWFS_DBG_INODE  = 0x0004,
	RAWFS_DBG_FILE   = 0x0008,
	RAWFS_DBG_DIR	= 0x0010,
	RAWFS_DBG_DENTRY = 0x0020,
	RAWFS_DBG_INIT   = 0x0040,
	RAWFS_DBG_GC	 = 0x0080,
	RAWFS_DBG_MOUNT  = 0x0100
};

extern int rawfs_debug_msg_mask;

#define RAWFS_DEBUG_MSG_DEFAULT  (RAWFS_DBG_SUPER | RAWFS_DBG_DEVICE | \
		RAWFS_DBG_INODE | RAWFS_DBG_FILE | \
		RAWFS_DBG_DIR | RAWFS_DBG_DENTRY | \
		RAWFS_DBG_INIT | RAWFS_DBG_GC | RAWFS_DBG_MOUNT)

#ifdef RAWFS_DBG
#define RAWFS_PRINT(category, str, ...) do { \
	if (category & rawfs_debug_msg_mask)	{ \
		RAWFS_DBG("rawfs: " str, ##__VA_ARGS__); \
	} } while (0)
#else
#define RAWFS_PRINT(...)
#endif

#define RAWFS_MAX_FILENAME_LEN 60

#define RAWFS_MNT_RAM		0x01
#define RAWFS_MNT_MTD		0x02
#define RAWFS_MNT_CASE		0x10

#define RAWFS_MNT_BLOCKFILE  0x40
#define RAWFS_MNT_FIRSTBOOT  0x80

/* RAW FS super block info */
#define RAWFS_HASH_BITS 2
#define RAWFS_HASH_SIZE (1UL << RAWFS_HASH_BITS)

/* Interface to MTD block device */
struct rawfs_dev {
	int (*erase_block) (struct super_block *sb, int block_no);
	int (*read_page_user) (struct super_block *sb, int block_no, int addr,
		const struct iovec *iov, unsigned long nr_segs, int size);
	int (*write_page) (struct super_block *sb, int block_no,
		int page_no, void *buffer);
	int (*read_page) (struct super_block *sb, int block_no,
		int page_no, void *buffer);
};

/* RAW FS super block info */
struct rawfs_sb_info {
	/* File System Context */
	struct list_head fs_context;
	struct super_block *super;
	struct proc_dir_entry *s_proc;
	/* Driver context */
	void *driver_context;
	struct rawfs_dev dev;
	/* Device Info */
	int total_blocks;
	int pages_per_block;
	int sectors_per_page;
	int block_size;
	int page_size;
	int page_data_size;
	/* Managment */
	int data_block;
	int data_block_free_page_index;
	int data_block_gcmarker_page_index;
	int empty_block;
	__u32 sequence_number;
	__u32 erase_count_max;
	int flags;
	char *fake_block;
	struct mutex rawfs_lock;
	struct nls_table *local_nls;	/* Codepage used on disk */
	/* File List */
	struct list_head folder_list;
	struct list_head file_list;
	struct mutex file_list_lock;
	/* Inode Hash Table */
	spinlock_t inode_hash_lock;
	struct hlist_head inode_hashtable[RAWFS_HASH_SIZE];
	/* Misc */
	unsigned int rsize;
	unsigned int wsize;
};

#define RAWFS_NAND_BLOCKS(sb)		 ((sb)?2:0) /* We use only two block */
#define RAWFS_NAND_PAGES(sb)		  (sb->pages_per_block)
#define RAWFS_NAND_PAGE_SIZE(sb)	  (sb->page_size)
#define RAWFS_NAND_BLOCK_SIZE(sb)	 (sb->block_size)
#define RAWFS_NAND_PAGE_SECTORS(sb)	(sb->sectors_per_page)
#define RAWFS_NAND_PAGE_DATA_SIZE(sb) (sb->page_data_size)

/* RAW FS inode info */
struct rawfs_inode_info {
	spinlock_t cache_lru_lock;
	struct list_head cache_lru;
	int nr_caches;
	unsigned int cache_valid_id;

	/* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */
	loff_t mmu_private;	/* physically allocated size */

	int i_location_block;		/* File Location: block */
	int i_location_page;		 /* File Location: starting page */
	int i_location_page_count;
	int i_id;
	int i_parent_folder_id;	  /* Parent folder ID */

	char i_name[RAWFS_MAX_FILENAME_LEN+4];
	struct hlist_node i_rawfs_hash;	/* hash by i_name */
	struct rw_semaphore truncate_lock; /* protect bmap against truncate */
	struct inode vfs_inode;
};

static inline struct rawfs_sb_info *
RAWFS_SB(struct super_block *sb)
{
	return sb->s_fs_info;
}

static inline struct rawfs_inode_info *
RAWFS_I(struct inode *inode)
{
	return container_of(inode, struct rawfs_inode_info, vfs_inode);
}

static inline struct mtd_info *
RAWFS_MTD(struct super_block *sb)
{
	return RAWFS_SB(sb)->driver_context;
}

#define RAWFS_CACHE_VALID 0

#define RAWFS_ROOT_DIR_ID 1

/* RAWFS inode number */
#define RAWFS_ROOT_INO	1
#define RAWFS_BLOCK0_INO 2
#define RAWFS_BLOCK1_INO 3
#define RAWFS_MAX_RESERVED_INO 64

/* Page Signatures */
#define RAWFS_NAND_BLOCK_SIG_HEAD		0x44484B42 /* BKHD */
#define RAWFS_NAND_PAGE_SIG_HEAD		 0x44484750 /* PGHD */
#define RAWFS_NAND_PAGE_SIG_FOOT		 0x54464750 /* PGFT */
#define RAWFS_NAND_GC_MARKER_SIG_HEAD	0x44484347 /* GCHD */
#define RAWFS_NAND_PAGE_SIG_EMPTY		0xFFFFFFFF

enum rawfs_block_stat_enum {
	RAWFS_BLOCK_STAT_INVALID_HEAD  = 0,
	RAWFS_BLOCK_STAT_EMPTY		 = 1,
	RAWFS_BLOCK_STAT_INVALID_DATA  = 2,
	RAWFS_BLOCK_STAT_DATA		  = 3
};

enum rawfs_page_stat_enum {
	RAWFS_PAGE_STAT_EMPTY		 =  0,
	RAWFS_PAGE_STAT_DELETED		=  1,
	RAWFS_PAGE_STAT_VALID		 =  2,
	RAWFS_PAGE_STAT_BLOCK_HEAD	=  3,
	RAWFS_PAGE_STAT_GC_MARKER	 =  4,
	RAWFS_PAGE_STAT_UNCORRECTABLE =  5,
	RAWFS_PAGE_STAT_INVALID		=  6
};

struct rawfs_block_header {
	__u32 i_signature_head;
	__u32 i_rawfs_version;
	__u32 i_sequence_number;
	__u32 i_sequence_number_last;
	__u32 i_erase_count;
	__u32 i_crc;
} __packed;

struct rawfs_gc_marker_page {
	__u32 i_signature_head;
	__u32 i_src_block_index;
	__u32 i_src_block_sequence_number;
	__u32 i_src_block_erase_count;
	__u32 i_crc;
} __packed;

struct rawfs_file_info {   /* dentry */
	char			i_name[RAWFS_MAX_FILENAME_LEN+4];
	int			 i_chunk_index;
	int			 i_chunk_total;
	struct timespec	i_atime;
	struct timespec	i_mtime;
	struct timespec	i_ctime;
	umode_t		 i_mode;
	uid_t			i_uid;
	gid_t			i_gid;
	loff_t		  i_size;
	int			 i_parent_folder_id;
	int			 i_id; /* 0 for normal file */
};

struct rawfs_file_list_entry {
	struct list_head list;
	struct rawfs_file_info file_info;
	int i_location_block;		/* File Location: block */
	int i_location_page;		 /* File Location: starting page */
	int i_location_page_count;
};

struct rawfs_page {
	__u32	i_signature_head;
	__u32	i_crc;
	union {
		struct rawfs_file_info  i_file_info;
		__u8	padding[488];
	} i_info;
	__u8	i_data[1];
} __packed;


/* Inode operations */
int __init rawfs_init_inodecache(void);
void __exit rawfs_destroy_inodecache(void);
void rawfs_hash_init(struct super_block *sb);
struct inode *rawfs_alloc_inode(struct super_block *sb);
void rawfs_destroy_inode(struct inode *inode);
int rawfs_fill_inode(struct inode *inode,
	struct rawfs_file_info *file_info, int block_no, int page_no,
	umode_t mode, dev_t dev);
struct inode *rawfs_iget(struct super_block *sb, const char *name,
	int folder);

/* Mount-time analysis */
int rawfs_block_level_analysis(struct super_block *sb);
int rawfs_page_level_analysis(struct super_block *sb);
int rawfs_file_level_analysis(struct super_block *sb);
int rawfs_page_get(struct super_block *sb, int block_no, int page_no,
	struct rawfs_file_info *file_info, void *data);
int rawfs_block_is_valid(struct super_block *sb, int block_no,
	struct rawfs_block_header *block_head_out,
	struct rawfs_gc_marker_page *gc_page_out);

/* Device Operation */
int rawfs_dev_free_space(struct super_block *sb);
int rawfs_dev_garbage_collection(struct super_block *sb);
void rawfs_page_signature(struct super_block *sb, void *buf);

int rawfs_dev_mtd_erase_block(struct super_block *sb, int block_no);
int rawfs_dev_mtd_read_page_user(struct super_block *sb, int block_no,
	int block_offset, const struct iovec *iov, unsigned long nr_segs, int size);
int rawfs_dev_mtd_write_page(struct super_block *sb,
	int block_no, int page_no, void *buffer);
int rawfs_dev_mtd_read_page(struct super_block *sb,
	int block_no, int page_no, void *buffer);

int rawfs_dev_ram_erase_block(struct super_block *sb, int block_no);
int rawfs_dev_ram_read_page_user(struct super_block *sb, int block_no,
	int block_offset, const struct iovec *iov, unsigned long nr_segs, int size);
int rawfs_dev_ram_write_page(struct super_block *sb,
	int block_no, int page_no, void *buffer);
int rawfs_dev_ram_read_page(struct super_block *sb,
	int block_no, int page_no, void *buffer);

/* File Operations */
int rawfs_reg_file_delete(struct inode *dir, struct dentry *dentry);
int rawfs_reg_file_create(struct inode *dir, struct dentry *dentry,
	umode_t mode, struct nameidata *nd);
int rawfs_reg_file_copy(struct inode *src_dir, struct dentry *src_dentry,
	struct inode *dest_dir, struct dentry *dest_dentry);
int rawfs_reserve_space(struct super_block *sb, int chunks);
ssize_t
rawfs_reg_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
		unsigned long nr_segs, loff_t pos);
ssize_t
rawfs_reg_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
	unsigned long nr_segs, loff_t pos);
ssize_t
rawfs_block_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
	unsigned long nr_segs, loff_t pos);
ssize_t rawfs_block_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
	unsigned long nr_segs, loff_t pos);
int rawfs_file_sync(struct file *file, loff_t start, loff_t end,
	int datasync);
int rawfs_readdir(struct file *filp, void *dirent, filldir_t filldir);

/* dentry operations */
int rawfs_delete_dentry(const struct dentry *dentry);

/* File info */
void rawfs_fill_file_info(struct inode *inode,
	struct rawfs_file_info *file_info);
void rawfs_fill_fileinfo_by_dentry(struct dentry *dentry,
	struct rawfs_file_info *file_info);

/* File and Folder lists */
struct rawfs_file_list_entry *rawfs_file_list_get(struct super_block *sb,
	const char *name, int folder_id);
struct rawfs_file_list_entry *rawfs_file_list_get_by_id(
	struct super_block *sb, umode_t mode, int id);
void rawfs_file_list_init(struct super_block *sb);
int rawfs_file_list_add(struct super_block *sb,
	struct rawfs_file_info *fi, int block_no, int page_no);
void rawfs_file_list_remove(struct super_block *sb,
	struct rawfs_file_info *fi);
void rawfs_file_list_destroy(struct super_block *sb);
int rawfs_file_list_count(struct super_block *sb,
	unsigned int *entry_count, unsigned int *used_blocks,
	unsigned int *free_blocks);
__u32 rawfs_page_crc_data(struct super_block *sb, void *data_page);
__u32 rawfs_page_crc_gcmarker(struct super_block *sb, void *gcmarker_page);

/* Address Space Operations: Block file & Normal file */
int rawfs_readpage(struct file *filp, struct page *page);
int rawfs_write_begin(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata);
int rawfs_write_end(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *pg, void *fsdata);

/* Case in-sensitive dentry operations */
int rawfs_ci_hash(const struct dentry *dentry, const struct inode *inode,
	struct qstr *q);
int rawfs_compare_dentry(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);
int rawfs_delete_dentry(const struct dentry *dentry);

/* Utility */
uint32_t rawfs_div(uint64_t n, uint32_t base);

#endif