source: mainline/uspace/lib/ext4/src/ialloc.c@ 84239b1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 84239b1 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.1 KB
RevLine 
[bf66ef4]1/*
[f22d5ef0]2 * Copyright (c) 2012 Frantisek Princ
[bf66ef4]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libext4
30 * @{
[38542dc]31 */
[bf66ef4]32/**
[4bfad34]33 * @file ialloc.c
[38542dc]34 * @brief I-node (de)allocation operations.
[bf66ef4]35 */
36
[3d4fd2c]37#include <errno.h>
[fcb0d76]38#include <stdbool.h>
39#include "ext4/bitmap.h"
40#include "ext4/block_group.h"
41#include "ext4/filesystem.h"
42#include "ext4/ialloc.h"
43#include "ext4/superblock.h"
[bf66ef4]44
[ee3b6150]45
46/** Convert i-node number to relative index in block group.
47 *
[38542dc]48 * @param sb Superblock
49 * @param inode I-node number to be converted
50 *
51 * @return Index of the i-node in the block group
52 *
[ee3b6150]53 */
[3d4fd2c]54static uint32_t ext4_ialloc_inode2index_in_group(ext4_superblock_t *sb,
[38542dc]55 uint32_t inode)
[3d4fd2c]56{
57 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
58 return (inode - 1) % inodes_per_group;
59}
60
[ee3b6150]61/** Convert relative index of i-node to absolute i-node number.
62 *
[38542dc]63 * @param sb Superblock
64 * @param inode Index to be converted
65 *
66 * @return Absolute number of the i-node
67 *
[ee3b6150]68 */
[cd1cc4e6]69static uint32_t ext4_ialloc_index_in_group2inode(ext4_superblock_t *sb,
[38542dc]70 uint32_t index, uint32_t bgid)
[cd1cc4e6]71{
72 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
73 return bgid * inodes_per_group + (index + 1);
74}
75
[ee3b6150]76/** Compute block group number from the i-node number.
77 *
[38542dc]78 * @param sb Superblock
79 * @param inode I-node number to be found the block group for
80 *
81 * @return Block group number computed from i-node number
82 *
[ee3b6150]83 */
[3d4fd2c]84static uint32_t ext4_ialloc_get_bgid_of_inode(ext4_superblock_t *sb,
[38542dc]85 uint32_t inode)
[3d4fd2c]86{
87 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
88 return (inode - 1) / inodes_per_group;
89}
90
91
[ee3b6150]92/** Free i-node number and modify filesystem data structers.
93 *
[38542dc]94 * @param fs Filesystem, where the i-node is located
95 * @param index Index of i-node to be release
96 * @param is_dir Flag us for information whether i-node is directory or not
97 *
[ee3b6150]98 */
[b7fd2a0]99errno_t ext4_ialloc_free_inode(ext4_filesystem_t *fs, uint32_t index, bool is_dir)
[3d4fd2c]100{
[304faab]101 ext4_superblock_t *sb = fs->superblock;
[a35b458]102
[06d85e5]103 /* Compute index of block group and load it */
[304faab]104 uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
[a35b458]105
[3d4fd2c]106 ext4_block_group_ref_t *bg_ref;
[b7fd2a0]107 errno_t rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
[38542dc]108 if (rc != EOK)
[3d4fd2c]109 return rc;
[a35b458]110
[06d85e5]111 /* Load i-node bitmap */
[3d4fd2c]112 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
[38542dc]113 bg_ref->block_group, sb);
[3d4fd2c]114 block_t *bitmap_block;
[38542dc]115 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
116 BLOCK_FLAGS_NONE);
117 if (rc != EOK)
[3d4fd2c]118 return rc;
[a35b458]119
[06d85e5]120 /* Free i-node in the bitmap */
[304faab]121 uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
[3d4fd2c]122 ext4_bitmap_free_bit(bitmap_block->data, index_in_group);
123 bitmap_block->dirty = true;
[a35b458]124
[06d85e5]125 /* Put back the block with bitmap */
[3d4fd2c]126 rc = block_put(bitmap_block);
127 if (rc != EOK) {
[06d85e5]128 /* Error in saving bitmap */
[3d4fd2c]129 ext4_filesystem_put_block_group_ref(bg_ref);
130 return rc;
131 }
[a35b458]132
[06d85e5]133 /* If released i-node is a directory, decrement used directories count */
[304faab]134 if (is_dir) {
[e5f8762]135 uint32_t bg_used_dirs = ext4_block_group_get_used_dirs_count(
[38542dc]136 bg_ref->block_group, sb);
[e5f8762]137 bg_used_dirs--;
[38542dc]138 ext4_block_group_set_used_dirs_count(bg_ref->block_group, sb,
139 bg_used_dirs);
[e5f8762]140 }
[a35b458]141
[06d85e5]142 /* Update block group free inodes count */
[3d4fd2c]143 uint32_t free_inodes = ext4_block_group_get_free_inodes_count(
[38542dc]144 bg_ref->block_group, sb);
[3d4fd2c]145 free_inodes++;
[38542dc]146 ext4_block_group_set_free_inodes_count(bg_ref->block_group, sb,
147 free_inodes);
[a35b458]148
[3d4fd2c]149 bg_ref->dirty = true;
[a35b458]150
[06d85e5]151 /* Put back the modified block group */
[3d4fd2c]152 rc = ext4_filesystem_put_block_group_ref(bg_ref);
[38542dc]153 if (rc != EOK)
[3d4fd2c]154 return rc;
[a35b458]155
[06d85e5]156 /* Update superblock free inodes count */
[38542dc]157 uint32_t sb_free_inodes =
158 ext4_superblock_get_free_inodes_count(sb);
[304faab]159 sb_free_inodes++;
160 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
[a35b458]161
[3d4fd2c]162 return EOK;
163}
164
[ee3b6150]165/** I-node allocation algorithm.
166 *
[38542dc]167 * This is more simple algorithm, than Orlov allocator used
168 * in the Linux kernel.
169 *
170 * @param fs Filesystem to allocate i-node on
171 * @param index Output value - allocated i-node number
172 * @param is_dir Flag if allocated i-node will be file or directory
173 *
174 * @return Error code
[ee3b6150]175 *
176 */
[b7fd2a0]177errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir)
[304faab]178{
179 ext4_superblock_t *sb = fs->superblock;
[a35b458]180
[304faab]181 uint32_t bgid = 0;
182 uint32_t bg_count = ext4_superblock_get_block_group_count(sb);
[cd1cc4e6]183 uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
184 uint32_t avg_free_inodes = sb_free_inodes / bg_count;
[a35b458]185
[06d85e5]186 /* Try to find free i-node in all block groups */
[304faab]187 while (bgid < bg_count) {
[06d85e5]188 /* Load block group to check */
[304faab]189 ext4_block_group_ref_t *bg_ref;
[b7fd2a0]190 errno_t rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
[38542dc]191 if (rc != EOK)
[304faab]192 return rc;
[a35b458]193
[304faab]194 ext4_block_group_t *bg = bg_ref->block_group;
[a35b458]195
[06d85e5]196 /* Read necessary values for algorithm */
[304faab]197 uint32_t free_blocks = ext4_block_group_get_free_blocks_count(bg, sb);
198 uint32_t free_inodes = ext4_block_group_get_free_inodes_count(bg, sb);
199 uint32_t used_dirs = ext4_block_group_get_used_dirs_count(bg, sb);
[a35b458]200
[8a45707d]201 /*
202 * Check if this block group is a good candidate
203 * for allocation.
204 *
205 * The criterion is based on the average number
206 * of free inodes, unless we examine the last block
207 * group. In that case the last block group might
208 * have less than the average number of free inodes,
209 * but it still needs to be taken as a candidate
210 * because the previous block groups have zero free
211 * blocks.
212 */
213 if (((free_inodes >= avg_free_inodes) || (bgid == bg_count - 1)) &&
214 (free_blocks > 0)) {
[06d85e5]215 /* Load block with bitmap */
[38542dc]216 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
217 bg_ref->block_group, sb);
[a35b458]218
[304faab]219 block_t *bitmap_block;
[38542dc]220 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
221 BLOCK_FLAGS_NONE);
[2f591127]222 if (rc != EOK) {
223 ext4_filesystem_put_block_group_ref(bg_ref);
[304faab]224 return rc;
[2f591127]225 }
[a35b458]226
[06d85e5]227 /* Try to allocate i-node in the bitmap */
[304faab]228 uint32_t inodes_in_group = ext4_superblock_get_inodes_in_group(sb, bgid);
[cd1cc4e6]229 uint32_t index_in_group;
[38542dc]230 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data,
231 0, &index_in_group, inodes_in_group);
[a35b458]232
[06d85e5]233 /* Block group has not any free i-node */
[1d69c69]234 if (rc == ENOSPC) {
[e5a1ace3]235 rc = block_put(bitmap_block);
236 if (rc != EOK) {
237 ext4_filesystem_put_block_group_ref(bg_ref);
238 return rc;
239 }
240
241 rc = ext4_filesystem_put_block_group_ref(bg_ref);
242 if (rc != EOK)
243 return rc;
244
[2f591127]245 bgid++;
[1d69c69]246 continue;
247 }
[a35b458]248
[06d85e5]249 /* Free i-node found, save the bitmap */
[304faab]250 bitmap_block->dirty = true;
[a35b458]251
[304faab]252 rc = block_put(bitmap_block);
[2f591127]253 if (rc != EOK) {
254 ext4_filesystem_put_block_group_ref(bg_ref);
[304faab]255 return rc;
[2f591127]256 }
[a35b458]257
[06d85e5]258 /* Modify filesystem counters */
[304faab]259 free_inodes--;
260 ext4_block_group_set_free_inodes_count(bg, sb, free_inodes);
[a35b458]261
[06d85e5]262 /* Increment used directories counter */
[304faab]263 if (is_dir) {
[cd1cc4e6]264 used_dirs++;
[304faab]265 ext4_block_group_set_used_dirs_count(bg, sb, used_dirs);
266 }
[a35b458]267
[e25d78c]268 /* Decrease unused inodes count */
269 if (ext4_block_group_has_flag(bg,
[38542dc]270 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
[e25d78c]271 uint32_t unused =
[38542dc]272 ext4_block_group_get_itable_unused(bg, sb);
[a35b458]273
[e25d78c]274 uint32_t inodes_in_group =
[38542dc]275 ext4_superblock_get_inodes_in_group(sb, bgid);
[a35b458]276
[e25d78c]277 uint32_t free = inodes_in_group - unused;
[a35b458]278
[e25d78c]279 if (index_in_group >= free) {
280 unused = inodes_in_group - (index_in_group + 1);
281 ext4_block_group_set_itable_unused(bg, sb, unused);
282 }
283 }
[a35b458]284
[06d85e5]285 /* Save modified block group */
[304faab]286 bg_ref->dirty = true;
[a35b458]287
[304faab]288 rc = ext4_filesystem_put_block_group_ref(bg_ref);
[38542dc]289 if (rc != EOK)
[847f2cb]290 return rc;
[a35b458]291
[06d85e5]292 /* Update superblock */
[304faab]293 sb_free_inodes--;
294 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
[a35b458]295
[06d85e5]296 /* Compute the absolute i-nodex number */
[cd1cc4e6]297 *index = ext4_ialloc_index_in_group2inode(sb, index_in_group, bgid);
[a35b458]298
[304faab]299 return EOK;
300 }
[a35b458]301
[06d85e5]302 /* Block group not modified, put it and jump to the next block group */
[e5a1ace3]303 rc = ext4_filesystem_put_block_group_ref(bg_ref);
304 if (rc != EOK)
305 return rc;
306
[cd1cc4e6]307 ++bgid;
[304faab]308 }
[a35b458]309
[304faab]310 return ENOSPC;
311}
[bf66ef4]312
313/**
314 * @}
[38542dc]315 */
Note: See TracBrowser for help on using the repository browser.