Merge branch '2019-04-09-master-imports-fs'

- test.py tests for mmc
- ext4 symlink support and other fixes
- ext4 block group descriptor sizing
This commit is contained in:
Tom Rini 2019-04-10 08:18:18 -04:00
commit 48ff1bc4f0
20 changed files with 646 additions and 89 deletions

View File

@ -76,6 +76,20 @@ U_BOOT_CMD(
" device type 'interface' instance 'dev'."
)
static int do_ln_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
return do_ln(cmdtp, flag, argc, argv, FS_TYPE_ANY);
}
U_BOOT_CMD(
ln, 5, 1, do_ln_wrapper,
"Create a symbolic link",
"<interface> <dev[:part]> target linkname\n"
" - create a symbolic link to 'target' with the name 'linkname' on\n"
" device type 'interface' instance 'dev'."
)
static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{

2
env/ext4.c vendored
View File

@ -60,7 +60,7 @@ static int env_ext4_save(void)
}
err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new,
sizeof(env_t));
sizeof(env_t), FILETYPE_REG);
ext4fs_close();
if (err == -1) {

View File

@ -190,7 +190,7 @@ uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
return res;
}
void put_ext4(uint64_t off, void *buf, uint32_t size)
void put_ext4(uint64_t off, const void *buf, uint32_t size)
{
uint64_t startblock;
uint64_t remainder;
@ -510,7 +510,8 @@ restart:
restart_read:
/* read the block no allocated to a file */
first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx,
NULL);
if (first_block_no_of_root <= 0)
goto fail;
@ -607,7 +608,7 @@ restart_read:
dir->direntlen = cpu_to_le16(fs->blksz - totalbytes);
dir->namelen = strlen(filename);
dir->filetype = FILETYPE_REG; /* regular file */
dir->filetype = file_type;
temp_dir = (char *)dir;
temp_dir = temp_dir + sizeof(struct ext2_dirent);
memcpy(temp_dir, filename, strlen(filename));
@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname)
/* get the block no allocated to a file */
for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
blknr = read_allocated_block(parent_inode, blk_idx);
blknr = read_allocated_block(parent_inode, blk_idx, NULL);
if (blknr <= 0)
goto fail;
@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename)
/* read the block no allocated to a file */
for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
blknr = read_allocated_block(g_parent_inode, blk_idx);
blknr = read_allocated_block(g_parent_inode, blk_idx, NULL);
if (blknr <= 0)
break;
inodeno = unlink_filename(filename, blknr);
@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
#endif
static struct ext4_extent_header *ext4fs_get_extent_block
(struct ext2_data *data, char *buf,
(struct ext2_data *data, struct ext_block_cache *cache,
struct ext4_extent_header *ext_block,
uint32_t fileblock, int log2_blksz)
{
@ -1546,17 +1547,19 @@ static struct ext4_extent_header *ext4fs_get_extent_block
break;
} while (fileblock >= le32_to_cpu(index[i].ei_block));
if (--i < 0)
return NULL;
/*
* If first logical block number is higher than requested fileblock,
* it is a sparse file. This is handled on upper layer.
*/
if (i > 0)
i--;
block = le16_to_cpu(index[i].ei_leaf_hi);
block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
buf))
ext_block = (struct ext4_extent_header *)buf;
else
block <<= log2_blksz;
if (!ext_cache_read(cache, (lbaint_t)block, blksz))
return NULL;
ext_block = (struct ext4_extent_header *)cache->buf;
}
}
@ -1584,7 +1587,7 @@ static int ext4fs_blockgroup
int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
{
struct ext2_block_group blkgrp;
struct ext2_block_group *blkgrp;
struct ext2_sblock *sblock = &data->sblock;
struct ext_filesystem *fs = get_fs();
int log2blksz = get_fs()->dev_desc->log2blksz;
@ -1592,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
long int blkno;
unsigned int blkoff;
/* Allocate blkgrp based on gdsize (for 64-bit support). */
blkgrp = zalloc(get_fs()->gdsize);
if (!blkgrp)
return 0;
/* It is easier to calculate if the first inode is 0. */
ino--;
status = ext4fs_blockgroup(data, ino / le32_to_cpu
(sblock->inodes_per_group), &blkgrp);
if (status == 0)
(sblock->inodes_per_group), blkgrp);
if (status == 0) {
free(blkgrp);
return 0;
}
inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) +
blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) +
(ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
blkoff = (ino % inodes_per_block) * fs->inodesz;
/* Free blkgrp as it is no longer required. */
free(blkgrp);
/* Read the inode. */
status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
log2blksz), blkoff,
@ -1613,7 +1627,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
return 1;
}
long int read_allocated_block(struct ext2_inode *inode, int fileblock)
long int read_allocated_block(struct ext2_inode *inode, int fileblock,
struct ext_block_cache *cache)
{
long int blknr;
int blksz;
@ -1630,20 +1645,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
long int startblock, endblock;
char *buf = zalloc(blksz);
if (!buf)
return -ENOMEM;
struct ext_block_cache *c, cd;
struct ext4_extent_header *ext_block;
struct ext4_extent *extent;
int i;
if (cache) {
c = cache;
} else {
c = &cd;
ext_cache_init(c);
}
ext_block =
ext4fs_get_extent_block(ext4fs_root, buf,
ext4fs_get_extent_block(ext4fs_root, c,
(struct ext4_extent_header *)
inode->b.blocks.dir_blocks,
fileblock, log2_blksz);
if (!ext_block) {
printf("invalid extent block\n");
free(buf);
if (!cache)
ext_cache_fini(c);
return -EINVAL;
}
@ -1655,19 +1676,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
if (startblock > fileblock) {
/* Sparse file */
free(buf);
if (!cache)
ext_cache_fini(c);
return 0;
} else if (fileblock < endblock) {
start = le16_to_cpu(extent[i].ee_start_hi);
start = (start << 32) +
le32_to_cpu(extent[i].ee_start_lo);
free(buf);
if (!cache)
ext_cache_fini(c);
return (fileblock - startblock) + start;
}
}
free(buf);
if (!cache)
ext_cache_fini(c);
return 0;
}

