diff options
| author | gkostka <kostka.grzegorz@gmail.com> | 2016-01-10 11:29:54 +0100 |
|---|---|---|
| committer | gkostka <kostka.grzegorz@gmail.com> | 2016-01-10 14:03:16 +0100 |
| commit | fad2d51c6c20323408b13f5ff95c3794ace78376 (patch) | |
| tree | 1f90a02512dbc887c111bae59b00f6c92f5d32cd | |
| parent | b4f36a128a7826b7343c8181b1ab34fe48ebfc18 (diff) | |
ext4: introduce ext4_trunc_inode to deal with ftruncate operation
Truncate operations might consume a lot of blocks. New function
will split one big transacion into a numerous of smaller ones.
CONFIG_MAX_TRUNCATE_SIZE limits single inode truncate size.
| -rw-r--r-- | lwext4/ext4.c | 60 | ||||
| -rw-r--r-- | lwext4/ext4_config.h | 6 |
2 files changed, 61 insertions, 5 deletions
diff --git a/lwext4/ext4.c b/lwext4/ext4.c index 5e24eef..16e50a0 100644 --- a/lwext4/ext4.c +++ b/lwext4/ext4.c @@ -704,6 +704,56 @@ static bool ext4_parse_flags(const char *flags, uint32_t *file_flags) return false; } +static int ext4_trunc_inode(struct ext4_mountpoint *mp, + struct ext4_inode_ref *inode_ref, uint64_t new_size) +{ + int r = EOK; + struct ext4_fs *const fs = &mp->fs; + uint64_t inode_size = ext4_inode_get_size(&fs->sb, inode_ref->inode); + uint32_t index = inode_ref->index; + + + while (inode_size > new_size + CONFIG_MAX_TRUNCATE_SIZE) { + + inode_size -= CONFIG_MAX_TRUNCATE_SIZE; + ext4_trans_start(mp); + r = ext4_fs_truncate_inode(inode_ref, inode_size); + if (r != EOK) + return r; + + r = ext4_fs_put_inode_ref(inode_ref); + if (r != EOK) + ext4_trans_abort(mp); + else + ext4_trans_stop(mp); + + r = ext4_fs_get_inode_ref(fs, index, inode_ref); + if (r != EOK) + return r; + } + + if (inode_size > new_size) { + + inode_size = new_size; + ext4_trans_start(mp); + r = ext4_fs_truncate_inode(inode_ref, inode_size); + if (r != EOK) + return r; + + r = ext4_fs_put_inode_ref(inode_ref); + if (r != EOK) + ext4_trans_abort(mp); + else + ext4_trans_stop(mp); + + r = ext4_fs_get_inode_ref(fs, index, inode_ref); + if (r != EOK) + return r; + } + + return r; +} + /* * NOTICE: if filetype is equal to EXT4_DIRENTRY_UNKNOWN, * any filetype of the target dir entry will be accepted. @@ -855,7 +905,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, if (is_goal) { if ((f->flags & O_TRUNC) && (imode == EXT4_INODE_MODE_FILE)) { - r = ext4_fs_truncate_inode(&ref, 0); + r = ext4_trunc_inode(mp, &ref, 0); if (r != EOK) { ext4_fs_put_inode_ref(&ref); return r; @@ -1237,7 +1287,7 @@ int ext4_fremove(const char *path) /*Turncate*/ ext4_block_cache_write_back(mp->fs.bdev, 1); /*Truncate may be IO heavy. Do it writeback cache mode.*/ - r = ext4_fs_truncate_inode(&child, 0); + r = ext4_trunc_inode(mp, &child, 0); ext4_block_cache_write_back(mp->fs.bdev, 0); if (r != EOK) @@ -1388,7 +1438,7 @@ static int ext4_ftruncate_no_lock(ext4_file *f, uint64_t size) if (r != EOK) goto Finish; - r = ext4_fs_truncate_inode(&ref, size); + r = ext4_trunc_inode(f->mp, &ref, size); if (r != EOK) goto Finish; @@ -2511,7 +2561,7 @@ int ext4_dir_rm(const char *path) } /* Truncate */ - r = ext4_fs_truncate_inode(&child, 0); + r = ext4_trunc_inode(mp, &child, 0); if (r != EOK) { ext4_fs_put_inode_ref(&child); goto End; @@ -2604,7 +2654,7 @@ End: ext4_inode_set_links_cnt(act.inode, 0); act.dirty = true; /*Turncate*/ - r = ext4_fs_truncate_inode(&act, 0); + r = ext4_trunc_inode(mp, &act, 0); if (r != EOK) { ext4_fs_put_inode_ref(&parent); ext4_fs_put_inode_ref(&act); diff --git a/lwext4/ext4_config.h b/lwext4/ext4_config.h index 1b25106..17da6bb 100644 --- a/lwext4/ext4_config.h +++ b/lwext4/ext4_config.h @@ -138,6 +138,12 @@ extern "C" { #define CONFIG_EXTENT_FULL 1 #endif +/**@brief Maximum single truncate size. Transactions must be limited to reduce + * number of allocetions for single transaction*/ +#ifndef CONFIG_MAX_TRUNCATE_SIZE +#define CONFIG_MAX_TRUNCATE_SIZE (16 * 1024 * 1024) +#endif + #ifdef __cplusplus } #endif |
