UBIFS文件系统

引言

什么是UBIFS文件系统

UBIFS是UBI file system的简称,用于裸的flash设备,作为jffs2的后继文件系统之一。UBIFS通过UBI子系统处理与MTD设备之间动作。UBIFS文件系统更适合MLCNAND FLASH。需要注意的是UBIFS并不是为SSD,MMC,SD,Compact Flash等之类的基于flash的存储设备,其是针对于裸flash设备。

         裸flash有以下特点:

l  其包含的块被称为可擦除块,而对于SSD这类的设备,并无可擦除块的概念,取而代之的是扇区的概念。

l  包括读、写、擦除可擦除块三种操作。

l  硬件并不管理坏的可擦除块,而SSD之类的设备则具有专门的控制器处理坏块。

l  可擦除块的读写寿命从几千到几十万之间不等。

图0.1中给出的设备是MMC、SD类型的,该设备具有flash转换层的硬件控制器,该硬件控制器的损耗平衡算法属于商业秘密,华为的dorado 系列高端存储器的文档对其损耗平衡(动态和静态)原理讲解的非常透彻,感兴趣的可以自己找找。对于UBIFS使用的场景,通常只有NANDFLASH那一个模块,其和控制器的接口通常是专门的NAND flash接口。由于这类设备的速率比较慢,所以通常用在相对而言比较低端的嵌入式设备,追求加载速度快一点嵌入式设备通常会选择使用emmc存储器,其文件系统通常会选择UFS。

图0.1 具有flash转换层的设备

UBI/UBIFS 协议栈

图0.2 UBIFS实现的协议栈

MTD(Memory Technology Devices)对闪存存储器提供了一个抽象,隐藏了特定flash的独特之处,提供统一的API存取各种类型的flash。

MTD在内核层的API是struct mtd_device而用户空间的API接口是/dev/mtd0,这些接口提供了设备信息,读写可擦除块,擦除一个可擦除块,标记一个可擦除块是坏块,检查可擦除块是否是坏块。MTD的API并不隐藏坏的可擦除块也不做任何损耗平衡。

UBI(Unsorted Block Images)的内核API是include/mtd/ubi-user.h,用户空间的则是/dev/ubi0,提供损耗平衡,隐藏坏块,允许运行时容量创建、删除和修改,有点类似LVM功能。UBI线性扩展,在初始化时会读取所有的可擦除块头,所以当flash容量越大,初始化所花费的时间越多,但是就可扩展性而言比JFFS2要好很多。

LEB(logic eraseblock),PEB(physical erase block);将LEB映射到PEB,任何一个LEB可能映射到任何一个PEB,可擦除块头存储的是映射信息以及擦除计数值。

图0.3 UBI基本思想

UBI坏的可擦除块处理:

l  为坏的可擦除块预留1%的PEB

l  如果一个PEB变成坏块,则相应的LEB会被映射到一个好的PEB中

l  I/O错处处理对上层并未隐藏。

写错误处理

假设用户写数据到LEB0可擦除块,选择一个好的PEB可擦除块(这里假设选择PEB4)来恢复数据,恢复数据实际上就是将数据拷贝到PEB4,然后重新映射LEB0到PEB4,映射完毕后将新数据再次写入PEB4,这是恢复就完成了,将回到UBI层,后台会将PEB1标记为坏块。

图0.4 写错误处理示例

原子改变LEB

这对UBIFS非常重要,假设LEB0需要被原子改变,这一过程是这样的:

         首先选择一个合适的PEB块,加入这里选择了PEB0,然后向这个块写入新数据,写入完成后需要将原始映射PEB4解映射同时将LEB0映射到PEB0,这是就完成了原子更新操作返回UBI层,但是PEB4的数据会被后台擦除。

图0.5 原子改变LEB

对UBI底层的操作有了一些了解后,可以开始UBIFS的介绍了,首先UBIFS并不关系可擦除坏块了,这一信息依赖于UBI层,损耗平衡依赖于UBI层而不是UBIFS,LEB的更改是原子性的。

         UBIFS文件索引

索引允许查找任何数据片段的物理地址。索引采用B+2的结构,图中右上半部分,只有叶子节点包含数据,数的扇出可配,缺省值是8。UBIFS的索引在flash上存储和维护。


图0.6 UBIFS索引