View File

@ -72,7 +72,7 @@ int ext4fs_iget(int inode_no, struct ext2_inode *inode);
void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
unsigned int total_remaining_blocks,
unsigned int *total_no_of_block);
void put_ext4(uint64_t off, void *buf, uint32_t size);
void put_ext4(uint64_t off, const void *buf, uint32_t size);
struct ext2_block_group *ext4fs_get_group_descriptor
(const struct ext_filesystem *fs, uint32_t bg_idx);
uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,

View File

@ -347,7 +347,7 @@ void recover_transaction(int prev_desc_logical_no)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
(struct ext2_inode *)&inode_journal);
blknr = read_allocated_block((struct ext2_inode *)
&inode_journal, i);
&inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
p_jdb = (char *)temp_buff;
@ -372,7 +372,7 @@ void recover_transaction(int prev_desc_logical_no)
be32_to_cpu(jdb->h_sequence)) == 0)
continue;
}
blknr = read_allocated_block(&inode_journal, i);
blknr = read_allocated_block(&inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
fs->blksz, metadata_buff);
put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
@ -419,7 +419,8 @@ int ext4fs_check_journal_state(int recovery_flag)
}
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@ -443,7 +444,7 @@ int ext4fs_check_journal_state(int recovery_flag)
i = be32_to_cpu(jsb->s_first);
while (1) {
blknr = read_allocated_block(&inode_journal, i);
blknr = read_allocated_block(&inode_journal, i, NULL);
memset(temp_buff1, '\0', fs->blksz);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
0, fs->blksz, temp_buff1);
@ -537,7 +538,7 @@ end:
ext4_read_superblock((char *)fs->sb);
blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK);
EXT2_JOURNAL_SUPERBLOCK, NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
(struct journal_superblock_t *)temp_buff,
(uint32_t) fs->blksz);
@ -566,7 +567,7 @@ static void update_descriptor_block(long int blknr)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK);
EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@ -618,7 +619,7 @@ static void update_commit_block(long int blknr)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
&inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK);
EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@ -645,16 +646,17 @@ void ext4fs_update_journal(void)
long int blknr;
int i;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_descriptor_block(blknr);
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
journal_ptr[i]->buf, fs->blksz);
}
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_commit_block(blknr);
printf("update journal finished\n");
}

View File

