You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
11 KiB
360 lines
11 KiB
/* |
|
* Copyright (C) 2016 MediaTek Inc. |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License version 2 as |
|
* published by the Free Software Foundation. |
|
* |
|
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. |
|
*/ |
|
|
|
#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_debug |
|
#endif |
|
|
|
#define RAWFS_BLOCK_LIMIT 2 /* do not modify, design limit */ |
|
#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_DIR | RAWFS_DBG_DENTRY | \ |
|
RAWFS_DBG_INIT | 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; |
|
/* Management */ |
|
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]; |
|
}; |
|
|
|
#define RAWFS_NAND_BLOCKS(sb) ((sb)?RAWFS_BLOCK_LIMIT: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, struct dir_context *ctx); |
|
|
|
/* 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, struct qstr *q); |
|
int rawfs_compare_dentry(const struct dentry *parent, |
|
const struct dentry *dentry, 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
|
|
|