UBIFS日志

日志比较小,为节省功耗只扫描日志并不扫描flash所有数据,这一结果会让挂载很快完成。文件系统所有更改将被日志记录,索引信息只在内存修改,并不在flash上修改。

         主节点存在于LEB1和LEB2,这两个块存储的是一样的,用于备份恢复之用,主节点指向根索引,主分区在挂载时可以很快被找到。


图0.7 索引和UBIFS的关系

超级块

超级块存储在LEB0位置处,对于UBIFS文件系统只读,但是可以被用户空间工具修改,存储如索引树扇出等一些配置信息,缺省使用zlib或者LZO进行压缩,在挂载该文件系统时,UBIFS的mount方法将被调用读取该超级块。

树节点缓存(TreeNode Cache)

         为了加速文件的操作,每次更新flash上的索引树的速率较慢,所以在内存中建立树节点缓存以加快索引树查找。

垃圾回收

有一个空的LEB专门为垃圾回收保留。垃圾回收的一个例子如下:

首先选择一个脏LEB,比如LEB1被选中,然后将其有效数据拷贝的到LEB5,LEB1这时就可以被擦除了,然后再选择一个脏LEB区,如LEB6,同样将数据拷贝到LEB5,拷贝完成后LEB6上的原有数据可能被擦除掉,LEB1将未垃圾回收预留,LEB6这时处于可用状态。索引处理方法,只是将Tree Node Cache的索引节点标记为脏。这样垃圾回收完成。但是还进行一个确认操作,确认操作肯定是可以完成的,会为索引预留至少3倍的空闲空间。

图0.8 垃圾回收原理

LPT(LEB Properites Tree)

         是一个B+树,但是大小固定,比主索引树小很多,管理方法类似于主索引树。

UBIFS初始化

UBIFS的文件系统需要编译的文件如下fs/ubifs/Makefile ,最后会编译成ubifs.o这个文件,链接时会将该文件链接到镜像文件中去。

Shrinker是动态调整树大小的。Journal是UBIFS的日志功能实现的文件,file、dir、super、sb以及io是文件、目录、超级块以及io操作实现;

Tnc(tree nodecache)模块,commit是在垃圾回收确认会用到的操作。gc是垃圾回收实现源码。


为了知道该模块的注册过程,首先查找相关的init函数。


         透过上面的两个查找可以知道,UBIFS子系统在加载时会首先执行ubifs_init函数,这很late_initcall在《Linux系统启动那些事—基于Linux 3.10内核》一文提到过其调用的时机,在系统启动时会被调用。

Super.c
	static int __init ubifs_init(void)
{
首先申请一个slab分配器,关于slab见《内存管理-之内核内存管理-基于linux3.10》
	ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab",
				sizeof(struct ubifs_inode), 0,
				SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT,
				&inode_slab_ctor);
//将ubifs_shrinker(定义于shrinker.c文件)注册到VM子系统,在cache压力较大时,将会缩小TNC(tree node cache)。
register_shrinker(&ubifs_shrinker_info);
//UBIFS文件系统支持两种压缩格式lzo和zlib,该函数定义于compress.c文件,两种压缩格式在编译时根据宏选定。
	err = ubifs_compressors_init();
//注册该文件系统,这个过程见《虚拟文件系统 (VFS)-基于linux3.10》,这里比较感兴趣的是ubifs_fs_type
	err = register_filesystem(&ubifs_fs_type);
}

mount方法才是最感兴趣的,在《虚拟文件系统 (VFS)-基于linux3.10》里提到文件系统挂载时会调用具体的文件系统的mount方法,这里就来看看它的mount方法。

<super.c>
static struct file_system_type ubifs_fs_type = {
	.name    = "ubifs",
	.owner   = THIS_MODULE,
	.mount   = ubifs_mount,
	.kill_sb = kill_ubifs_super,
};

Mount的函数虽然很重要,但是并没有想象中那么复杂,逻辑结构相对比较明晰。该函数首先调用open_ubi打开一个UBI设备,之所以以只读方式打开是因为这也许是一个新的挂载点,UBI同一时刻只允许有一个读写者。alloc_ubifs_info为描述UBIFS文件系统的结构体struct ubifs_info申请内存,并且初始化自旋锁、互斥锁、链表、树节点等操作。Sget首先在该文件系统中查找超级块,如果没有找到则调用alloc_super创建一个超级块,并初始化超级块的相关成员,该函数并未定义于ubifs文件目录内。然后调用ubifs_fill_super对超级块进行填充,填充的信息源于LEB0,这涉及到UBI和MTD层。由于fill_super()函数在一次打开了UBI,所以这里调用ubi_close_volume将其关闭。最后调用dget返回目录项。

