您的位置:首页 > 移动开发 > Android开发

让Android系统支持ubifs文件系统

2013-11-20 13:49 323 查看
原文地址:http://www.cnblogs.com/linucos/p/3279381.html

1. ubifs号称性能比yaffs2 好,同时压缩可读写,文件系统image体较小同时可写,相当不错
2. ubifs制作

(1) mkfs.ubifs

mkfs.ubifs -r system -m 2048 -e 126976 -c 1057 -x zlib -o system.ubifs

-r说的目录

-m说的是nand flash的页大小,一般都是2048或者4096,当然也有些是512,硬件特性决定好了,或者说驱动规定好了,有些平台4096页当做2048用也是用的

-e说的是逻辑擦除块大小,大家知道nand flash页读页写块擦,一个设备多个块,一个块多个页,一般也都是一个块是64个页,这样算一下无论擦除块大小就是2048*64=131072,-e的算法是物理擦除块大小-2*页大小,这里就是131072-2*2048=126976

-c说的是最大逻辑块编号,这个很重要,不能大也不能小,太小也要大于image大小,太大mount有问题,计算起点是分区的物理块数量,比如128MiB的mtd分区,物理块数量是128MiB/2048/64 = 1024个,需要减去2个坏块保留块,减去1个wear-leveling块,还要减去1个eba的块,等等,比如最终的值是1022,注意,如果物理上这个分区有坏块的话,kernel会扫描到的,这时候,我们计算的这个值就要减去坏块数了,否则会有逻辑块大于物理块数的内核问题mount失败,确切知道坏块数是比较困难的,一般做法是做一个坏块容忍数,比如20个,这样我们再减去20个坏块,不要担心这个会浪费空间,ubinize的autoresize选项就是解决这个问题的。具体的这个值需要计算。!!!!

-o说的image名字

-x说的是压缩方法,默认是lzo,还支持zlib,zlib压缩率高些,但是lzo压缩解压速度快

(2) ubinize

ubinize -o system.ubi -m 2048 -p 131072 ubinize.cfg
-o说的是输出image

-m还是页大小

-p是物理擦除块大小

ubinize.cfg是volume配置文件,例子如下:

[ubifs]

mode=ubi

image=system.ubifs #说的是mkfs.ubifs的结果

vol_id=0

vol_size=100MiB #说的是volume大小,用-e和-c的值做乘法计算,一般不用写,autoresize会自动根据mtd分区大小适应,默认值是image大小,写了这个作用是帮助检查image是否超过了分区限制,制作时候就提示,否则mount会出错。-c的值是经过计算的最大值了,不过autoresize参数会自适应大小,不会浪费空间的。

vol_type=dynamic

vol_alignment=1

vol_name=system #说的是分区名字

vol_flags=autoresize

(4) uboot支持

-0- 需要打开的配置 - 需要烧写mkfs.ubifs结果时候需要打开,ubinize处理过的不需要

CONFIG_CMD_UBI

CONFIG_CMD_UBIFS

CONFIG_LZO

CONFIG_RBTREE

CONFIG_ZLIB

CONFIG_GZIP

-1- ubifs烧写

mkfs.ubifs工具制作的结果,就是ubifs镜像,不包含volume信息,需要用

nand erase.part system

ubi part system - 激活分区

ubi create system - 创建分区

ubi write 84000000 system xxxxx - xxxxx表示镜像实际大小

-2- ubi volume bin烧写

mkfs.ubifs后,使用ubinize处理了ubifs的镜像后,镜像含有了volume信息,直接

nand write 84000000 system xxxxx - xxxxx表示镜像实际大小

(5) kernel支持

Device Drivers --->

Memory Technology Device(MTD) support --->

UBI - Unsorted block images --->

<*> Enable UBI - Unsorted block images

File systems --->

Miscellaneous filesystems --->

<*> UBIFS file system support

[*] Advanced compression options

[*] LZO compression support

[*] ZLIB compression support

(6) android支持

-1- andriod/system/core/rootdir/init.rc

mount yaffs2 mtd@userdata /data nosuid nodev
改为:

mount ubifs ubi@userdata /data nosuid nodev

-2- 增加对ubifs的mount支持

andriod/system/core/init/builtins.c

在 } else if (!strncmp(source, "loop@", 5)) {

之前加上

+ }else if (!strncmp(source, "ubi@", 4)) {

+ n = ubi_attach_mtd(source + 4);

+ if (n < 0) {

+ return -1;

+ }

+ sprintf(tmp, "/dev/ubi%d_0", n);

+ if (wait)

+ wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);

+ if (mount(tmp, target, system, flags, options) < 0) {

+ ubi_detach_dev(n);

+ return -1;

+ }

+ return 0;