@ -465,6 +465,15 @@ static int ext4fs_delete_file(int inodeno)
if (le32_to_cpu(inode.size) % fs->blksz)
no_blocks++;
/*
* special case for symlinks whose target are small enough that
*it fits in struct ext2_inode.b.symlink: no block had been allocated
*/
if ((le16_to_cpu(inode.mode) & S_IFLNK) &&
le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) {
no_blocks = 0;
}
if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
/* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
struct ext4_extent_header *eh =
@ -479,7 +488,7 @@ static int ext4fs_delete_file(int inodeno)
/* release data blocks */
for (i = 0; i < no_blocks; i++) {
blknr = read_allocated_block(&inode, i);
blknr = read_allocated_block(&inode, i, NULL);
if (blknr == 0)
continue;
if (blknr < 0)
@ -695,7 +704,7 @@ void ext4fs_deinit(void)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
&inode_journal);
blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK);
EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *)temp_buff;
@ -752,7 +761,7 @@ void ext4fs_deinit(void)
* contigous sectors as ext4fs_read_file
*/
static int ext4fs_write_file(struct ext2_inode *file_inode,
int pos, unsigned int len, char *buf)
int pos, unsigned int len, const char *buf)
{
int i;
int blockcnt;
@ -764,7 +773,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
int delayed_start = 0;
int delayed_extent = 0;
int delayed_next = 0;
char *delayed_buf = NULL;
const char *delayed_buf = NULL;
/* Adjust len so it we can't read past the end of the file. */
if (len > filesize)
@ -776,7 +785,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
long int blknr;
int blockend = fs->blksz;
int skipfirst = 0;
blknr = read_allocated_block(file_inode, i);
blknr = read_allocated_block(file_inode, i, NULL);
if (blknr <= 0)
return -1;
@ -816,7 +825,6 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
(uint32_t) delayed_extent);
previous_block_number = -1;
}
memset(buf, 0, fs->blksz - skipfirst);
}
buf += fs->blksz - skipfirst;
}
@ -830,8 +838,8 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
return len;
}
int ext4fs_write(const char *fname, unsigned char *buffer,
unsigned long sizebytes)
int ext4fs_write(const char *fname, const char *buffer,
unsigned long sizebytes, int type)
{
int ret = 0;
struct ext2_inode *file_inode = NULL;
@ -854,8 +862,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
struct ext2_block_group *bgd = NULL;
struct ext_filesystem *fs = get_fs();
ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
bool store_link_in_inode = false;
memset(filename, 0x00, 256);
if (type != FILETYPE_REG && type != FILETYPE_SYMLINK)
return -1;
g_parent_inode = zalloc(fs->inodesz);
if (!g_parent_inode)
goto fail;
@ -893,8 +905,16 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (ret)
goto fail;
}
/* calucalate how many blocks required */
bytes_reqd_for_file = sizebytes;
/* calculate how many blocks required */
if (type == FILETYPE_SYMLINK &&
sizebytes <= sizeof(file_inode->b.symlink)) {
store_link_in_inode = true;
bytes_reqd_for_file = 0;
} else {
bytes_reqd_for_file = sizebytes;
}
blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
blks_reqd_for_file++;
@ -907,7 +927,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
goto fail;
}
inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
inodeno = ext4fs_update_parent_dentry(filename, type);
if (inodeno == -1)
goto fail;
/* prepare file inode */
@ -915,14 +935,23 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (!inode_buffer)
goto fail;
file_inode = (struct ext2_inode *)inode_buffer;
file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
file_inode->size = cpu_to_le32(sizebytes);
if (type == FILETYPE_SYMLINK) {
file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG |
S_IRWXO);
if (store_link_in_inode) {
strncpy(file_inode->b.symlink, buffer, sizebytes);
sizebytes = 0;
}
} else {
file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP |
S_IROTH | S_IXGRP | S_IXOTH);
}
/* ToDo: Update correct time */
file_inode->mtime = cpu_to_le32(timestamp);
file_inode->atime = cpu_to_le32(timestamp);
file_inode->ctime = cpu_to_le32(timestamp);
file_inode->nlinks = cpu_to_le16(1);
file_inode->size = cpu_to_le32(sizebytes);
/* Allocate data blocks */
ext4fs_allocate_blocks(file_inode, blocks_remaining,
@ -949,7 +978,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (ext4fs_put_metadata(temp_ptr, itable_blkno))
goto fail;
/* copy the file content into data blocks */
if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) {
printf("Error in copying content\n");
/* FIXME: Deallocate data blocks */
goto fail;
@ -1014,7 +1043,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset,
return -1;
}
ret = ext4fs_write(filename, buf, len);
ret = ext4fs_write(filename, buf, len, FILETYPE_REG);
if (ret) {
printf("** Error ext4fs_write() **\n");
goto fail;
@ -1029,3 +1058,8 @@ fail:
return -1;
}
int ext4fs_create_link(const char *target, const char *fname)
{
return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK);
}

View File

@ -62,6 +62,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
lbaint_t delayed_next = 0;
char *delayed_buf = NULL;
short status;
struct ext_block_cache cache;
ext_cache_init(&cache);
if (blocksize <= 0)
return -1;
@ -77,9 +80,11 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
int blockoff = pos - (blocksize * i);
int blockend = blocksize;
int skipfirst = 0;
blknr = read_allocated_block(&(node->inode), i);
if (blknr < 0)
blknr = read_allocated_block(&node->inode, i, &cache);
if (blknr < 0) {
ext_cache_fini(&cache);
return -1;
}
blknr = blknr << log2_fs_blocksize;
@ -109,8 +114,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_skipfirst,
delayed_extent,
delayed_buf);
if (status == 0)
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = blknr;
delayed_start = blknr;
delayed_extent = blockend;
@ -136,8 +143,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_skipfirst,
delayed_extent,
delayed_buf);
if (status == 0)
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = -1;
}
/* Zero no more than `len' bytes. */
@ -153,12 +162,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
status = ext4fs_devread(delayed_start,
delayed_skipfirst, delayed_extent,
delayed_buf);
if (status == 0)
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = -1;
}
*actread = len;
ext_cache_fini(&cache);
return 0;
}
@ -252,3 +264,32 @@ int ext4fs_uuid(char *uuid_str)
return -ENOSYS;
#endif
}
void ext_cache_init(struct ext_block_cache *cache)
{
memset(cache, 0, sizeof(*cache));
}
void ext_cache_fini(struct ext_block_cache *cache)
{
free(cache->buf);
ext_cache_init(cache);
}
int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
{
/* This could be more lenient, but this is simple and enough for now */
if (cache->buf && cache->block == block && cache->size == size)
return 1;
ext_cache_fini(cache);
cache->buf = malloc(size);
if (!cache->buf)
return 0;
if (!ext4fs_devread(block, 0, size, cache->buf)) {
free(cache->buf);
return 0;
}
cache->block = block;
cache->size = size;
return 1;
}

View File