图1.1 UBIFS挂载过程

假设挂载形式如《虚拟文件系统 (VFS)-基于linux3.10》提到的,如:

mount   –t     ubifs               /dev/ubi4_0                         /config

则open_ubi调用ubi_open_volume_path(“/dev/ubi4_0”,UBI_READONLY)查找UBI卷描述符。

struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
{
//该函数分析见《虚拟文件系统 (VFS)-基于linux3.10》
	error = kern_path(pathname, LOOKUP_FOLLOW, &path);

	inode = path.dentry->d_inode;
	mod = inode->i_mode;
//获得主次设备号
	ubi_num = ubi_major2num(imajor(inode));
	vol_id = iminor(inode) - 1;
	path_put(&path);

UBI卷描述符的获取
	if (vol_id >= 0 && ubi_num >= 0)
		return ubi_open_volume(ubi_num, vol_id, mode);
}

ubi_open_volume获取UBI卷描述符,主要依赖前两个参数,第一个参数是UBI主设备号对应的数字,而第二个参数是UBI次设备号对应的数字。由主设备号索引到ubi设备,ubi_devices是一个局部全局的描述ubi设备的数组。

struct ubi_device *ubi;
ubi = ubi_devices[ubi_num];

根据ubi设备信息找到UBI卷:

vol = ubi->volumes[vol_id];

alloc_ubifs_info主要功能就是slab分配内存,不多解释,有兴趣见《内存管理-之内核内存管理-基于linux3.10》。

sget用于查找并创建超级块

struct super_block *sget(struct file_system_type *type,
			int (*test)(struct super_block *,void *),
			int (*set)(struct super_block *,void *),
			int flags,
			void *data)
{
	struct super_block *s = NULL;
	struct super_block *old;
	int err;

retry:
	spin_lock(&sb_lock); //获得超级块锁
//这个if语句就是在现有的文件系统中查找超级块是否存在
	if (test) { //这个函数在存在,实际上就是sb_test函数。
		hlist_for_each_entry(old, &type->fs_supers, s_instances) {
			if (!test(old, data))
				continue;
			if (!grab_super(old))
				goto retry;
			if (s) {
				up_write(&s->s_umount);
				destroy_super(s);
				s = NULL;
			}
			down_write(&old->s_umount);
			if (unlikely(!(old->s_flags & MS_BORN))) {
				deactivate_locked_super(old);
				goto retry;
			}
			return old;
		}
	}
//如果s == null,则说明上面在ubifs文件系统中没有找到,则需要创建超级块,这里申请内存。
	if (!s) {
		spin_unlock(&sb_lock);
		s = alloc_super(type, flags);
		if (!s)
			return ERR_PTR(-ENOMEM);
		goto retry;
	}
//调用set方法,为超级块设置一些内容。
	err = set(s, data);
	if (err) {
		spin_unlock(&sb_lock);
		up_write(&s->s_umount);
		destroy_super(s);
		return ERR_PTR(err);
	}
//对超级块的一些其它字段的初始化。
	s->s_type = type;
	strlcpy(s->s_id, type->name, sizeof(s->s_id));
	list_add_tail(&s->s_list, &super_blocks);
	hlist_add_head(&s->s_instances, &type->fs_supers);
	spin_unlock(&sb_lock);
	get_filesystem(type);
	register_shrinker(&s->s_shrink);
	return s;
}

如果sb->s_root为null,则说明还没挂载,该超级块的内容需要从flash上读取。这个任务有ubifs_fill_super实现。

该函数的原型如下:

static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
sb参数是先前创建的超级块,首先将超级块描述ubifs信息的字段单独取出来
	struct ubifs_info *c = sb->s_fs_info;

	c->vfs_sb = sb;
	这里重新打开改UBI设备,注意权限编程的读写,这意味着需要从该设备读写数据了。
	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);