+ }else if (!strncmp(source, "loop@", 5)) {

3. andriod/system/core/init/init.c

在static int property_triggers_enabled = 0;之后加上

+static unsigned ubifs_enabled = 1;

static int set_init_properties_action(int nargs, char **args)

{

property_set("ro.revision", tmp);

+ property_set("ro.ubifs",ubifs_enabled ? "1" : "0");

return 0;

}

int main(int argc, char **argv)

{

action_for_each_trigger("post-fs", action_add_queue_tail);

+ action_for_each_trigger("ubi-fs", action_add_queue_tail);

}

4. andriod/system/core/init/util.h

void get_hardware_name(char *hardware, unsigned int *revision);

+int ubi_attach_mtd(const char *name);

+int ubi_detach_dev(int dev);

5. andriod/system/core/init/util.c

#include <sys/un.h>

+#include <sys/ioctl.h>

#include "util.h"

+#include "ubi-user.h"

+#define UBI_CTRL_DEV "/dev/ubi_ctrl"

+#define UBI_SYS_PATH "/sys/class/ubi"

在最后添加下面三个函数

static int ubi_dev_read_int(int dev, const char *file, int def)

{

int fd, val = def;

char path[128], buf[64];

sprintf(path, UBI_SYS_PATH "/ubi%d/%s", dev, file);

wait_for_file(path, 5);

fd = open(path, O_RDONLY);

if (fd == -1) {

return val;

}

if (read(fd, buf, 64) > 0) {

val = atoi(buf);

}

close(fd);

return val;

}

int ubi_attach_mtd(const char *name)

{

int ret;

int mtd_num, ubi_num;

int ubi_ctrl, ubi_dev;

int vols, avail_lebs, leb_size;

char path[128];

struct ubi_attach_req attach_req;

struct ubi_mkvol_req mkvol_req;

mtd_num = mtd_name_to_number(name);

if (mtd_num == -1) {

return -1;

}

ubi_ctrl = open(UBI_CTRL_DEV, O_RDONLY);

if (ubi_ctrl == -1) {

return -1;

}

memset(&attach_req, 0, sizeof(struct ubi_attach_req));

attach_req.ubi_num = UBI_DEV_NUM_AUTO;

attach_req.mtd_num = mtd_num;

ret = ioctl(ubi_ctrl, UBI_IOCATT, &attach_req);

if (ret == -1) {

close(ubi_ctrl);

return -1;

}

ubi_num = attach_req.ubi_num;

vols = ubi_dev_read_int(ubi_num, "volumes_count", -1);

if (vols == 0) {

sprintf(path, "/dev/ubi%d", ubi_num);

ubi_dev = open(path, O_RDONLY);

if (ubi_dev == -1) {

close(ubi_ctrl);

return ubi_num;

}

avail_lebs = ubi_dev_read_int(ubi_num, "avail_eraseblocks", 0);

leb_size = ubi_dev_read_int(ubi_num, "eraseblock_size", 0);

memset(&mkvol_req, 0, sizeof(struct ubi_mkvol_req));

mkvol_req.vol_id = UBI_VOL_NUM_AUTO;

mkvol_req.alignment = 1;

mkvol_req.bytes = (long long)avail_lebs * leb_size;

mkvol_req.vol_type = UBI_DYNAMIC_VOLUME;

ret = snprintf(mkvol_req.name, UBI_MAX_VOLUME_NAME + 1, "%s", name);

mkvol_req.name_len = ret;

ioctl(ubi_dev, UBI_IOCMKVOL, &mkvol_req);

close(ubi_dev);

}

close(ubi_ctrl);

return ubi_num;

}

int ubi_detach_dev(int dev)

{

int ret, ubi_ctrl;

ubi_ctrl = open(UBI_CTRL_DEV, O_RDONLY);

if (ubi_ctrl == -1) {

return -1;

}

ret = ioctl(ubi_ctrl, UBI_IOCDET, &dev);

close(ubi_ctrl);

return ret;

}

6.增加文件

andriod/system/core/init/ubi-user.h

/*

* Copyright (c) International Business Machines Corp., 2006

*

* 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, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*

* Author: Artem Bityutskiy (Битюцкий Артём)

*/

#ifndef __UBI_USER_H__

#define __UBI_USER_H__

/*

* UBI device creation (the same as MTD device attachment)

* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*

* MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI

* control device. The caller has to properly fill and pass

* &struct ubi_attach_req object - UBI will attach the MTD device specified in

* the request and return the newly created UBI device number as the ioctl

* return value.

*

* UBI device deletion (the same as MTD device detachment)

* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*

* An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI

* control device.

*

* UBI volume creation

* ~~~~~~~~~~~~~~~~~~~

*

* UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character

* device. A &struct ubi_mkvol_req object has to be properly filled and a

* pointer to it has to be passed to the IOCTL.

*

* UBI volume deletion

* ~~~~~~~~~~~~~~~~~~~

*

* To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character

* device should be used. A pointer to the 32-bit volume ID hast to be passed

* to the IOCTL.

*

* UBI volume re-size

* ~~~~~~~~~~~~~~~~~~

*

* To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character

* device should be used. A &struct ubi_rsvol_req object has to be properly

* filled and a pointer to it has to be passed to the IOCTL.

*

* UBI volume update

* ~~~~~~~~~~~~~~~~~

*

* Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the

* corresponding UBI volume character device. A pointer to a 64-bit update

* size should be passed to the IOCTL. After this, UBI expects user to write

* this number of bytes to the volume character device. The update is finished

* when the claimed number of bytes is passed. So, the volume update sequence

* is something like:

*

* fd = open("/dev/my_volume");

* ioctl(fd, UBI_IOCVOLUP, &image_size);

* write(fd, buf, image_size);

* close(fd);

*

* Atomic eraseblock change

* ~~~~~~~~~~~~~~~~~~~~~~~~

*

* Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL

* command of the corresponding UBI volume character device. A pointer to

* &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is

* expected to write the requested amount of bytes. This is similar to the

* "volume update" IOCTL.

*/

/*

* When a new UBI volume or UBI device is created, users may either specify the

* volume/device number they want to create or to let UBI automatically assign

* the number using these constants.

*/

#define UBI_VOL_NUM_AUTO (-1)

#define UBI_DEV_NUM_AUTO (-1)

/* Maximum volume name length */

#define UBI_MAX_VOLUME_NAME 127

/* IOCTL commands of UBI character devices */

#define UBI_IOC_MAGIC 'o'

/* Create an UBI volume */

#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)

/* Remove an UBI volume */

#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)

/* Re-size an UBI volume */

#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)

/* IOCTL commands of the UBI control character device */

#define UBI_CTRL_IOC_MAGIC 'o'

/* Attach an MTD device */

#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)

/* Detach an MTD device */

#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)

/* IOCTL commands of UBI volume character devices */

#define UBI_VOL_IOC_MAGIC 'O'

/* Start UBI volume update */

#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)

/* An eraseblock erasure command, used for debugging, disabled by default */

#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)

/* An atomic eraseblock change command */

#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)

/* Maximum MTD device name length supported by UBI */

#define MAX_UBI_MTD_NAME_LEN 127

/*

* UBI data type hint constants.

*

* UBI_LONGTERM: long-term data

* UBI_SHORTTERM: short-term data

* UBI_UNKNOWN: data persistence is unknown

*

* These constants are used when data is written to UBI volumes in order to

* help the UBI wear-leveling unit to find more appropriate physical

* eraseblocks.

*/

enum {

UBI_LONGTERM = 1,

UBI_SHORTTERM = 2,

UBI_UNKNOWN = 3,

};

/*

* UBI volume type constants.

*

* @UBI_DYNAMIC_VOLUME: dynamic volume

* @UBI_STATIC_VOLUME: static volume

*/

enum {

UBI_DYNAMIC_VOLUME = 3,

UBI_STATIC_VOLUME = 4,

};

/**

* struct ubi_attach_req - attach MTD device request.

* @ubi_num: UBI device number to create

* @mtd_num: MTD device number to attach

* @vid_hdr_offset: VID header offset (use defaults if %0)

* @padding: reserved for future, not used, has to be zeroed

*

* This data structure is used to specify MTD device UBI has to attach and the

* parameters it has to use. The number which should be assigned to the new UBI

* device is passed in @ubi_num. UBI may automatically assign the number if

* @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in

* @ubi_num.

*

* Most applications should pass %0 in @vid_hdr_offset to make UBI use default

* offset of the VID header within physical eraseblocks. The default offset is

* the next min. I/O unit after the EC header. For example, it will be offset

* 512 in case of a 512 bytes page NAND flash with no sub-page support. Or

* it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.

*

* But in rare cases, if this optimizes things, the VID header may be placed to

* a different offset. For example, the boot-loader might do things faster if the

* VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As

* the boot-loader would not normally need to read EC headers (unless it needs

* UBI in RW mode), it might be faster to calculate ECC. This is weird example,

* but it real-life example. So, in this example, @vid_hdr_offer would be

* 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes

* aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page

* of the first page and add needed padding.

*/

struct ubi_attach_req {

int32_t ubi_num;

int32_t mtd_num;

int32_t vid_hdr_offset;

uint8_t padding[12];

};

/**

* struct ubi_mkvol_req - volume description data structure used in

* volume creation requests.

* @vol_id: volume number

* @alignment: volume alignment

* @bytes: volume size in bytes

* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)

* @padding1: reserved for future, not used, has to be zeroed

* @name_len: volume name length

* @padding2: reserved for future, not used, has to be zeroed

* @name: volume name

*

* This structure is used by user-space programs when creating new volumes. The

* @used_bytes field is only necessary when creating static volumes.

*

* The @alignment field specifies the required alignment of the volume logical

* eraseblock. This means, that the size of logical eraseblocks will be aligned

* to this number, i.e.,

* (UBI device logical eraseblock size) mod (@alignment) = 0.

*

* To put it differently, the logical eraseblock of this volume may be slightly

* shortened in order to make it properly aligned. The alignment has to be

* multiple of the flash minimal input/output unit, or %1 to utilize the entire

* available space of logical eraseblocks.

*

* The @alignment field may be useful, for example, when one wants to maintain

* a block device on top of an UBI volume. In this case, it is desirable to fit

* an integer number of blocks in logical eraseblocks of this UBI volume. With

* alignment it is possible to update this volume using plane UBI volume image

* BLOBs, without caring about how to properly align them.

*/

struct ubi_mkvol_req {

int32_t vol_id;

int32_t alignment;

int64_t bytes;

int8_t vol_type;

int8_t padding1;

int16_t name_len;

int8_t padding2[4];

char name[UBI_MAX_VOLUME_NAME + 1];

} __attribute__ ((packed));

/**

* struct ubi_rsvol_req - a data structure used in volume re-size requests.

* @vol_id: ID of the volume to re-size

* @bytes: new size of the volume in bytes

*

* Re-sizing is possible for both dynamic and static volumes. But while dynamic

* volumes may be re-sized arbitrarily, static volumes cannot be made to be

* smaller then the number of bytes they bear. To arbitrarily shrink a static

* volume, it must be wiped out first (by means of volume update operation with

* zero number of bytes).

*/

struct ubi_rsvol_req {

int64_t bytes;

int32_t vol_id;

} __attribute__ ((packed));

/**

* struct ubi_leb_change_req - a data structure used in atomic logical

* eraseblock change requests.

* @lnum: logical eraseblock number to change

* @bytes: how many bytes will be written to the logical eraseblock

* @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)

* @padding: reserved for future, not used, has to be zeroed

*/

struct ubi_leb_change_req {

int32_t lnum;

int32_t bytes;

uint8_t dtype;

uint8_t padding[7];

} __attribute__ ((packed));

#endif /* __UBI_USER_H__ */

3. 常见问题

(1) ubifs_check_node: bad CRC: calculated 0xca82b3d7, read 0x9be0e26

ubifs_check_node: bad node at LEB 51:45312

注意这个crc错误,说的错误并不是LED 0的问题,也就是说第一个逻辑块没问题,CRC是正确的,这个问题的一个解决办法是要精确mkfs.ubifs时候的-c参数的值,不能太大了

(2)

[ 5.433349] UBIFS error (pid 71): ubifs_read_node: bad node type (150 but expected 1)
[ 5.434204] UBIFS error (pid 71): ubifs_read_node: bad node at LEB 524:4072, LEB mapping status 1
[ 5.435241] Not a node, first 24 bytes:
[ 5.435729] 00000000: 34 fb 21 ee 84 18 69 2d 60 b0 33 e6 74 f8 1c 15 da ca a1 c9 96 e3 ac 51 4.!...i-`.3.t..........Q

这个问题是,ubifs给nand驱动的buffer不一定是按照硬件对齐要求的,所以要驱动来判断,dma等地址需要页对齐等特性

(3) crc错误,但是LED 0:0

可能镜像没烧对,或者mtd-utils的版本和内核版本相差较远

(4) 可以擦掉一个分区,并不需要非要烧写image到那个分区,也可以直接mount的,这样可以做实验验证ubi的性能,前提是kernel配置好了,mount正确了

(5) 如果是跟文件系统或者要手动mount,以下步骤供参考:

uboot里, mtd命令后,看到需要用ubifs的mtd分区的编号,比如

device nand0 <rda_nand>, # parts = 10
#: name size offset mask_flags
0: bootloader 0x00200000 0x00000000 0
1: boot 0x00800000 0x00800000 0
2: system 0x08000000 0x02000000 0

system分区mtd编号是2,命令如下:

nand erase.part system

命令行参数增加

ubi.mtd=2,如果有多个,可以增加,如ubi.mtd=2,ubi.mtd=1,这样传递后,内核启动后会做attach的操作,类似android的init中的attach那样,attach之后,/dev/下就建立好设备了,进入系统后用:

内核控制台里,mount -t ubifs /dev/ubi0_0 /mnt 即可mount
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: