Merge patch series "fs: exfat: Flush node before put in read() callback"
This series from Marek Vasut <marex@denx.de> includes a number of fixes to the exFAT filesystem support that he recently added. Link: https://lore.kernel.org/r/20250413085740.5953-1-marex@denx.de
This commit is contained in:
128
fs/exfat/io.c
128
fs/exfat/io.c
@@ -597,15 +597,13 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __UBOOT__
|
#ifdef __UBOOT__
|
||||||
|
#define PATH_MAX FS_DIRENT_NAME_LEN
|
||||||
|
|
||||||
struct exfat_dir_stream {
|
struct exfat_dir_stream {
|
||||||
|
char dirname[PATH_MAX];
|
||||||
struct fs_dir_stream fs_dirs;
|
struct fs_dir_stream fs_dirs;
|
||||||
struct fs_dirent dirent;
|
struct fs_dirent dirent;
|
||||||
|
int offset;
|
||||||
struct exfat_node* node;
|
|
||||||
struct exfat_iterator it;
|
|
||||||
/* State tracker flags for emulated . and .. dirents */
|
|
||||||
bool dot;
|
|
||||||
bool dotdot;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int exfat_fs_probe(struct blk_desc *fs_dev_desc,
|
int exfat_fs_probe(struct blk_desc *fs_dev_desc,
|
||||||
@@ -626,8 +624,6 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PATH_MAX FS_DIRENT_NAME_LEN
|
|
||||||
|
|
||||||
/* Adapted from uclibc 1.0.35 */
|
/* Adapted from uclibc 1.0.35 */
|
||||||
static char *exfat_realpath(const char *path, char got_path[])
|
static char *exfat_realpath(const char *path, char got_path[])
|
||||||
{
|
{
|
||||||
@@ -721,31 +717,31 @@ int exfat_lookup_realpath(struct exfat* ef, struct exfat_node** node,
|
|||||||
int exfat_fs_opendir(const char *filename, struct fs_dir_stream **dirsp)
|
int exfat_fs_opendir(const char *filename, struct fs_dir_stream **dirsp)
|
||||||
{
|
{
|
||||||
struct exfat_dir_stream *dirs;
|
struct exfat_dir_stream *dirs;
|
||||||
|
struct exfat_node *dnode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = exfat_lookup_realpath(&ctxt.ef, &dnode, filename);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!(dnode->attrib & EXFAT_ATTRIB_DIR))
|
||||||
|
err = -ENOTDIR;
|
||||||
|
|
||||||
|
exfat_put_node(&ctxt.ef, dnode);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
dirs = calloc(1, sizeof(*dirs));
|
dirs = calloc(1, sizeof(*dirs));
|
||||||
if (!dirs)
|
if (!dirs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = exfat_lookup_realpath(&ctxt.ef, &dirs->node, filename);
|
strcpy(dirs->dirname, filename);
|
||||||
if (err)
|
dirs->offset = -1;
|
||||||
goto err_out;
|
|
||||||
|
|
||||||
if (!(dirs->node->attrib & EXFAT_ATTRIB_DIR)) {
|
|
||||||
err = -ENOTDIR;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = exfat_opendir(&ctxt.ef, dirs->node, &dirs->it);
|
|
||||||
if (err)
|
|
||||||
goto err_out;
|
|
||||||
|
|
||||||
*dirsp = &dirs->fs_dirs;
|
*dirsp = &dirs->fs_dirs;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
|
||||||
free(dirs);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int exfat_fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
|
int exfat_fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
|
||||||
@@ -753,50 +749,77 @@ int exfat_fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
|
|||||||
struct exfat_dir_stream *dirs =
|
struct exfat_dir_stream *dirs =
|
||||||
container_of(fs_dirs, struct exfat_dir_stream, fs_dirs);
|
container_of(fs_dirs, struct exfat_dir_stream, fs_dirs);
|
||||||
struct fs_dirent *dent = &dirs->dirent;
|
struct fs_dirent *dent = &dirs->dirent;
|
||||||
struct exfat_node* node;
|
struct exfat_node *dnode, *node;
|
||||||
|
struct exfat_iterator it;
|
||||||
|
int offset = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = exfat_lookup_realpath(&ctxt.ef, &dnode, dirs->dirname);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!(dnode->attrib & EXFAT_ATTRIB_DIR)) {
|
||||||
|
err = -ENOTDIR;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Emulate current directory ./ */
|
/* Emulate current directory ./ */
|
||||||
if (!dirs->dot) {
|
if (dirs->offset == -1) {
|
||||||
dirs->dot = true;
|
dirs->offset++;
|
||||||
snprintf(dent->name, FS_DIRENT_NAME_LEN, ".");
|
snprintf(dent->name, FS_DIRENT_NAME_LEN, ".");
|
||||||
dent->type = FS_DT_DIR;
|
dent->type = FS_DT_DIR;
|
||||||
*dentp = dent;
|
*dentp = dent;
|
||||||
return 0;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Emulate parent directory ../ */
|
/* Emulate parent directory ../ */
|
||||||
if (!dirs->dotdot) {
|
if (dirs->offset == 0) {
|
||||||
dirs->dotdot = true;
|
dirs->offset++;
|
||||||
snprintf(dent->name, FS_DIRENT_NAME_LEN, "..");
|
snprintf(dent->name, FS_DIRENT_NAME_LEN, "..");
|
||||||
dent->type = FS_DT_DIR;
|
dent->type = FS_DT_DIR;
|
||||||
*dentp = dent;
|
*dentp = dent;
|
||||||
return 0;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = exfat_opendir(&ctxt.ef, dnode, &it);
|
||||||
|
if (err)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
*dentp = NULL;
|
||||||
|
|
||||||
/* Read actual directory content */
|
/* Read actual directory content */
|
||||||
node = exfat_readdir(&dirs->it);
|
while ((node = exfat_readdir(&it))) {
|
||||||
if (!node) { /* No more content, reset . and .. emulation */
|
if (dirs->offset != ++offset) {
|
||||||
dirs->dot = false;
|
exfat_put_node(&ctxt.ef, node);
|
||||||
dirs->dotdot = false;
|
continue;
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
|
exfat_get_name(node, dent->name);
|
||||||
|
if (node->attrib & EXFAT_ATTRIB_DIR) {
|
||||||
|
dent->type = FS_DT_DIR;
|
||||||
|
} else {
|
||||||
|
dent->type = FS_DT_REG;
|
||||||
|
dent->size = node->size;
|
||||||
|
}
|
||||||
|
exfat_put_node(&ctxt.ef, node);
|
||||||
|
*dentp = dent;
|
||||||
|
dirs->offset++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
exfat_get_name(node, dent->name);
|
exfat_closedir(&ctxt.ef, &it);
|
||||||
if (node->attrib & EXFAT_ATTRIB_DIR) {
|
|
||||||
dent->type = FS_DT_DIR;
|
|
||||||
} else {
|
|
||||||
dent->type = FS_DT_REG;
|
|
||||||
dent->size = node->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dentp = dent;
|
err_out:
|
||||||
|
exfat_put_node(&ctxt.ef, dnode);
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exfat_fs_closedir(struct fs_dir_stream *fs_dirs)
|
void exfat_fs_closedir(struct fs_dir_stream *fs_dirs)
|
||||||
{
|
{
|
||||||
free(fs_dirs);
|
struct exfat_dir_stream *dirs =
|
||||||
|
container_of(fs_dirs, struct exfat_dir_stream, fs_dirs);
|
||||||
|
|
||||||
|
free(dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exfat_fs_ls(const char *dirname)
|
int exfat_fs_ls(const char *dirname)
|
||||||
@@ -852,11 +875,11 @@ int exfat_fs_exists(const char *filename)
|
|||||||
|
|
||||||
err = exfat_lookup_realpath(&ctxt.ef, &node, filename);
|
err = exfat_lookup_realpath(&ctxt.ef, &node, filename);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return 0;
|
||||||
|
|
||||||
exfat_put_node(&ctxt.ef, node);
|
exfat_put_node(&ctxt.ef, node);
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exfat_fs_size(const char *filename, loff_t *size)
|
int exfat_fs_size(const char *filename, loff_t *size)
|
||||||
@@ -898,9 +921,7 @@ int exfat_fs_read(const char *filename, void *buf, loff_t offset, loff_t len,
|
|||||||
|
|
||||||
*actread = sz;
|
*actread = sz;
|
||||||
|
|
||||||
exfat_put_node(&ctxt.ef, node);
|
err = exfat_flush_node(&ctxt.ef, node);
|
||||||
|
|
||||||
return exfat_flush_node(&ctxt.ef, node);
|
|
||||||
exit:
|
exit:
|
||||||
exfat_put_node(&ctxt.ef, node);
|
exfat_put_node(&ctxt.ef, node);
|
||||||
return err;
|
return err;
|
||||||
@@ -992,6 +1013,11 @@ exit:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int exfat_fs_rename(const char *old_path, const char *new_path)
|
||||||
|
{
|
||||||
|
return exfat_rename(&ctxt.ef, old_path, new_path);
|
||||||
|
}
|
||||||
|
|
||||||
void exfat_fs_close(void)
|
void exfat_fs_close(void)
|
||||||
{
|
{
|
||||||
exfat_unmount(&ctxt.ef);
|
exfat_unmount(&ctxt.ef);
|
||||||
|
@@ -218,8 +218,9 @@ int exfat_split(struct exfat* ef, struct exfat_node** parent,
|
|||||||
exfat_put_node(ef, *parent);
|
exfat_put_node(ef, *parent);
|
||||||
*parent = *node;
|
*parent = *node;
|
||||||
}
|
}
|
||||||
|
#ifndef __UBOOT__
|
||||||
exfat_bug("impossible");
|
exfat_bug("impossible");
|
||||||
#ifdef __UBOOT__
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
1
fs/fs.c
1
fs/fs.c
@@ -401,6 +401,7 @@ static struct fstype_info fstypes[] = {
|
|||||||
.ln = fs_ln_unsupported,
|
.ln = fs_ln_unsupported,
|
||||||
.unlink = exfat_fs_unlink,
|
.unlink = exfat_fs_unlink,
|
||||||
.mkdir = exfat_fs_mkdir,
|
.mkdir = exfat_fs_mkdir,
|
||||||
|
.rename = exfat_fs_rename,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@@ -20,5 +20,6 @@ int exfat_fs_unlink(const char *filename);
|
|||||||
int exfat_fs_mkdir(const char *dirname);
|
int exfat_fs_mkdir(const char *dirname);
|
||||||
int exfat_fs_write(const char *filename, void *buf, loff_t offset,
|
int exfat_fs_write(const char *filename, void *buf, loff_t offset,
|
||||||
loff_t len, loff_t *actwrite);
|
loff_t len, loff_t *actwrite);
|
||||||
|
int exfat_fs_rename(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
#endif /* _EXFAT_H */
|
#endif /* _EXFAT_H */
|
||||||
|
@@ -17,7 +17,7 @@ supported_fs_fat = ['fat12', 'fat16']
|
|||||||
supported_fs_mkdir = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
|
supported_fs_mkdir = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
|
||||||
supported_fs_unlink = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
|
supported_fs_unlink = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
|
||||||
supported_fs_symlink = ['ext4']
|
supported_fs_symlink = ['ext4']
|
||||||
supported_fs_rename = ['fat12', 'fat16', 'fat32']
|
supported_fs_rename = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
|
||||||
|
|
||||||
#
|
#
|
||||||
# Filesystem test specific setup
|
# Filesystem test specific setup
|
||||||
|
@@ -35,6 +35,19 @@ class TestFsBasic(object):
|
|||||||
'%sls host 0:0 invalid_d' % fs_cmd_prefix)
|
'%sls host 0:0 invalid_d' % fs_cmd_prefix)
|
||||||
assert('' == output)
|
assert('' == output)
|
||||||
|
|
||||||
|
with ubman.log.section('Test Case 1c - test -e'):
|
||||||
|
# Test Case 1 - test -e
|
||||||
|
output = ubman.run_command_list([
|
||||||
|
'host bind 0 %s' % fs_img,
|
||||||
|
'test -e host 0:0 1MB.file && echo PASS'])
|
||||||
|
assert('PASS' in ''.join(output))
|
||||||
|
|
||||||
|
with ubman.log.section('Test Case 1d - test -e (invalid file)'):
|
||||||
|
# In addition, test with a nonexistent file to see if we crash.
|
||||||
|
output = ubman.run_command(
|
||||||
|
'test -e host 0:0 2MB.file || echo PASS')
|
||||||
|
assert('PASS' in ''.join(output))
|
||||||
|
|
||||||
def test_fs2(self, ubman, fs_obj_basic):
|
def test_fs2(self, ubman, fs_obj_basic):
|
||||||
"""
|
"""
|
||||||
Test Case 2 - size command for a small file
|
Test Case 2 - size command for a small file
|
||||||
|
Reference in New Issue
Block a user