初始化相关字段,bdi是backing_dev_info简写,其功能是禁止预读,不需要改功能。
	c->bdi.name = "ubifs",
	c->bdi.capabilities = BDI_CAP_MAP_COPY;
	err  = bdi_init(&c->bdi);
	err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d",
			   c->vi.ubi_num, c->vi.vol_id);

	err = ubifs_parse_options(c, data, 0);
	if (err)
		goto out_bdi;
//超级块信息初始化
	sb->s_bdi = &c->bdi;
	sb->s_fs_info = c;
	sb->s_magic = UBIFS_SUPER_MAGIC;
	sb->s_blocksize = UBIFS_BLOCK_SIZE;
	sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
	sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
	if (c->max_inode_sz > MAX_LFS_FILESIZE)
		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
	sb->s_op = &ubifs_super_operations;

	mutex_lock(&c->umount_mutex);
//挂载ubifs文件系统。并调用ubifs_read_superblock读取超级块,使能日志功能等
	err = mount_ubifs(c);
	
	/*读取根索引节点*/
	root = ubifs_iget(sb, UBIFS_ROOT_INO);
将超级块和根索引节点关联
	sb->s_root = d_make_root(root);


UBIFS文件系统的读写实际上就是UBI层到MTD层的一个过程,其读代码的执行流程如下,

由于在这篇文章里并不分析UBI和MTD层,所以这里只列出散布在UBIFS文件目录里的各个函数接口,其功能和关键实现代码在后续文章中再剖析。

UBIFS接口函数集

Makefile中显示的各个编译后目标的文件提供的函数接口如下:

/* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
		   int len, int even_ebadmsg);
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
		    int len);
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len);
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
int ubifs_leb_map(struct ubifs_info *c, int lnum);
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs);
int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
		    int lnum, int offs);
int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
			 int lnum, int offs);
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
		     int offs);
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
		     int offs, int quiet, int must_chk_crc);
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
int ubifs_io_init(struct ubifs_info *c);
void ubifs_pad(const struct ubifs_info *c, void *buf, int pad);
int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf);
int ubifs_bg_wbufs_sync(struct ubifs_info *c);
void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum);
int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode);


/* scan.c */
struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
				  int offs, void *sbuf, int quiet);
void ubifs_scan_destroy(struct ubifs_scan_leb *sleb);
int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
		      int offs, int quiet);
struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
					int offs, void *sbuf);
void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
		    int lnum, int offs);
int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
		   void *buf, int offs);
void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
			      void *buf);

/* log.c */
void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud);
void ubifs_create_buds_lists(struct ubifs_info *c);
int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs);
struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum);
struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum);
int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum);
int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum);
int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum);
int ubifs_consolidate_log(struct ubifs_info *c);

/* journal.c */
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
		     const struct qstr *nm, const struct inode *inode,
		     int deletion, int xent);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
			 const union ubifs_key *key, const void *buf, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
		     const struct dentry *old_dentry,
		     const struct inode *new_dir,
		     const struct dentry *new_dentry, int sync);
int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
		       loff_t old_size, loff_t new_size);
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
			   const struct inode *inode, const struct qstr *nm);
int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
			   const struct inode *inode2);



/* budget.c */
int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req);
void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req);
void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
				      struct ubifs_inode *ui);
int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode,
			  struct ubifs_budget_req *req);
void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
				struct ubifs_budget_req *req);
void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
			 struct ubifs_budget_req *req);
long long ubifs_get_free_space(struct ubifs_info *c);
long long ubifs_get_free_space_nolock(struct ubifs_info *c);
int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
void ubifs_convert_page_budget(struct ubifs_info *c);
long long ubifs_reported_space(const struct ubifs_info *c, long long free);
long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);



/* find.c */
int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
			  int squeeze);
int ubifs_find_free_leb_for_idx(struct ubifs_info *c);
int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
			 int min_space, int pick_free);
int ubifs_find_dirty_idx_leb(struct ubifs_info *c);
int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);



/* tnc.c */
int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
			struct ubifs_znode **zn, int *n);
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
			void *node, const struct qstr *nm);
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
		     void *node, int *lnum, int *offs);
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
		  int offs, int len);
int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
		      int old_lnum, int old_offs, int lnum, int offs, int len);
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
		     int lnum, int offs, int len, const struct qstr *nm);