@ -602,8 +602,13 @@ static int get_fs_info(fsdata *mydata)
mydata->data_begin = mydata->rootdir_sect +
mydata->rootdir_size -
(mydata->clust_size * 2);
mydata->root_cluster =
sect_to_clust(mydata, mydata->rootdir_sect);
/*
* The root directory is not cluster-aligned and may be on a
* "negative" cluster, this will be handled specially in
* next_cluster().
*/
mydata->root_cluster = 0;
}
mydata->fatbufnum = -1;
@ -733,20 +738,38 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent)
itr->last_cluster = 0;
}
static void *next_cluster(fat_itr *itr)
static void *next_cluster(fat_itr *itr, unsigned *nbytes)
{
fsdata *mydata = itr->fsdata; /* for silly macros */
int ret;
u32 sect;
u32 read_size;
/* have we reached the end? */
if (itr->last_cluster)
return NULL;
sect = clust_to_sect(itr->fsdata, itr->next_clust);
if (itr->is_root && itr->fsdata->fatsize != 32) {
/*
* The root directory is located before the data area and
* cannot be indexed using the regular unsigned cluster
* numbers (it may start at a "negative" cluster or not at a
* cluster boundary at all), so consider itr->next_clust to be
* a offset in cluster-sized units from the start of rootdir.
*/
unsigned sect_offset = itr->next_clust * itr->fsdata->clust_size;
unsigned remaining_sects = itr->fsdata->rootdir_size - sect_offset;
sect = itr->fsdata->rootdir_sect + sect_offset;
/* do not read past the end of rootdir */
read_size = min_t(u32, itr->fsdata->clust_size,
remaining_sects);
} else {
sect = clust_to_sect(itr->fsdata, itr->next_clust);
read_size = itr->fsdata->clust_size;
}
debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
sect, itr->fsdata->clust_size, DIRENTSPERBLOCK);
debug("FAT read(sect=%d), clust_size=%d, read_size=%u, DIRENTSPERBLOCK=%zd\n",
sect, itr->fsdata->clust_size, read_size, DIRENTSPERBLOCK);
/*
* NOTE: do_fat_read_at() had complicated logic to deal w/
@ -757,18 +780,17 @@ static void *next_cluster(fat_itr *itr)
* dent at a time and iteratively constructing the vfat long
* name.
*/
ret = disk_read(sect, itr->fsdata->clust_size,
itr->block);
ret = disk_read(sect, read_size, itr->block);
if (ret < 0) {
debug("Error: reading block\n");
return NULL;
}
*nbytes = read_size * itr->fsdata->sect_size;
itr->clust = itr->next_clust;
if (itr->is_root && itr->fsdata->fatsize != 32) {
itr->next_clust++;
sect = clust_to_sect(itr->fsdata, itr->next_clust);
if (sect - itr->fsdata->rootdir_sect >=
if (itr->next_clust * itr->fsdata->clust_size >=
itr->fsdata->rootdir_size) {
debug("nextclust: 0x%x\n", itr->next_clust);
itr->last_cluster = 1;
@ -787,9 +809,8 @@ static void *next_cluster(fat_itr *itr)
static dir_entry *next_dent(fat_itr *itr)
{
if (itr->remaining == 0) {
struct dir_entry *dent = next_cluster(itr);
unsigned nbytes = itr->fsdata->sect_size *
itr->fsdata->clust_size;
unsigned nbytes;
struct dir_entry *dent = next_cluster(itr, &nbytes);
/* have we reached the last cluster? */
if (!dent) {

44
fs/fs.c
View File

@ -90,6 +90,11 @@ static inline int fs_write_unsupported(const char *filename, void *buf,
return -1;
}
static inline int fs_ln_unsupported(const char *filename, const char *target)
{
return -1;
}
static inline void fs_close_unsupported(void)
{
}
@ -154,6 +159,7 @@ struct fstype_info {
void (*closedir)(struct fs_dir_stream *dirs);
int (*unlink)(const char *filename);
int (*mkdir)(const char *dirname);
int (*ln)(const char *filename, const char *target);
};
static struct fstype_info fstypes[] = {
@ -181,6 +187,7 @@ static struct fstype_info fstypes[] = {
.opendir = fat_opendir,
.readdir = fat_readdir,
.closedir = fat_closedir,
.ln = fs_ln_unsupported,
},
#endif
@ -197,8 +204,10 @@ static struct fstype_info fstypes[] = {
.read = ext4_read_file,
#ifdef CONFIG_CMD_EXT4_WRITE
.write = ext4_write_file,
.ln = ext4fs_create_link,
#else
.write = fs_write_unsupported,
.ln = fs_ln_unsupported,
#endif
.uuid = ext4fs_uuid,
.opendir = fs_opendir_unsupported,
@ -222,6 +231,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
.ln = fs_ln_unsupported,
},
#endif
#ifdef CONFIG_CMD_UBIFS
@ -240,6 +250,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
.ln = fs_ln_unsupported,
},
#endif
#ifdef CONFIG_FS_BTRFS
@ -258,6 +269,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
.ln = fs_ln_unsupported,
},
#endif
{
@ -275,6 +287,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
.ln = fs_ln_unsupported,
},
};
@ -602,6 +615,22 @@ int fs_mkdir(const char *dirname)
return ret;
}
int fs_ln(const char *fname, const char *target)
{
struct fstype_info *info = fs_get_info(fs_type);
int ret;
ret = info->ln(fname, target);
if (ret < 0) {
printf("** Unable to create link %s -> %s **\n", fname, target);
ret = -1;
}
fs_close();
return ret;
}
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
@ -840,3 +869,18 @@ int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
return 0;
}
int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
if (argc != 5)
return CMD_RET_USAGE;
if (fs_set_blk_dev(argv[1], argv[2], fstype))
return 1;
if (fs_ln(argv[3], argv[4]))
return 1;
return 0;
}

View File

@ -117,6 +117,12 @@ struct ext_filesystem {
struct blk_desc *dev_desc;
};
struct ext_block_cache {
char *buf;
lbaint_t block;
int size;
};
extern struct ext2_data *ext4fs_root;
extern struct ext2fs_node *ext4fs_file;
@ -128,10 +134,11 @@ extern int gindex;
int ext4fs_init(void);
void ext4fs_deinit(void);
int ext4fs_filename_unlink(char *filename);
int ext4fs_write(const char *fname, unsigned char *buffer,
unsigned long sizebytes);
int ext4fs_write(const char *fname, const char *buffer,
unsigned long sizebytes, int type);
int ext4_write_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actwrite);
int ext4fs_create_link(const char *target, const char *fname);
#endif
struct ext_filesystem *get_fs(void);
@ -146,11 +153,15 @@ int ext4fs_size(const char *filename, loff_t *size);
void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len, char *buf);
void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info);
long int read_allocated_block(struct ext2_inode *inode, int fileblock);
long int read_allocated_block(struct ext2_inode *inode, int fileblock,
struct ext_block_cache *cache);
int ext4fs_probe(struct blk_desc *fs_dev_desc,
disk_partition_t *fs_partition);
int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actread);
int ext4_read_superblock(char *buffer);
int ext4fs_uuid(char *uuid_str);
void ext_cache_init(struct ext_block_cache *cache);
void ext_cache_fini(struct ext_block_cache *cache);
int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size);
#endif

View File

@ -191,6 +191,8 @@ int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
/*
* Determine the UUID of the specified filesystem and print it. Optionally it is

View File

@ -13,6 +13,7 @@ supported_fs_basic = ['fat16', 'fat32', 'ext4']
supported_fs_ext = ['fat16', 'fat32']
supported_fs_mkdir = ['fat16', 'fat32']
supported_fs_unlink = ['fat16', 'fat32']
supported_fs_symlink = ['ext4']
#
# Filesystem test specific setup
@ -48,6 +49,7 @@ def pytest_configure(config):
global supported_fs_ext
global supported_fs_mkdir
global supported_fs_unlink
global supported_fs_symlink
def intersect(listA, listB):
return [x for x in listA if x in listB]
@ -59,6 +61,7 @@ def pytest_configure(config):
supported_fs_ext = intersect(supported_fs, supported_fs_ext)
supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir)
supported_fs_unlink = intersect(supported_fs, supported_fs_unlink)
supported_fs_symlink = intersect(supported_fs, supported_fs_symlink)
def pytest_generate_tests(metafunc):
"""Parametrize fixtures, fs_obj_xxx
@ -84,6 +87,9 @@ def pytest_generate_tests(metafunc):
if 'fs_obj_unlink' in metafunc.fixturenames:
metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
indirect=True, scope='module')
if 'fs_obj_symlink' in metafunc.fixturenames:
metafunc.parametrize('fs_obj_symlink', supported_fs_symlink,
indirect=True, scope='module')
#
# Helper functions
@ -143,6 +149,8 @@ def mk_fs(config, fs_type, size, id):
mkfs_opt = '-F 16'
elif fs_type == 'fat32':
mkfs_opt = '-F 32'
elif fs_type == 'ext4':
mkfs_opt = '-O ^metadata_csum'
else:
mkfs_opt = ''
@ -523,3 +531,72 @@ def fs_obj_unlink(request, u_boot_config):
call('rmdir %s' % mount_dir, shell=True)
if fs_img:
call('rm -f %s' % fs_img, shell=True)
#
# Fixture for symlink fs test
#
# NOTE: yield_fixture was deprecated since pytest-3.0
@pytest.yield_fixture()
def fs_obj_symlink(request, u_boot_config):
"""Set up a file system to be used in symlink fs test.
Args:
request: Pytest request object.
u_boot_config: U-boot configuration.
Return:
A fixture for basic fs test, i.e. a triplet of file system type,
volume file name and a list of MD5 hashes.
"""
fs_type = request.param
fs_img = ''
fs_ubtype = fstype_to_ubname(fs_type)
check_ubconfig(u_boot_config, fs_ubtype)
mount_dir = u_boot_config.persistent_data_dir + '/mnt'
small_file = mount_dir + '/' + SMALL_FILE
medium_file = mount_dir + '/' + MEDIUM_FILE
try:
# 3GiB volume
fs_img = mk_fs(u_boot_config, fs_type, 0x40000000, '1GB')
# Mount the image so we can populate it.
check_call('mkdir -p %s' % mount_dir, shell=True)
mount_fs(fs_type, fs_img, mount_dir)
# Create a subdirectory.
check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
# Create a small file in this image.
check_call('dd if=/dev/urandom of=%s bs=1M count=1'
% small_file, shell=True)
# Create a medium file in this image.
check_call('dd if=/dev/urandom of=%s bs=10M count=1'
% medium_file, shell=True)
# Generate the md5sums of reads that we will test against small file
out = check_output(
'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
% small_file, shell=True)
md5val = [out.split()[0]]
out = check_output(
'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum'
% medium_file, shell=True)
md5val.extend([out.split()[0]])
umount_fs(mount_dir)
except CalledProcessError:
pytest.skip('Setup failed for filesystem: ' + fs_type)
return
else:
yield [fs_ubtype, fs_img, md5val]
finally:
umount_fs(mount_dir)
call('rmdir %s' % mount_dir, shell=True)
if fs_img:
call('rm -f %s' % fs_img, shell=True)

View File

@ -6,6 +6,9 @@ MIN_FILE='testfile'
# $SMALL_FILE is the name of the 1MB file in the file system image
SMALL_FILE='1MB.file'
# $MEDIUM_FILE is the name of the 10MB file in the file system image
MEDIUM_FILE='10MB.file'
# $BIG_FILE is the name of the 2.5GB file in the file system image
BIG_FILE='2.5GB.file'

View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2019, Texas Instrument
# Author: JJ Hiblot <jjhiblot@ti.com>
#
from subprocess import check_call, CalledProcessError
def assert_fs_integrity(fs_type, fs_img):
try:
if fs_type == 'ext4':
check_call('fsck.ext4 -n -f %s' % fs_img, shell=True)
except CalledProcessError:
raise

View File

@ -11,6 +11,7 @@ This test verifies basic read/write operation on file system.
import pytest
import re
from fstest_defs import *
from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@ -237,6 +238,7 @@ class TestFsBasic(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs12(self, u_boot_console, fs_obj_basic):
"""
@ -252,6 +254,7 @@ class TestFsBasic(object):
'host bind 0 %s' % fs_img,
'%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)])
assert('Unable to write' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs13(self, u_boot_console, fs_obj_basic):
"""
@ -286,3 +289,4 @@ class TestFsBasic(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)

View File

@ -11,6 +11,7 @@ This test verifies extended write operation on file system.
import pytest
import re
from fstest_defs import *
from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@ -36,6 +37,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext2(self, u_boot_console, fs_obj_ext):
"""
@ -58,6 +60,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext3(self, u_boot_console, fs_obj_ext):
"""
@ -72,6 +75,7 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/none/%s.w3 $filesize'
% (fs_type, ADDR, MIN_FILE)])
assert('Unable to write "/dir1/none/' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext4(self, u_boot_console, fs_obj_ext):
"""
@ -104,6 +108,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[1] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext5(self, u_boot_console, fs_obj_ext):
"""
@ -136,6 +141,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[2] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext6(self, u_boot_console, fs_obj_ext):
"""
@ -160,6 +166,7 @@ class TestFsExt(object):
'printenv filesize',
'setenv filesize'])
assert('filesize=0' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext7(self, u_boot_console, fs_obj_ext):
"""
@ -192,6 +199,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[3] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext8(self, u_boot_console, fs_obj_ext):
"""
@ -209,6 +217,7 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x'
% (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400))
assert('Unable to write "/dir1' in output)
assert_fs_integrity(fs_type, fs_img)
def test_fs_ext9(self, u_boot_console, fs_obj_ext):
"""
@ -223,3 +232,4 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400'
% (fs_type, ADDR, MIN_FILE)])
assert('Unable to write "/dir1' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)

View File

@ -9,6 +9,7 @@ This test verifies mkdir operation on file system.
"""
import pytest
from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@ -29,6 +30,8 @@ class TestMkdir(object):
'%sls host 0:0 dir1' % fs_type)
assert('./' in output)
assert('../' in output)
assert_fs_integrity(fs_type, fs_img)
def test_mkdir2(self, u_boot_console, fs_obj_mkdir):
"""
@ -46,6 +49,7 @@ class TestMkdir(object):
'%sls host 0:0 dir1/dir2' % fs_type)
assert('./' in output)
assert('../' in output)
assert_fs_integrity(fs_type, fs_img)
def test_mkdir3(self, u_boot_console, fs_obj_mkdir):
"""
@ -58,6 +62,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 none/dir3' % fs_type])
assert('Unable to create a directory' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_mkdir4(self, u_boot_console, fs_obj_mkdir):
"""
@ -69,6 +74,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 .' % fs_type])
assert('Unable to create a directory' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_mkdir5(self, u_boot_console, fs_obj_mkdir):
"""
@ -80,6 +86,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 ..' % fs_type])
assert('Unable to create a directory' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_mkdir6(self, u_boot_console, fs_obj_mkdir):
"""
@ -111,3 +118,4 @@ class TestMkdir(object):
'%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type)
assert('0123456789abcdef00/' in output)
assert('0123456789abcdef13/' in output)
assert_fs_integrity(fs_type, fs_img)

View File

@ -0,0 +1,130 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2019, Texas Instrument
# Author: Jean-Jacques Hiblot <jjhiblot@ti.com>
#
# U-Boot File System:symlink Test
"""
This test verifies unlink operation (deleting a file or a directory)
on file system.
"""
import pytest
import re
from fstest_defs import *
from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
class TestSymlink(object):
def test_symlink1(self, u_boot_console, fs_obj_symlink):
"""
Test Case 1 - create a link. and follow it when reading
"""
fs_type, fs_img, md5val = fs_obj_symlink
with u_boot_console.log.section('Test Case 1 - create link and read'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % fs_img,
'setenv filesize',
'ln host 0:0 %s /%s.link ' % (SMALL_FILE, SMALL_FILE),
])
assert('' in ''.join(output))
output = u_boot_console.run_command_list([
'%sload host 0:0 %x /%s.link' % (fs_type, ADDR, SMALL_FILE),
'printenv filesize'])
assert('filesize=100000' in ''.join(output))
# Test Case 4b - Read full 1MB of small file
output = u_boot_console.run_command_list([
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_symlink2(self, u_boot_console, fs_obj_symlink):
"""
Test Case 2 - create chained links
"""
fs_type, fs_img, md5val = fs_obj_symlink
with u_boot_console.log.section('Test Case 2 - create chained links'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % fs_img,
'setenv filesize',
'ln host 0:0 %s /%s.link1 ' % (SMALL_FILE, SMALL_FILE),
'ln host 0:0 /%s.link1 /SUBDIR/%s.link2' % (
SMALL_FILE, SMALL_FILE),
'ln host 0:0 SUBDIR/%s.link2 /%s.link3' % (
SMALL_FILE, SMALL_FILE),
])
assert('' in ''.join(output))
output = u_boot_console.run_command_list([
'%sload host 0:0 %x /%s.link3' % (fs_type, ADDR, SMALL_FILE),
'printenv filesize'])
assert('filesize=100000' in ''.join(output))
# Test Case 4b - Read full 1MB of small file
output = u_boot_console.run_command_list([
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_symlink3(self, u_boot_console, fs_obj_symlink):
"""
Test Case 3 - replace file/link with link
"""
fs_type, fs_img, md5val = fs_obj_symlink
with u_boot_console.log.section('Test Case 1 - create link and read'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % fs_img,
'setenv filesize',
'ln host 0:0 %s /%s ' % (MEDIUM_FILE, SMALL_FILE),
'ln host 0:0 %s /%s.link ' % (MEDIUM_FILE, MEDIUM_FILE),
])
assert('' in ''.join(output))
output = u_boot_console.run_command_list([
'%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
'printenv filesize'])
assert('filesize=a00000' in ''.join(output))
output = u_boot_console.run_command_list([
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[1] in ''.join(output))
output = u_boot_console.run_command_list([
'ln host 0:0 %s.link /%s ' % (MEDIUM_FILE, SMALL_FILE),
'%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
'printenv filesize'])
assert('filesize=a00000' in ''.join(output))
output = u_boot_console.run_command_list([
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[1] in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_symlink4(self, u_boot_console, fs_obj_symlink):
"""
Test Case 4 - create a broken link
"""
fs_type, fs_img, md5val = fs_obj_symlink
with u_boot_console.log.section('Test Case 1 - create link and read'):
output = u_boot_console.run_command_list([
'setenv filesize',
'ln host 0:0 nowhere /link ',
])
assert('' in ''.join(output))
output = u_boot_console.run_command(
'%sload host 0:0 %x /link' %
(fs_type, ADDR))
with u_boot_console.disable_check('error_notification'):
output = u_boot_console.run_command('printenv filesize')
assert('"filesize" not defined' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)

View File

@ -10,6 +10,7 @@ on file system.
"""
import pytest
from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@ -30,6 +31,7 @@ class TestUnlink(object):
'%sls host 0:0 dir1/' % fs_type)
assert(not 'file1' in output)
assert('file2' in output)
assert_fs_integrity(fs_type, fs_img)
def test_unlink2(self, u_boot_console, fs_obj_unlink):
"""
@ -48,6 +50,7 @@ class TestUnlink(object):
output = u_boot_console.run_command(
'%sls host 0:0 dir2' % fs_type)
assert('0 file(s), 2 dir(s)' in output)
assert_fs_integrity(fs_type, fs_img)
def test_unlink3(self, u_boot_console, fs_obj_unlink):
"""
@ -59,6 +62,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir1/nofile' % fs_type])
assert('nofile: doesn\'t exist' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_unlink4(self, u_boot_console, fs_obj_unlink):
"""
@ -71,9 +75,10 @@ class TestUnlink(object):
'%srm host 0:0 dir4' % fs_type])
assert('' == ''.join(output))
output = u_boot_console.run_command(
'%sls host 0:0 /' % fs_type)
assert(not 'dir4' in output)
output = u_boot_console.run_command(
'%sls host 0:0 /' % fs_type)
assert(not 'dir4' in output)
assert_fs_integrity(fs_type, fs_img)
def test_unlink5(self, u_boot_console, fs_obj_unlink):
"""
@ -86,6 +91,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5' % fs_type])
assert('directory is not empty' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_unlink6(self, u_boot_console, fs_obj_unlink):
"""
@ -97,6 +103,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5/.' % fs_type])
assert('directory is not empty' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)
def test_unlink7(self, u_boot_console, fs_obj_unlink):
"""
@ -108,3 +115,4 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5/..' % fs_type])
assert('directory is not empty' in ''.join(output))
assert_fs_integrity(fs_type, fs_img)

View File

@ -6,6 +6,7 @@
# read if the test configuration contains a CRC of the expected data.
import pytest
import time
import u_boot_utils
"""
@ -57,6 +58,116 @@ env__mmc_rd_configs = (
)
"""
def mmc_dev(u_boot_console, is_emmc, devid, partid):
"""Run the "mmc dev" command.
Args:
u_boot_console: A U-Boot console connection.
is_emmc: Whether the device is eMMC
devid: Device ID
partid: Partition ID
Returns:
Nothing.
"""
# Select MMC device
cmd = 'mmc dev %d' % devid
if is_emmc:
cmd += ' %d' % partid
response = u_boot_console.run_command(cmd)
assert 'no card present' not in response
if is_emmc:
partid_response = '(part %d)' % partid
else:
partid_response = ''
good_response = 'mmc%d%s is current device' % (devid, partid_response)
assert good_response in response
@pytest.mark.buildconfigspec('cmd_mmc')
def test_mmc_dev(u_boot_console, env__mmc_rd_config):
"""Test the "mmc dev" command.
Args:
u_boot_console: A U-Boot console connection.
env__mmc_rd_config: The single MMC configuration on which
to run the test. See the file-level comment above for details
of the format.
Returns:
Nothing.
"""
is_emmc = env__mmc_rd_config['is_emmc']
devid = env__mmc_rd_config['devid']
partid = env__mmc_rd_config.get('partid', 0)
# Select MMC device
mmc_dev(u_boot_console, is_emmc, devid, partid)
@pytest.mark.buildconfigspec('cmd_mmc')
def test_mmc_rescan(u_boot_console, env__mmc_rd_config):
"""Test the "mmc rescan" command.
Args:
u_boot_console: A U-Boot console connection.
env__mmc_rd_config: The single MMC configuration on which
to run the test. See the file-level comment above for details
of the format.
Returns:
Nothing.
"""
is_emmc = env__mmc_rd_config['is_emmc']
devid = env__mmc_rd_config['devid']
partid = env__mmc_rd_config.get('partid', 0)
# Select MMC device
mmc_dev(u_boot_console, is_emmc, devid, partid)
# Rescan MMC device
cmd = 'mmc rescan'
response = u_boot_console.run_command(cmd)
assert 'no card present' not in response
@pytest.mark.buildconfigspec('cmd_mmc')
def test_mmc_info(u_boot_console, env__mmc_rd_config):
"""Test the "mmc info" command.
Args:
u_boot_console: A U-Boot console connection.
env__mmc_rd_config: The single MMC configuration on which
to run the test. See the file-level comment above for details
of the format.
Returns:
Nothing.
"""
is_emmc = env__mmc_rd_config['is_emmc']
devid = env__mmc_rd_config['devid']
partid = env__mmc_rd_config.get('partid', 0)
info_device = env__mmc_rd_config['info_device']
info_speed = env__mmc_rd_config['info_speed']
info_mode = env__mmc_rd_config['info_mode']
info_buswidth = env__mmc_rd_config['info_buswidth']
# Select MMC device
mmc_dev(u_boot_console, is_emmc, devid, partid)
# Read MMC device information
cmd = 'mmc info'
response = u_boot_console.run_command(cmd)
good_response = "Device: %s" % info_device
assert good_response in response
good_response = "Bus Speed: %s" % info_speed
assert good_response in response
good_response = "Mode : %s" % info_mode
assert good_response in response
good_response = "Bus Width: %s" % info_buswidth
assert good_response in response
@pytest.mark.buildconfigspec('cmd_mmc')
def test_mmc_rd(u_boot_console, env__mmc_rd_config):
"""Test the "mmc read" command.
@ -77,6 +188,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
sector = env__mmc_rd_config.get('sector', 0)
count_sectors = env__mmc_rd_config.get('count', 1)
expected_crc32 = env__mmc_rd_config.get('crc32', None)
read_duration_max = env__mmc_rd_config.get('read_duration_max', 0)
count_bytes = count_sectors * 512
bcfg = u_boot_console.config.buildconfig
@ -86,17 +198,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
addr = '0x%08x' % ram_base
# Select MMC device
cmd = 'mmc dev %d' % devid
if is_emmc:
cmd += ' %d' % partid
response = u_boot_console.run_command(cmd)
assert 'no card present' not in response
if is_emmc:
partid_response = '(part %d)' % partid
else:
partid_response = ''
good_response = 'mmc%d%s is current device' % (devid, partid_response)
assert good_response in response
mmc_dev(u_boot_console, is_emmc, devid, partid)
# Clear target RAM
if expected_crc32:
@ -113,7 +215,9 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
# Read data
cmd = 'mmc read %s %x %x' % (addr, sector, count_sectors)
tstart = time.time()
response = u_boot_console.run_command(cmd)
tend = time.time()
good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (
devid, sector, count_sectors, count_sectors)
assert good_response in response
@ -126,3 +230,10 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
assert expected_crc32 in response
else:
u_boot_console.log.warning('CONFIG_CMD_CRC32 != y: Skipping check')
# Check if the command did not take too long
if read_duration_max:
elapsed = tend - tstart
u_boot_console.log.info('Reading %d bytes took %f seconds' %
(count_bytes, elapsed))
assert elapsed <= (read_duration_max - 0.01)