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:
Tom Rini
2025-04-21 11:07:22 -06:00
6 changed files with 95 additions and 53 deletions

View File

@@ -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);

View File

@@ -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
} }

View File

@@ -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
{ {

View File

@@ -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 */

View File

@@ -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

View File

@@ -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