int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
			const struct qstr *nm);
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
			   union ubifs_key *to_key);
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
					   union ubifs_key *key,
					   const struct qstr *nm);
void ubifs_tnc_close(struct ubifs_info *c);
int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
		       int lnum, int offs, int is_idx);
int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
			 int lnum, int offs);
/* Shared by tnc.c for tnc_commit.c */
void destroy_old_idx(struct ubifs_info *c);
int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
		       int lnum, int offs);
int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode);
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu);
int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu);


/* tnc_misc.c */
struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
					      struct ubifs_znode *znode);
int ubifs_search_zbranch(const struct ubifs_info *c,
			 const struct ubifs_znode *znode,
			 const union ubifs_key *key, int *n);
struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode);
struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode);
long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr);
struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
				     struct ubifs_zbranch *zbr,
				     struct ubifs_znode *parent, int iip);
int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
			void *node);

/* tnc_commit.c */
int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
int ubifs_tnc_end_commit(struct ubifs_info *c);

/* shrinker.c */
int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc);

/* commit.c */
int ubifs_bg_thread(void *info);
void ubifs_commit_required(struct ubifs_info *c);
void ubifs_request_bg_commit(struct ubifs_info *c);
int ubifs_run_commit(struct ubifs_info *c);
void ubifs_recovery_commit(struct ubifs_info *c);
int ubifs_gc_should_commit(struct ubifs_info *c);
void ubifs_wait_for_commit(struct ubifs_info *c);

/* master.c */
int ubifs_read_master(struct ubifs_info *c);
int ubifs_write_master(struct ubifs_info *c);

/* sb.c */
int ubifs_read_superblock(struct ubifs_info *c);
struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
int ubifs_fixup_free_space(struct ubifs_info *c);

/* replay.c */
int ubifs_validate_entry(struct ubifs_info *c,
			 const struct ubifs_dent_node *dent);
int ubifs_replay_journal(struct ubifs_info *c);

/* gc.c */
int ubifs_garbage_collect(struct ubifs_info *c, int anyway);
int ubifs_gc_start_commit(struct ubifs_info *c);
int ubifs_gc_end_commit(struct ubifs_info *c);
void ubifs_destroy_idx_gc(struct ubifs_info *c);
int ubifs_get_idx_gc_leb(struct ubifs_info *c);
int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp);

/* orphan.c */
int ubifs_add_orphan(struct ubifs_info *c, ino_t inum);
void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum);
int ubifs_orphan_start_commit(struct ubifs_info *c);
int ubifs_orphan_end_commit(struct ubifs_info *c);
int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only);
int ubifs_clear_orphans(struct ubifs_info *c);

/* lpt.c */
int ubifs_calc_lpt_geom(struct ubifs_info *c);
int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
			  int *lpt_lebs, int *big_lpt);
int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr);
struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum);
struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum);
int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
			  ubifs_lpt_scan_callback scan_cb, void *data);

/* Shared by lpt.c for lpt_commit.c */
void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave);
void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
		     struct ubifs_lpt_lprops *ltab);
void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
		      struct ubifs_pnode *pnode);
void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
		      struct ubifs_nnode *nnode);
struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
				    struct ubifs_nnode *parent, int iip);
struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
				    struct ubifs_nnode *parent, int iip);
int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
/* Needed only in debugging code in lpt_commit.c */
int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
		       struct ubifs_nnode *nnode);

/* lpt_commit.c */
int ubifs_lpt_start_commit(struct ubifs_info *c);
int ubifs_lpt_end_commit(struct ubifs_info *c);
int ubifs_lpt_post_commit(struct ubifs_info *c);
void ubifs_lpt_free(struct ubifs_info *c, int wr_only);

/* lprops.c */
const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
					   const struct ubifs_lprops *lp,
					   int free, int dirty, int flags,
					   int idx_gc_cnt);
void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst);
void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
		      int cat);
void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
		       struct ubifs_lprops *new_lprops);
void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops);
int ubifs_categorize_lprops(const struct ubifs_info *c,
			    const struct ubifs_lprops *lprops);
int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
			int flags_set, int flags_clean, int idx_gc_cnt);
int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
			int flags_set, int flags_clean);
int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp);
const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c);
const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c);
const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c);
const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
int ubifs_calc_dark(const struct ubifs_info *c, int spc);

