mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
sys/vfs: Introduce vfs_iterate_mount_dirs
... as thread-safe replacement for vfs_iterate_mounts
This commit is contained in:
parent
9a319a9b4f
commit
90069197f7
@ -1007,6 +1007,35 @@ int vfs_normalize_path(char *buf, const char *path, size_t buflen);
|
||||
*/
|
||||
const vfs_mount_t *vfs_iterate_mounts(const vfs_mount_t *cur);
|
||||
|
||||
/**
|
||||
* @brief Iterate through all mounted file systems by their root directories
|
||||
*
|
||||
* Unlike @ref vfs_iterate_mounts, this is thread safe, and allows thread safe
|
||||
* access to the mount point's stats through @ref vfs_dstatvfs. If mounts or
|
||||
* unmounts happen while iterating, this is guaranteed to report all file
|
||||
* systems that stayed mounted, and may report any that are transiently
|
||||
* mounted. Note that the volume being reported can not be unmounted as @p dir
|
||||
* is an open directory.
|
||||
*
|
||||
* Zero-initialize @p dir to start. As long as @c true is returned, @p dir is a
|
||||
* valid directory on which the user can call @ref vfs_readdir or @ref
|
||||
* vfs_dstatvfs (or even peek at its `.mp` if they dare ignore the warning in
|
||||
* @ref vfs_DIR).
|
||||
*
|
||||
* Users MUST NOT call @ref vfs_closedir if they intend to keep iterating, but
|
||||
* MUST call it when aborting iteration.
|
||||
*
|
||||
* Note that this requires all enumerated file systems to support the `opendir`
|
||||
* @ref vfs_dir_ops; any file system that does not support that will
|
||||
* prematurely terminate the mount point enumeration.
|
||||
*
|
||||
* @param[inout] dir The root directory of the discovered mount point
|
||||
*
|
||||
* @return @c true if another file system is mounted; @p dir then contains an open directory.
|
||||
* @return @c false if the file system list is exhausted; @p dir is uninitialized then.
|
||||
*/
|
||||
bool vfs_iterate_mount_dirs(vfs_DIR *dir);
|
||||
|
||||
/**
|
||||
* @brief Get information about the file for internal purposes
|
||||
*
|
||||
|
@ -522,7 +522,7 @@ int vfs_mount(vfs_mount_t *mountp)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* insert last in list */
|
||||
/* Insert last in list. This property is relied on by vfs_iterate_mount_dirs. */
|
||||
clist_rpush(&_vfs_mounts_list, &mountp->list_entry);
|
||||
mutex_unlock(&_mount_mutex);
|
||||
DEBUG("vfs_mount: mount done\n");
|
||||
@ -907,6 +907,51 @@ const vfs_mount_t *vfs_iterate_mounts(const vfs_mount_t *cur)
|
||||
return container_of(node, vfs_mount_t, list_entry);
|
||||
}
|
||||
|
||||
/* General implementation note: This heavily relies on the produced opened dir
|
||||
* to lock keep the underlying mount point from closing. */
|
||||
bool vfs_iterate_mount_dirs(vfs_DIR *dir)
|
||||
{
|
||||
/* This is NULL after the prescribed initialization, or a valid (and
|
||||
* locked) mount point otherwise */
|
||||
vfs_mount_t *last_mp = dir->mp;
|
||||
|
||||
/* This is technically violating vfs_iterate_mounts' API, as that says no
|
||||
* mounts or unmounts on the chain while iterating. However, as we know
|
||||
* that the current dir's mount point is still on, the equivalent procedure
|
||||
* of starting a new round of `vfs_iterate_mounts` from NULL and calling it
|
||||
* until it produces `last_mp` (all while holding _mount_mutex) would leave
|
||||
* us with the very same situation as if we started iteration with last_mp.
|
||||
*
|
||||
* On the cast discarding const: vfs_iterate_mounts's type is more for
|
||||
* public use */
|
||||
vfs_mount_t *next = (vfs_mount_t *)vfs_iterate_mounts(last_mp);
|
||||
if (next == NULL) {
|
||||
/* Ignoring errors, can't help with them */
|
||||
vfs_closedir(dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Even if we held the mutex up to here (see above comment on the fiction
|
||||
* of acquiring it, iterating to where we are, and releasing it again),
|
||||
* we'd need to let go of it now to actually open the directory. This
|
||||
* temporary count ensures that the file system will stick around for the
|
||||
* directory open step that follows immediately */
|
||||
atomic_fetch_add(&next->open_files, 1);
|
||||
|
||||
/* Ignoring errors, can't help with them */
|
||||
vfs_closedir(dir);
|
||||
|
||||
int err = vfs_opendir(dir, next->mount_point);
|
||||
/* No matter the success, the open_files lock has done its duty */
|
||||
atomic_fetch_sub(&next->open_files, 1);
|
||||
|
||||
if (err != 0) {
|
||||
DEBUG("vfs_iterate_mount opendir erred: vfs_opendir(\"%s\") = %d\n", next->mount_point, err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const vfs_file_t *vfs_file_get(int fd)
|
||||
{
|
||||
if (_fd_is_valid(fd) == 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user