/* * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup lwext4 * @{ *//** * @file ext4.h * @brief Ext4 high level operations (file, directory, mountpoints...) */ #include <ext4.h>#include <ext4_trans.h>#include <ext4_fs.h>#include <ext4_dir.h>#include <ext4_inode.h>#include <ext4_super.h>#include <ext4_block_group.h>#include <ext4_dir_idx.h>#include <ext4_xattr.h>#include <ext4_journal.h> #include <stdlib.h>#include <string.h> /**@brief Mount point OS dependent lock*/#define EXT4_MP_LOCK(_m) \ do { \ if ((_m)->os_locks) \ (_m)->os_locks->lock((_m)->os_locks->p_user); \ } while (0) /**@brief Mount point OS dependent unlock*/#define EXT4_MP_UNLOCK(_m) \ do { \ if ((_m)->os_locks) \ (_m)->os_locks->unlock((_m)->os_locks->p_user); \ } while (0) /**@brief Mount point descriptor.*/struct ext4_mountpoint { /**@brief Mount done flag.*/ bool mounted; /**@brief Mount point name (@ref ext4_mount)*/ char name[CONFIG_EXT4_MAX_MP_NAME + 1]; /**@brief OS dependent lock/unlock functions.*/ const struct ext4_lock *os_locks; /**@brief Ext4 filesystem internals.*/ struct ext4_fs fs; /**@brief JBD fs.*/ struct jbd_fs jbd_fs; /**@brief Journal.*/ struct jbd_journal jbd_journal; /**@brief Block cache.*/ struct ext4_bcache bc;}; /**@brief Block devices descriptor.*/struct ext4_block_devices { /**@brief Block device name.*/ char name[CONFIG_EXT4_MAX_BLOCKDEV_NAME + 1]; /**@brief Block device handle.*/ struct ext4_blockdev *bd;}; /**@brief Block devices.*/static struct ext4_block_devices s_bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT]; /**@brief Mountpoints.*/static struct ext4_mountpoint s_mp[CONFIG_EXT4_MOUNTPOINTS_COUNT]; int ext4_device_register(struct ext4_blockdev *bd, const char *dev_name){ ext4_assert(bd && dev_name); if (strlen(dev_name) > CONFIG_EXT4_MAX_BLOCKDEV_NAME) return EINVAL; for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!strcmp(s_bdevices[i].name, dev_name)) return EEXIST; } for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!s_bdevices[i].bd) { strcpy(s_bdevices[i].name, dev_name); s_bdevices[i].bd = bd; return EOK; } } return ENOSPC;} int ext4_device_unregister(const char *dev_name){ ext4_assert(dev_name); for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (strcmp(s_bdevices[i].name, dev_name) == 0) { memset(&s_bdevices[i], 0, sizeof(s_bdevices[i])); return EOK; } } return ENOENT;} int ext4_device_unregister_all(void){ memset(s_bdevices, 0, sizeof(s_bdevices)); return EOK;} /****************************************************************************/ static bool ext4_is_dots(const uint8_t *name, size_t name_size){ if ((name_size == 1) && (name[0] == '.')) return true; if ((name_size == 2) && (name[0] == '.') && (name[1] == '.')) return true; return false;} static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode){ struct ext4_sblock *sb = &enode->fs->sb; /* Check if node is directory */ if (!ext4_inode_is_type(sb, enode->inode, EXT4_INODE_MODE_DIRECTORY)) { *has_children = false; return EOK; } struct ext4_dir_iter it; int rc = ext4_dir_iterator_init(&it, enode, 0); if (rc != EOK) return rc; /* Find a non-empty directory entry */ bool found = false; while (it.curr != NULL) { if (ext4_dir_en_get_inode(it.curr) != 0) { uint16_t nsize; nsize = ext4_dir_en_get_name_len(sb, it.curr); if (!ext4_is_dots(it.curr->name, nsize)) { found = true; break; } } rc = ext4_dir_iterator_next(&it); if (rc != EOK) { ext4_dir_iterator_fini(&it); return rc; } } rc = ext4_dir_iterator_fini(&it); if (rc != EOK) return rc; *has_children = found; return EOK;} static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *ch, const char *n, uint32_t len, bool rename){ /* Check maximum name length */ if (len > EXT4_DIRECTORY_FILENAME_LEN) return EINVAL; /* Add entry to parent directory */ int r = ext4_dir_add_entry(parent, n, len, ch); if (r != EOK) return r; /* Fill new dir -> add '.' and '..' entries. * Also newly allocated inode should have 0 link count. */ bool is_dir = ext4_inode_is_type(&mp->fs.sb, ch->inode, EXT4_INODE_MODE_DIRECTORY); if (is_dir && !rename) { #if CONFIG_DIR_INDEX_ENABLE /* Initialize directory index if supported */ if (ext4_sb_feature_com(&mp->fs.sb, EXT4_FCOM_DIR_INDEX)) { r = ext4_dir_dx_init(ch, parent); if (r != EOK) return r; ext4_inode_set_flag(ch->inode, EXT4_INODE_FLAG_INDEX); ch->dirty = true; } else#endif r = ext4_dir_add_entry(ch, ".", strlen("."), ch); if (r != EOK) { ext4_dir_remove_entry(parent, n, strlen(n)); return r; } r = ext4_dir_add_entry(ch, "..", strlen(".."), parent); if (r != EOK) { ext4_dir_remove_entry(parent, n, strlen(n)); ext4_dir_remove_entry(ch, ".", strlen(".")); return r; } /*New empty directory. Two links (. and ..) */ ext4_inode_set_links_cnt(ch->inode, 2); ext4_fs_inode_links_count_inc(parent); ch->dirty = true; parent->dirty = true; return r; } /* * In case we want to rename a directory, * we reset the original '..' pointer. */ if (is_dir) { bool idx; idx = ext4_inode_has_flag(ch->inode, EXT4_INODE_FLAG_INDEX); struct ext4_dir_search_result res; if (!idx) { r = ext4_dir_find_entry(&res, ch, "..", strlen("..")); if (r != EOK) return EIO; ext4_dir_en_set_inode(res.dentry, parent->index); ext4_trans_set_block_dirty(res.block.buf); r = ext4_dir_destroy_result(ch, &res); if (r != EOK) return r; } else {#if CONFIG_DIR_INDEX_ENABLE r = ext4_dir_dx_reset_parent_inode(ch, parent->index); if (r != EOK) return r; #endif } ext4_fs_inode_links_count_inc(parent); parent->dirty = true; } if (!rename) { ext4_fs_inode_links_count_inc(ch); ch->dirty = true; } return r;} static int ext4_unlink(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *child, const char *name, uint32_t name_len){ bool has_children; int rc = ext4_has_children(&has_children, child); if (rc != EOK) return rc; /* Cannot unlink non-empty node */ if (has_children) return ENOTEMPTY; /* Remove entry from parent directory */ rc = ext4_dir_remove_entry(parent, name, name_len); if (rc != EOK) return rc; bool is_dir = ext4_inode_is_type(&mp->fs.sb, child->inode, EXT4_INODE_MODE_DIRECTORY); /* If directory - handle links from parent */ if (is_dir) { ext4_fs_inode_links_count_dec(parent); parent->dirty = true; } /* * TODO: Update timestamps of the parent * (when we have wall-clock time). * * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now); * ext4_inode_set_modification_time(parent->inode, (uint32_t) now); * parent->dirty = true; */ /* * TODO: Update timestamp for inode. * * ext4_inode_set_change_inode_time(child->inode, * (uint32_t) now); */ if (ext4_inode_get_links_cnt(child->inode)) { ext4_fs_inode_links_count_dec(child); child->dirty = true; } return EOK;} /****************************************************************************/ int ext4_mount(const char *dev_name, const char *mount_point, bool read_only){ int r; uint32_t bsize; struct ext4_bcache *bc; struct ext4_blockdev *bd = 0; struct ext4_mountpoint *mp = 0; ext4_assert(mount_point && dev_name); size_t mp_len = strlen(mount_point); if (mp_len > CONFIG_EXT4_MAX_MP_NAME) return EINVAL; if (mount_point[mp_len - 1] != '/') return ENOTSUP; for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!strcmp(dev_name, s_bdevices[i].name)) { bd = s_bdevices[i].bd; break; } } if (!bd) return ENODEV; for (size_t i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!s_mp[i].mounted) { strcpy(s_mp[i].name, mount_point); s_mp[i].mounted = 1; mp = &s_mp[i]; break; } if (!strcmp(s_mp[i].name, mount_point)) return EOK; } if (!mp) return ENOMEM; r = ext4_block_init(bd); if (r != EOK) return r; r = ext4_fs_init(&mp->fs, bd, read_only); if (r != EOK) { ext4_block_fini(bd); return r; } bsize = ext4_sb_get_block_size(&mp->fs.sb); ext4_block_set_lb_size(bd, bsize); bc = &mp->bc; r = ext4_bcache_init_dynamic(bc, CONFIG_BLOCK_DEV_CACHE_SIZE, bsize); if (r != EOK) { ext4_block_fini(bd); return r; } if (bsize != bc->itemsize) return ENOTSUP; /*Bind block cache to block device*/ r = ext4_block_bind_bcache(bd, bc); if (r != EOK) { ext4_bcache_cleanup(bc); ext4_block_fini(bd); ext4_bcache_fini_dynamic(bc); return r; } bd->fs = &mp->fs; return r;} int ext4_umount(const char *mount_point){ int i; int r; struct ext4_mountpoint *mp = 0; for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!strcmp(s_mp[i].name, mount_point)) { mp = &s_mp[i]; break; } } if (!mp) return ENODEV; r = ext4_fs_fini(&mp->fs); if (r != EOK) goto Finish; mp->mounted = 0; ext4_bcache_cleanup(mp->fs.bdev->bc); ext4_bcache_fini_dynamic(mp->fs.bdev->bc); r = ext4_block_fini(mp->fs.bdev);Finish: mp->fs.bdev->fs = NULL; return r;} static struct ext4_mountpoint *ext4_get_mount(const char *path){ for (size_t i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!s_mp[i].mounted) continue; if (!strncmp(s_mp[i].name, path, strlen(s_mp[i].name))) return &s_mp[i]; } return NULL;} __unusedstatic int __ext4_journal_start(const char *mount_point){ int r = EOK; struct ext4_mountpoint *mp = ext4_get_mount(mount_point); if (!mp) return ENOENT; if (mp->fs.read_only) return EOK; if (ext4_sb_feature_com(&mp->fs.sb, EXT4_FCOM_HAS_JOURNAL)) { r = jbd_get_fs(&mp->fs, &mp->jbd_fs); if (r != EOK) goto Finish; r = jbd_journal_start(&mp->jbd_fs, &mp->jbd_journal); if (r != EOK) { mp->jbd_fs.dirty = false; jbd_put_fs(&mp->jbd_fs); goto Finish;Lines 1–500 of 3246. Load more
/* * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup lwext4 * @{ */ /** * @file ext4.h * @brief Ext4 high level operations (file, directory, mountpoints...) */ #include <ext4.h> #include <ext4_trans.h> #include <ext4_fs.h> #include <ext4_dir.h> #include <ext4_inode.h> #include <ext4_super.h> #include <ext4_block_group.h> #include <ext4_dir_idx.h> #include <ext4_xattr.h> #include <ext4_journal.h> #include <stdlib.h> #include <string.h> /**@brief Mount point OS dependent lock*/ #define EXT4_MP_LOCK(_m) \ do { \ if ((_m)->os_locks) \ (_m)->os_locks->lock((_m)->os_locks->p_user); \ } while (0) /**@brief Mount point OS dependent unlock*/ #define EXT4_MP_UNLOCK(_m) \ do { \ if ((_m)->os_locks) \ (_m)->os_locks->unlock((_m)->os_locks->p_user); \ } while (0) /**@brief Mount point descriptor.*/ struct ext4_mountpoint { /**@brief Mount done flag.*/ bool mounted; /**@brief Mount point name (@ref ext4_mount)*/ char name[CONFIG_EXT4_MAX_MP_NAME + 1]; /**@brief OS dependent lock/unlock functions.*/ const struct ext4_lock *os_locks; /**@brief Ext4 filesystem internals.*/ struct ext4_fs fs; /**@brief JBD fs.*/ struct jbd_fs jbd_fs; /**@brief Journal.*/ struct jbd_journal jbd_journal; /**@brief Block cache.*/ struct ext4_bcache bc; }; /**@brief Block devices descriptor.*/ struct ext4_block_devices { /**@brief Block device name.*/ char name[CONFIG_EXT4_MAX_BLOCKDEV_NAME + 1]; /**@brief Block device handle.*/ struct ext4_blockdev *bd; }; /**@brief Block devices.*/ static struct ext4_block_devices s_bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT]; /**@brief Mountpoints.*/ static struct ext4_mountpoint s_mp[CONFIG_EXT4_MOUNTPOINTS_COUNT]; int ext4_device_register(struct ext4_blockdev *bd, const char *dev_name) { ext4_assert(bd && dev_name); if (strlen(dev_name) > CONFIG_EXT4_MAX_BLOCKDEV_NAME) return EINVAL; for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!strcmp(s_bdevices[i].name, dev_name)) return EEXIST; } for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!s_bdevices[i].bd) { strcpy(s_bdevices[i].name, dev_name); s_bdevices[i].bd = bd; return EOK; } } return ENOSPC; } int ext4_device_unregister(const char *dev_name) { ext4_assert(dev_name); for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (strcmp(s_bdevices[i].name, dev_name) == 0) { memset(&s_bdevices[i], 0, sizeof(s_bdevices[i])); return EOK; } } return ENOENT; } int ext4_device_unregister_all(void) { memset(s_bdevices, 0, sizeof(s_bdevices)); return EOK; } /****************************************************************************/ static bool ext4_is_dots(const uint8_t *name, size_t name_size) { if ((name_size == 1) && (name[0] == '.')) return true; if ((name_size == 2) && (name[0] == '.') && (name[1] == '.')) return true; return false; } static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode) { struct ext4_sblock *sb = &enode->fs->sb; /* Check if node is directory */ if (!ext4_inode_is_type(sb, enode->inode, EXT4_INODE_MODE_DIRECTORY)) { *has_children = false; return EOK; } struct ext4_dir_iter it; int rc = ext4_dir_iterator_init(&it, enode, 0); if (rc != EOK) return rc; /* Find a non-empty directory entry */ bool found = false; while (it.curr != NULL) { if (ext4_dir_en_get_inode(it.curr) != 0) { uint16_t nsize; nsize = ext4_dir_en_get_name_len(sb, it.curr); if (!ext4_is_dots(it.curr->name, nsize)) { found = true; break; } } rc = ext4_dir_iterator_next(&it); if (rc != EOK) { ext4_dir_iterator_fini(&it); return rc; } } rc = ext4_dir_iterator_fini(&it); if (rc != EOK) return rc; *has_children = found; return EOK; } static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *ch, const char *n, uint32_t len, bool rename) { /* Check maximum name length */ if (len > EXT4_DIRECTORY_FILENAME_LEN) return EINVAL; /* Add entry to parent directory */ int r = ext4_dir_add_entry(parent, n, len, ch); if (r != EOK) return r; /* Fill new dir -> add '.' and '..' entries. * Also newly allocated inode should have 0 link count. */ bool is_dir = ext4_inode_is_type(&mp->fs.sb, ch->inode, EXT4_INODE_MODE_DIRECTORY); if (is_dir && !rename) { #if CONFIG_DIR_INDEX_ENABLE /* Initialize directory index if supported */ if (ext4_sb_feature_com(&mp->fs.sb, EXT4_FCOM_DIR_INDEX)) { r = ext4_dir_dx_init(ch, parent); if (r != EOK) return r; ext4_inode_set_flag(ch->inode, EXT4_INODE_FLAG_INDEX); ch->dirty = true; } else #endif r = ext4_dir_add_entry(ch, ".", strlen("."), ch); if (r != EOK) { ext4_dir_remove_entry(parent, n, strlen(n)); return r; } r = ext4_dir_add_entry(ch, "..", strlen(".."), parent); if (r != EOK) { ext4_dir_remove_entry(parent, n, strlen(n)); ext4_dir_remove_entry(ch, ".", strlen(".")); return r; } /*New empty directory. Two links (. and ..) */ ext4_inode_set_links_cnt(ch->inode, 2); ext4_fs_inode_links_count_inc(parent); ch->dirty = true; parent->dirty = true; return r; } /* * In case we want to rename a directory, * we reset the original '..' pointer. */ if (is_dir) { bool idx; idx = ext4_inode_has_flag(ch->inode, EXT4_INODE_FLAG_INDEX); struct ext4_dir_search_result res; if (!idx) { r = ext4_dir_find_entry(&res, ch, "..", strlen("..")); if (r != EOK) return EIO; ext4_dir_en_set_inode(res.dentry, parent->index); ext4_trans_set_block_dirty(res.block.buf); r = ext4_dir_destroy_result(ch, &res); if (r != EOK) return r; } else { #if CONFIG_DIR_INDEX_ENABLE r = ext4_dir_dx_reset_parent_inode(ch, parent->index); if (r != EOK) return r; #endif } ext4_fs_inode_links_count_inc(parent); parent->dirty = true; } if (!rename) { ext4_fs_inode_links_count_inc(ch); ch->dirty = true; } return r; } static int ext4_unlink(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *child, const char *name, uint32_t name_len) { bool has_children; int rc = ext4_has_children(&has_children, child); if (rc != EOK) return rc; /* Cannot unlink non-empty node */ if (has_children) return ENOTEMPTY; /* Remove entry from parent directory */ rc = ext4_dir_remove_entry(parent, name, name_len); if (rc != EOK) return rc; bool is_dir = ext4_inode_is_type(&mp->fs.sb, child->inode, EXT4_INODE_MODE_DIRECTORY); /* If directory - handle links from parent */ if (is_dir) { ext4_fs_inode_links_count_dec(parent); parent->dirty = true; } /* * TODO: Update timestamps of the parent * (when we have wall-clock time). * * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now); * ext4_inode_set_modification_time(parent->inode, (uint32_t) now); * parent->dirty = true; */ /* * TODO: Update timestamp for inode. * * ext4_inode_set_change_inode_time(child->inode, * (uint32_t) now); */ if (ext4_inode_get_links_cnt(child->inode)) { ext4_fs_inode_links_count_dec(child); child->dirty = true; } return EOK; } /****************************************************************************/ int ext4_mount(const char *dev_name, const char *mount_point, bool read_only) { int r; uint32_t bsize; struct ext4_bcache *bc; struct ext4_blockdev *bd = 0; struct ext4_mountpoint *mp = 0; ext4_assert(mount_point && dev_name); size_t mp_len = strlen(mount_point); if (mp_len > CONFIG_EXT4_MAX_MP_NAME) return EINVAL; if (mount_point[mp_len - 1] != '/') return ENOTSUP; for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) { if (!strcmp(dev_name, s_bdevices[i].name)) { bd = s_bdevices[i].bd; break; } } if (!bd) return ENODEV; for (size_t i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!s_mp[i].mounted) { strcpy(s_mp[i].name, mount_point); s_mp[i].mounted = 1; mp = &s_mp[i]; break; } if (!strcmp(s_mp[i].name, mount_point)) return EOK; } if (!mp) return ENOMEM; r = ext4_block_init(bd); if (r != EOK) return r; r = ext4_fs_init(&mp->fs, bd, read_only); if (r != EOK) { ext4_block_fini(bd); return r; } bsize = ext4_sb_get_block_size(&mp->fs.sb); ext4_block_set_lb_size(bd, bsize); bc = &mp->bc; r = ext4_bcache_init_dynamic(bc, CONFIG_BLOCK_DEV_CACHE_SIZE, bsize); if (r != EOK) { ext4_block_fini(bd); return r; } if (bsize != bc->itemsize) return ENOTSUP; /*Bind block cache to block device*/ r = ext4_block_bind_bcache(bd, bc); if (r != EOK) { ext4_bcache_cleanup(bc); ext4_block_fini(bd); ext4_bcache_fini_dynamic(bc); return r; } bd->fs = &mp->fs; return r; } int ext4_umount(const char *mount_point) { int i; int r; struct ext4_mountpoint *mp = 0; for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!strcmp(s_mp[i].name, mount_point)) { mp = &s_mp[i]; break; } } if (!mp) return ENODEV; r = ext4_fs_fini(&mp->fs); if (r != EOK) goto Finish; mp->mounted = 0; ext4_bcache_cleanup(mp->fs.bdev->bc); ext4_bcache_fini_dynamic(mp->fs.bdev->bc); r = ext4_block_fini(mp->fs.bdev); Finish: mp->fs.bdev->fs = NULL; return r; } static struct ext4_mountpoint *ext4_get_mount(const char *path) { for (size_t i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { if (!s_mp[i].mounted) continue; if (!strncmp(s_mp[i].name, path, strlen(s_mp[i].name))) return &s_mp[i]; } return NULL; } __unused static int __ext4_journal_start(const char *mount_point) { int r = EOK; struct ext4_mountpoint *mp = ext4_get_mount(mount_point); if (!mp) return ENOENT; if (mp->fs.read_only) return EOK; if (ext4_sb_feature_com(&mp->fs.sb, EXT4_FCOM_HAS_JOURNAL)) { r = jbd_get_fs(&mp->fs, &mp->jbd_fs); if (r != EOK) goto Finish; r = jbd_journal_start(&mp->jbd_fs, &mp->jbd_journal); if (r != EOK) { mp->jbd_fs.dirty = false; jbd_put_fs(&mp->jbd_fs); goto Finish;