/* file.c */
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
int ubifs_setattr(struct dentry *dentry, struct iattr *attr);

/* dir.c */
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
			      umode_t mode);
int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
		  struct kstat *stat);

/* xattr.c */
int ubifs_setxattr(struct dentry *dentry, const char *name,
		   const void *value, size_t size, int flags);
ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
		       size_t size);
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int ubifs_removexattr(struct dentry *dentry, const char *name);

/* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);

/* recovery.c */
int ubifs_recover_master_node(struct ubifs_info *c);
int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
					 int offs, void *sbuf, int jhead);
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
					     int offs, void *sbuf);
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
int ubifs_rcvry_gc_commit(struct ubifs_info *c);
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
			     int deletion, loff_t new_size);
int ubifs_recover_size(struct ubifs_info *c);
void ubifs_destroy_size_tree(struct ubifs_info *c);

/* ioctl.c */
long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
void ubifs_set_inode_flags(struct inode *inode);
#ifdef CONFIG_COMPAT
long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#endif

/* compressor.c */
int __init ubifs_compressors_init(void);
void ubifs_compressors_exit(void);
void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
		    int *compr_type);
int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
		     int compr_type);


### 回答1: UBIFS文件系统是一种专门为嵌入式系统设计的文件系统,它的主要特点是支持压缩和闪存友好。 对于SLC NAND闪存,由于其读写速度和寿命较高,因此UBIFS文件系统很适合用于SLC NAND闪存上。它采用的压缩技术可以将存储的数据压缩至更小的空间中,同时还可以加速数据的读取和存储,从而减少闪存空间的使用,并提高闪存使用寿命。 除了支持压缩和提高存储效率之外,UBIFS文件系统还可以自动检测并修复闪存上的错误,这对于保证系统稳定性和数据完整性是非常有帮助的。此外,它还支持快速随机读取和写入操作,因此可以在需要快速存储和读取数据的应用场景下得到广泛应用。 总之,UBIFS文件系统非常适合用于SLC NAND闪存上,它可以提高嵌入式系统的存储效率和稳定性,同时还可以延长闪存的使用寿命。 ### 回答2: UBIFS是一个专为闪存设备设计的文件系统,支持SLC NAND闪存,并且可以提供良好的性能和可靠性。 SLC NAND(Single-Level Cell NAND)是一种基于NAND闪存技术的存储介质,在闪存中性能最优,可靠性最高,但比MLC NAND成本更高。 UBIFS文件系统能够充分利用SLC NAND的性能优势,通过采用快速读写方式,提供快速访问和高效的存储容量管理。 UBIFS在SLC NAND中的可靠性方面也有很好的表现。由于SLC NAND闪存使用更耐久的存储单元,UBIFS的可靠性和耐久性都比使用MLC NAND的文件系统要高得多。 总之,UBIFS文件系统的优势在于其专门为闪存设备而设计,支持SLC NAND闪存,提供高效的访问和可靠的存储容量管理。通过在SLC NAND中运行,UBIFS的性能和可靠性得到保证,并且可以帮助优化移动设备的性能和功能。 ### 回答3: UBIFS是一种专为闪存设备设计的文件系统,提供了高效的存储管理和数据保护功能。SLC NAND是一种高速、可靠的闪存芯片类型,因其可靠性和较高的写入耐久性而广泛应用于消费电子产品中。UBIFS文件系统与SLC NAND芯片的配合非常紧密,可以实现最佳的读写性能和数据稳定性。 相比于传统的文件系统,例如ext3和NTFS,UBIFS在存储管理中加入了一些先进的算法,如基于UBI层的块管理、扇区撤销等。同时,UBIFS也支持透明的压缩和加密功能,可以进一步提高数据存储的效率和安全性。 对于SLC NAND存储,它的写入耐久性比较高,因此可以不必过分关注闪存的使用寿命。同时,由于SLC NAND的读写速度非常快,UBIFS文件系统也可以针对SLC NAND进行一些优化,进一步提高文件系统的运行效率。 总的来说,UBIFS文件系统和SLC NAND芯片的结合可以实现高效、可靠的数据存储和管理,同时也可以最大限度地发挥SLC NAND芯片的读写速度和写入耐久性,从而提升系统的整体性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shichaog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值