source: mainline/uspace/lib/ext4/src/ialloc.c@ 6ff23ff

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6ff23ff 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
Line 
1/*
2 * Copyright (c) 2012 Frantisek Princ
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 * @{
31 */
32/**
33 * @file ialloc.c
34 * @brief I-node (de)allocation operations.
35 */
36
37#include <errno.h>
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"
44
45
46/** Convert i-node number to relative index in block group.
47 *
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 *
53 */
54static uint32_t ext4_ialloc_inode2index_in_group(ext4_superblock_t *sb,
55 uint32_t inode)
56{
57 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
58 return (inode - 1) % inodes_per_group;
59}
60
61/** Convert relative index of i-node to absolute i-node number.
62 *
63 * @param sb Superblock
64 * @param inode Index to be converted
65 *
66 * @return Absolute number of the i-node
67 *
68 */
69static uint32_t ext4_ialloc_index_in_group2inode(ext4_superblock_t *sb,
70 uint32_t index, uint32_t bgid)
71{
72 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
73 return bgid * inodes_per_group + (index + 1);
74}
75
76/** Compute block group number from the i-node number.
77 *
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 *
83 */
84static uint32_t ext4_ialloc_get_bgid_of_inode(ext4_superblock_t *sb,
85 uint32_t inode)
86{
87 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
88 return (inode - 1) / inodes_per_group;
89}
90
91
92/** Free i-node number and modify filesystem data structers.
93 *
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 *
98 */
99errno_t ext4_ialloc_free_inode(ext4_filesystem_t *fs, uint32_t index, bool is_dir)
100{
101 ext4_superblock_t *sb = fs->superblock;
102
103 /* Compute index of block group and load it */
104 uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
105
106 ext4_block_group_ref_t *bg_ref;
107 errno_t rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
108 if (rc != EOK)
109 return rc;
110
111 /* Load i-node bitmap */
112 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
113 bg_ref->block_group, sb);
114 block_t *bitmap_block;
115 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
116 BLOCK_FLAGS_NONE);
117 if (rc != EOK)
118 return rc;
119
120 /* Free i-node in the bitmap */
121 uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
122 ext4_bitmap_free_bit(bitmap_block->data, index_in_group);
123 bitmap_block->dirty = true;
124
125 /* Put back the block with bitmap */
126 rc = block_put(bitmap_block);
127 if (rc != EOK) {
128 /* Error in saving bitmap */
129 ext4_filesystem_put_block_group_ref(bg_ref);
130 return rc;
131 }
132
133 /* If released i-node is a directory, decrement used directories count */
134 if (is_dir) {
135 uint32_t bg_used_dirs = ext4_block_group_get_used_dirs_count(
136 bg_ref->block_group, sb);
137 bg_used_dirs--;
138 ext4_block_group_set_used_dirs_count(bg_ref->block_group, sb,
139 bg_used_dirs);
140 }
141
142 /* Update block group free inodes count */
143 uint32_t free_inodes = ext4_block_group_get_free_inodes_count(
144 bg_ref->block_group, sb);
145 free_inodes++;
146 ext4_block_group_set_free_inodes_count(bg_ref->block_group, sb,
147 free_inodes);
148
149 bg_ref->dirty = true;
150
151 /* Put back the modified block group */
152 rc = ext4_filesystem_put_block_group_ref(bg_ref);
153 if (rc != EOK)
154 return rc;
155
156 /* Update superblock free inodes count */
157 uint32_t sb_free_inodes =
158 ext4_superblock_get_free_inodes_count(sb);
159 sb_free_inodes++;
160 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
161
162 return EOK;
163}
164
165/** I-node allocation algorithm.
166 *
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
175 *
176 */
177errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir)
178{
179 ext4_superblock_t *sb = fs->superblock;
180
181 uint32_t bgid = 0;
182 uint32_t bg_count = ext4_superblock_get_block_group_count(sb);
183 uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
184 uint32_t avg_free_inodes = sb_free_inodes / bg_count;
185
186 /* Try to find free i-node in all block groups */
187 while (bgid < bg_count) {
188 /* Load block group to check */
189 ext4_block_group_ref_t *bg_ref;
190 errno_t rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
191 if (rc != EOK)
192 return rc;
193
194 ext4_block_group_t *bg = bg_ref->block_group;
195
196 /* Read necessary values for algorithm */
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);
200
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)) {
215 /* Load block with bitmap */
216 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
217 bg_ref->block_group, sb);
218
219 block_t *bitmap_block;
220 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
221 BLOCK_FLAGS_NONE);
222 if (rc != EOK) {
223 ext4_filesystem_put_block_group_ref(bg_ref);
224 return rc;
225 }
226
227 /* Try to allocate i-node in the bitmap */
228 uint32_t inodes_in_group = ext4_superblock_get_inodes_in_group(sb, bgid);
229 uint32_t index_in_group;
230 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data,
231 0, &index_in_group, inodes_in_group);
232
233 /* Block group has not any free i-node */
234 if (rc == ENOSPC) {
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
245 bgid++;
246 continue;
247 }
248
249 /* Free i-node found, save the bitmap */
250 bitmap_block->dirty = true;
251
252 rc = block_put(bitmap_block);
253 if (rc != EOK) {
254 ext4_filesystem_put_block_group_ref(bg_ref);
255 return rc;
256 }
257
258 /* Modify filesystem counters */
259 free_inodes--;
260 ext4_block_group_set_free_inodes_count(bg, sb, free_inodes);
261
262 /* Increment used directories counter */
263 if (is_dir) {
264 used_dirs++;
265 ext4_block_group_set_used_dirs_count(bg, sb, used_dirs);
266 }
267
268 /* Decrease unused inodes count */
269 if (ext4_block_group_has_flag(bg,
270 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
271 uint32_t unused =
272 ext4_block_group_get_itable_unused(bg, sb);
273
274 uint32_t inodes_in_group =
275 ext4_superblock_get_inodes_in_group(sb, bgid);
276
277 uint32_t free = inodes_in_group - unused;
278
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 }
284
285 /* Save modified block group */
286 bg_ref->dirty = true;
287
288 rc = ext4_filesystem_put_block_group_ref(bg_ref);
289 if (rc != EOK)
290 return rc;
291
292 /* Update superblock */
293 sb_free_inodes--;
294 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
295
296 /* Compute the absolute i-nodex number */
297 *index = ext4_ialloc_index_in_group2inode(sb, index_in_group, bgid);
298
299 return EOK;
300 }
301
302 /* Block group not modified, put it and jump to the next block group */
303 rc = ext4_filesystem_put_block_group_ref(bg_ref);
304 if (rc != EOK)
305 return rc;
306
307 ++bgid;
308 }
309
310 return ENOSPC;
311}
312
313/**
314 * @}
315 */
Note: See TracBrowser for help on using the repository browser.