source: mainline/uspace/lib/ext4/src/directory_index.c@ 395df52

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 395df52 was 4bfad34, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Move parts of ext4 filesystem initialization.

  • Property mode set to 100644
File size: 31.6 KB
RevLine 
[0dc91833]1/*
[f22d5ef0]2 * Copyright (c) 2012 Frantisek Princ
[0dc91833]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 */
[0dc91833]32/**
[4bfad34]33 * @file directory_index.c
[38542dc]34 * @brief Ext4 directory index operations.
[0dc91833]35 */
36
[343ccfd]37#include <byteorder.h>
[0dc91833]38#include <errno.h>
[fcb0d76]39#include <mem.h>
[f577058]40#include <sort.h>
[fcb0d76]41#include <stdlib.h>
42#include <str.h>
43#include "ext4/directory.h"
44#include "ext4/directory_index.h"
45#include "ext4/filesystem.h"
46#include "ext4/hash.h"
47#include "ext4/inode.h"
48#include "ext4/superblock.h"
[0dc91833]49
[db8fb43]50/** Type entry to pass to sorting algorithm.
51 *
52 */
[b191acae]53typedef struct ext4_dx_sort_entry {
54 uint32_t hash;
55 uint32_t rec_len;
56 void *dentry;
57} ext4_dx_sort_entry_t;
58
[db8fb43]59/** Get hash version used in directory index.
60 *
[38542dc]61 * @param root_info Pointer to root info structure of index
62 *
63 * @return Hash algorithm version
64 *
[db8fb43]65 */
[343ccfd]66uint8_t ext4_directory_dx_root_info_get_hash_version(
[38542dc]67 ext4_directory_dx_root_info_t *root_info)
[343ccfd]68{
69 return root_info->hash_version;
70}
71
[db8fb43]72/** Set hash version, that will be used in directory index.
73 *
[38542dc]74 * @param root_info Pointer to root info structure of index
75 * @param version Hash algorithm version
76 *
[db8fb43]77 */
[343ccfd]78void ext4_directory_dx_root_info_set_hash_version(
[38542dc]79 ext4_directory_dx_root_info_t *root_info, uint8_t version)
[343ccfd]80{
81 root_info->hash_version = version;
82}
83
[db8fb43]84/** Get length of root_info structure in bytes.
85 *
[38542dc]86 * @param root_info Pointer to root info structure of index
87 *
88 * @return Length of the structure
89 *
[db8fb43]90 */
[343ccfd]91uint8_t ext4_directory_dx_root_info_get_info_length(
[38542dc]92 ext4_directory_dx_root_info_t *root_info)
[343ccfd]93{
94 return root_info->info_length;
95}
96
[db8fb43]97/** Set length of root_info structure in bytes.
98 *
[38542dc]99 * @param root_info Pointer to root info structure of index
100 * @param info_length Length of the structure
101 *
[db8fb43]102 */
[343ccfd]103void ext4_directory_dx_root_info_set_info_length(
[38542dc]104 ext4_directory_dx_root_info_t *root_info, uint8_t info_length)
[343ccfd]105{
106 root_info->info_length = info_length;
107}
108
[db8fb43]109/** Get number of indirect levels of HTree.
110 *
[38542dc]111 * @param root_info Pointer to root info structure of index
112 *
113 * @return Height of HTree (actually only 0 or 1)
114 *
[db8fb43]115 */
[343ccfd]116uint8_t ext4_directory_dx_root_info_get_indirect_levels(
[38542dc]117 ext4_directory_dx_root_info_t *root_info)
[343ccfd]118{
119 return root_info->indirect_levels;
120}
121
[db8fb43]122/** Set number of indirect levels of HTree.
123 *
[38542dc]124 * @param root_info Pointer to root info structure of index
125 * @param levels Height of HTree (actually only 0 or 1)
126 *
[db8fb43]127 */
[343ccfd]128void ext4_directory_dx_root_info_set_indirect_levels(
[38542dc]129 ext4_directory_dx_root_info_t *root_info, uint8_t levels)
[343ccfd]130{
131 root_info->indirect_levels = levels;
132}
133
[db8fb43]134/** Get maximum number of index node entries.
135 *
[38542dc]136 * @param countlimit Pointer to counlimit structure
137 *
138 * @return Maximum of entries in node
139 *
[db8fb43]140 */
[343ccfd]141uint16_t ext4_directory_dx_countlimit_get_limit(
[38542dc]142 ext4_directory_dx_countlimit_t *countlimit)
[343ccfd]143{
144 return uint16_t_le2host(countlimit->limit);
145}
146
[db8fb43]147/** Set maximum number of index node entries.
148 *
[38542dc]149 * @param countlimit Pointer to counlimit structure
150 * @param limit Maximum of entries in node
151 *
[db8fb43]152 */
[343ccfd]153void ext4_directory_dx_countlimit_set_limit(
[38542dc]154 ext4_directory_dx_countlimit_t *countlimit, uint16_t limit)
[343ccfd]155{
156 countlimit->limit = host2uint16_t_le(limit);
157}
158
[db8fb43]159/** Get current number of index node entries.
160 *
[38542dc]161 * @param countlimit Pointer to counlimit structure
162 *
163 * @return Number of entries in node
164 *
[db8fb43]165 */
[343ccfd]166uint16_t ext4_directory_dx_countlimit_get_count(
[38542dc]167 ext4_directory_dx_countlimit_t *countlimit)
[343ccfd]168{
169 return uint16_t_le2host(countlimit->count);
170}
171
[db8fb43]172/** Set current number of index node entries.
173 *
[38542dc]174 * @param countlimit Pointer to counlimit structure
175 * @param count Number of entries in node
176 *
[db8fb43]177 */
[343ccfd]178void ext4_directory_dx_countlimit_set_count(
[38542dc]179 ext4_directory_dx_countlimit_t *countlimit, uint16_t count)
[343ccfd]180{
181 countlimit->count = host2uint16_t_le(count);
182}
183
[db8fb43]184/** Get hash value of index entry.
185 *
[38542dc]186 * @param entry Pointer to index entry
187 *
188 * @return Hash value
189 *
[db8fb43]190 */
[343ccfd]191uint32_t ext4_directory_dx_entry_get_hash(ext4_directory_dx_entry_t *entry)
192{
193 return uint32_t_le2host(entry->hash);
194}
195
[db8fb43]196/** Set hash value of index entry.
197 *
[38542dc]198 * @param entry Pointer to index entry
199 * @param hash Hash value
200 *
[db8fb43]201 */
[343ccfd]202void ext4_directory_dx_entry_set_hash(ext4_directory_dx_entry_t *entry,
[38542dc]203 uint32_t hash)
[343ccfd]204{
205 entry->hash = host2uint32_t_le(hash);
206}
207
[db8fb43]208/** Get block address where child node is located.
209 *
[38542dc]210 * @param entry Pointer to index entry
211 *
212 * @return Block address of child node
213 *
[db8fb43]214 */
[343ccfd]215uint32_t ext4_directory_dx_entry_get_block(ext4_directory_dx_entry_t *entry)
216{
217 return uint32_t_le2host(entry->block);
218}
219
[db8fb43]220/** Set block address where child node is located.
221 *
[38542dc]222 * @param entry Pointer to index entry
223 * @param block Block address of child node
224 *
[db8fb43]225 */
[343ccfd]226void ext4_directory_dx_entry_set_block(ext4_directory_dx_entry_t *entry,
[38542dc]227 uint32_t block)
[343ccfd]228{
229 entry->block = host2uint32_t_le(block);
230}
231
[e6f6260]232/** Initialize index structure of new directory.
[db8fb43]233 *
[38542dc]234 * @param dir Pointer to directory i-node
235 *
236 * @return Error code
237 *
[db8fb43]238 */
[7eb033ce]239int ext4_directory_dx_init(ext4_inode_ref_t *dir)
240{
[06d85e5]241 /* Load block 0, where will be index root located */
[7eb033ce]242 uint32_t fblock;
[38542dc]243 int rc = ext4_filesystem_get_inode_data_block_index(dir, 0,
244 &fblock);
245 if (rc != EOK)
[7eb033ce]246 return rc;
[38542dc]247
[7eb033ce]248 block_t *block;
249 rc = block_get(&block, dir->fs->device, fblock, BLOCK_FLAGS_NONE);
[38542dc]250 if (rc != EOK)
[7eb033ce]251 return rc;
[38542dc]252
[06d85e5]253 /* Initialize pointers to data structures */
[7eb033ce]254 ext4_directory_dx_root_t *root = block->data;
255 ext4_directory_dx_root_info_t *info = &(root->info);
[38542dc]256
[06d85e5]257 /* Initialize root info structure */
[7eb033ce]258 uint8_t hash_version =
[38542dc]259 ext4_superblock_get_default_hash_version(dir->fs->superblock);
260
[7eb033ce]261 ext4_directory_dx_root_info_set_hash_version(info, hash_version);
262 ext4_directory_dx_root_info_set_indirect_levels(info, 0);
263 ext4_directory_dx_root_info_set_info_length(info, 8);
[38542dc]264
[06d85e5]265 /* Set limit and current number of entries */
[7eb033ce]266 ext4_directory_dx_countlimit_t *countlimit =
[38542dc]267 (ext4_directory_dx_countlimit_t *) &root->entries;
[7eb033ce]268 ext4_directory_dx_countlimit_set_count(countlimit, 1);
[38542dc]269
270 uint32_t block_size =
271 ext4_superblock_get_block_size(dir->fs->superblock);
272 uint32_t entry_space =
273 block_size - 2 * sizeof(ext4_directory_dx_dot_entry_t) -
274 sizeof(ext4_directory_dx_root_info_t);
[7eb033ce]275 uint16_t root_limit = entry_space / sizeof(ext4_directory_dx_entry_t);
276 ext4_directory_dx_countlimit_set_limit(countlimit, root_limit);
[38542dc]277
[06d85e5]278 /* Append new block, where will be new entries inserted in the future */
[7eb033ce]279 uint32_t iblock;
280 rc = ext4_filesystem_append_inode_block(dir, &fblock, &iblock);
281 if (rc != EOK) {
282 block_put(block);
283 return rc;
284 }
[38542dc]285
[7eb033ce]286 block_t *new_block;
287 rc = block_get(&new_block, dir->fs->device, fblock, BLOCK_FLAGS_NOREAD);
288 if (rc != EOK) {
289 block_put(block);
290 return rc;
291 }
[38542dc]292
[06d85e5]293 /* Fill the whole block with empty entry */
[7eb033ce]294 ext4_directory_entry_ll_t *block_entry = new_block->data;
295 ext4_directory_entry_ll_set_entry_length(block_entry, block_size);
296 ext4_directory_entry_ll_set_inode(block_entry, 0);
[38542dc]297
[7eb033ce]298 new_block->dirty = true;
299 rc = block_put(new_block);
300 if (rc != EOK) {
301 block_put(block);
302 return rc;
303 }
[38542dc]304
[06d85e5]305 /* Connect new block to the only entry in index */
[7eb033ce]306 ext4_directory_dx_entry_t *entry = root->entries;
307 ext4_directory_dx_entry_set_block(entry, iblock);
[38542dc]308
[7eb033ce]309 block->dirty = true;
[38542dc]310
311 return block_put(block);
[7eb033ce]312}
[343ccfd]313
[e6f6260]314/** Initialize hash info structure necessary for index operations.
315 *
[38542dc]316 * @param hinfo Pointer to hinfo to be initialized
317 * @param root_block Root block (number 0) of index
318 * @param sb Pointer to superblock
319 * @param name_len Length of name to be computed hash value from
320 * @param name Name to be computed hash value from
321 *
322 * @return Error code
323 *
[e6f6260]324 */
[38542dc]325static int ext4_directory_hinfo_init(ext4_hash_info_t *hinfo,
326 block_t *root_block, ext4_superblock_t *sb, size_t name_len,
327 const char *name)
[0dc91833]328{
[38542dc]329 ext4_directory_dx_root_t *root =
330 (ext4_directory_dx_root_t *) root_block->data;
331
332 if ((root->info.hash_version != EXT4_HASH_VERSION_TEA) &&
333 (root->info.hash_version != EXT4_HASH_VERSION_HALF_MD4) &&
334 (root->info.hash_version != EXT4_HASH_VERSION_LEGACY))
[0dc91833]335 return EXT4_ERR_BAD_DX_DIR;
[38542dc]336
[06d85e5]337 /* Check unused flags */
[38542dc]338 if (root->info.unused_flags != 0)
[0dc91833]339 return EXT4_ERR_BAD_DX_DIR;
[38542dc]340
[06d85e5]341 /* Check indirect levels */
[38542dc]342 if (root->info.indirect_levels > 1)
[0dc91833]343 return EXT4_ERR_BAD_DX_DIR;
[38542dc]344
[06d85e5]345 /* Check if node limit is correct */
[d9bbe45]346 uint32_t block_size = ext4_superblock_get_block_size(sb);
347 uint32_t entry_space = block_size;
[0dc91833]348 entry_space -= 2 * sizeof(ext4_directory_dx_dot_entry_t);
349 entry_space -= sizeof(ext4_directory_dx_root_info_t);
[38542dc]350 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t);
351
352 uint16_t limit = ext4_directory_dx_countlimit_get_limit(
353 (ext4_directory_dx_countlimit_t *) &root->entries);
354 if (limit != entry_space)
355 return EXT4_ERR_BAD_DX_DIR;
356
357 /* Check hash version and modify if necessary */
358 hinfo->hash_version =
359 ext4_directory_dx_root_info_get_hash_version(&root->info);
360 if ((hinfo->hash_version <= EXT4_HASH_VERSION_TEA) &&
361 (ext4_superblock_has_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
[06d85e5]362 /* 3 is magic from ext4 linux implementation */
[0dc91833]363 hinfo->hash_version += 3;
364 }
[38542dc]365
[06d85e5]366 /* Load hash seed from superblock */
[0dc91833]367 hinfo->seed = ext4_superblock_get_hash_seed(sb);
[38542dc]368
[06d85e5]369 /* Compute hash value of name */
[38542dc]370 if (name)
[0dc91833]371 ext4_hash_string(hinfo, name_len, name);
[38542dc]372
[0dc91833]373 return EOK;
374}
375
[e6f6260]376/** Walk through index tree and load leaf with corresponding hash value.
377 *
[38542dc]378 * @param hinfo Initialized hash info structure
379 * @param inode_ref Current i-node
380 * @param root_block Root block (iblock 0), where is root node located
381 * @param dx_block Pointer to leaf node in dx_blocks array
382 * @param dx_blocks Array with the whole path from root to leaf
383 *
384 * @return Error code
385 *
[e6f6260]386 */
[0dc91833]387static int ext4_directory_dx_get_leaf(ext4_hash_info_t *hinfo,
[38542dc]388 ext4_inode_ref_t *inode_ref, block_t *root_block,
389 ext4_directory_dx_block_t **dx_block, ext4_directory_dx_block_t *dx_blocks)
[0dc91833]390{
391 ext4_directory_dx_block_t *tmp_dx_block = dx_blocks;
[38542dc]392 ext4_directory_dx_root_t *root =
393 (ext4_directory_dx_root_t *) root_block->data;
394 ext4_directory_dx_entry_t *entries =
395 (ext4_directory_dx_entry_t *) &root->entries;
396
397 uint16_t limit = ext4_directory_dx_countlimit_get_limit(
398 (ext4_directory_dx_countlimit_t *) entries);
399 uint8_t indirect_level =
400 ext4_directory_dx_root_info_get_indirect_levels(&root->info);
401
[d9bbe45]402 block_t *tmp_block = root_block;
[38542dc]403 ext4_directory_dx_entry_t *p;
404 ext4_directory_dx_entry_t *q;
405 ext4_directory_dx_entry_t *m;
406 ext4_directory_dx_entry_t *at;
407
[06d85e5]408 /* Walk through the index tree */
[0dc91833]409 while (true) {
[38542dc]410 uint16_t count = ext4_directory_dx_countlimit_get_count(
411 (ext4_directory_dx_countlimit_t *) entries);
412 if ((count == 0) || (count > limit))
[0dc91833]413 return EXT4_ERR_BAD_DX_DIR;
[38542dc]414
[06d85e5]415 /* Do binary search in every node */
[0dc91833]416 p = entries + 1;
417 q = entries + count - 1;
[38542dc]418
[0dc91833]419 while (p <= q) {
420 m = p + (q - p) / 2;
[38542dc]421 if (ext4_directory_dx_entry_get_hash(m) > hinfo->hash)
[0dc91833]422 q = m - 1;
[38542dc]423 else
[0dc91833]424 p = m + 1;
425 }
[38542dc]426
[0dc91833]427 at = p - 1;
[38542dc]428
[06d85e5]429 /* Write results */
[0dc91833]430 tmp_dx_block->block = tmp_block;
431 tmp_dx_block->entries = entries;
432 tmp_dx_block->position = at;
[38542dc]433
[06d85e5]434 /* Is algorithm in the leaf? */
[38542dc]435 if (indirect_level == 0) {
436 *dx_block = tmp_dx_block;
437 return EOK;
438 }
439
440 /* Goto child node */
[d9bbe45]441 uint32_t next_block = ext4_directory_dx_entry_get_block(at);
[38542dc]442
443 indirect_level--;
444
445 uint32_t fblock;
446 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref,
447 next_block, &fblock);
448 if (rc != EOK)
449 return rc;
450
451 rc = block_get(&tmp_block, inode_ref->fs->device, fblock,
452 BLOCK_FLAGS_NONE);
453 if (rc != EOK)
454 return rc;
455
[0dc91833]456 entries = ((ext4_directory_dx_node_t *) tmp_block->data)->entries;
[1ac1ab4]457 limit = ext4_directory_dx_countlimit_get_limit(
[38542dc]458 (ext4_directory_dx_countlimit_t *) entries);
459
460 uint16_t entry_space =
461 ext4_superblock_get_block_size(inode_ref->fs->superblock) -
462 sizeof(ext4_directory_dx_dot_entry_t);
463 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t);
464
[0dc91833]465 if (limit != entry_space) {
466 block_put(tmp_block);
[38542dc]467 return EXT4_ERR_BAD_DX_DIR;
[0dc91833]468 }
[38542dc]469
[0dc91833]470 ++tmp_dx_block;
471 }
[38542dc]472
[06d85e5]473 /* Unreachable */
[0dc91833]474 return EOK;
475}
476
[e6f6260]477/** Check if the the next block would be checked during entry search.
478 *
[38542dc]479 * @param inode_ref Directory i-node
480 * @param hash Hash value to check
481 * @param dx_block Current block
482 * @param dx_blocks Array with path from root to leaf node
483 *
484 * @return Error code
485 *
[e6f6260]486 */
[38542dc]487static int ext4_directory_dx_next_block(ext4_inode_ref_t *inode_ref,
488 uint32_t hash, ext4_directory_dx_block_t *dx_block,
489 ext4_directory_dx_block_t *dx_blocks)
[0dc91833]490{
[38542dc]491 uint32_t num_handles = 0;
492 ext4_directory_dx_block_t *p = dx_block;
493
494 /* Try to find data block with next bunch of entries */
495 while (true) {
496 p->position++;
497 uint16_t count = ext4_directory_dx_countlimit_get_count(
498 (ext4_directory_dx_countlimit_t *) p->entries);
499
500 if (p->position < p->entries + count)
501 break;
502
503 if (p == dx_blocks)
504 return EOK;
505
506 num_handles++;
507 p--;
508 }
509
510 /* Check hash collision (if not occured - no next block cannot be used) */
511 uint32_t current_hash = ext4_directory_dx_entry_get_hash(p->position);
512 if ((hash & 1) == 0) {
513 if ((current_hash & ~1) != hash)
514 return 0;
515 }
516
517 /* Fill new path */
518 while (num_handles--) {
519 uint32_t block_idx =
520 ext4_directory_dx_entry_get_block(p->position);
521 uint32_t block_addr;
522
523 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref,
524 block_idx, &block_addr);
525 if (rc != EOK)
526 return rc;
527
528 block_t *block;
529 rc = block_get(&block, inode_ref->fs->device, block_addr, BLOCK_FLAGS_NONE);
530 if (rc != EOK)
531 return rc;
532
533 p++;
534
535 /* Don't forget to put old block (prevent memory leak) */
[e5a1ace3]536 rc = block_put(p->block);
537 if (rc != EOK)
538 return rc;
[38542dc]539
540 p->block = block;
541 p->entries = ((ext4_directory_dx_node_t *) block->data)->entries;
542 p->position = p->entries;
543 }
544
545 return ENOENT;
[0dc91833]546}
547
[e6f6260]548/** Try to find directory entry using directory index.
549 *
[38542dc]550 * @param result Output value - if entry will be found,
551 * than will be passed through this parameter
552 * @param inode_ref Directory i-node
553 * @param name_len Length of name to be found
554 * @param name Name to be found
555 *
556 * @return Error code
557 *
[e6f6260]558 */
[7689590]559int ext4_directory_dx_find_entry(ext4_directory_search_result_t *result,
[38542dc]560 ext4_inode_ref_t *inode_ref, size_t name_len, const char *name)
[0dc91833]561{
[06d85e5]562 /* Load direct block 0 (index root) */
[d9bbe45]563 uint32_t root_block_addr;
[e5a1ace3]564 int rc2;
[38542dc]565 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 0,
566 &root_block_addr);
567 if (rc != EOK)
[0dc91833]568 return rc;
[38542dc]569
[1ac1ab4]570 ext4_filesystem_t *fs = inode_ref->fs;
[38542dc]571
[d9bbe45]572 block_t *root_block;
[38542dc]573 rc = block_get(&root_block, fs->device, root_block_addr,
574 BLOCK_FLAGS_NONE);
575 if (rc != EOK)
[0dc91833]576 return rc;
[38542dc]577
[06d85e5]578 /* Initialize hash info (compute hash value) */
[d9bbe45]579 ext4_hash_info_t hinfo;
[38542dc]580 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock,
581 name_len, name);
[0dc91833]582 if (rc != EOK) {
583 block_put(root_block);
584 return EXT4_ERR_BAD_DX_DIR;
585 }
[38542dc]586
587 /*
588 * Hardcoded number 2 means maximum height of index tree,
589 * specified in the Linux driver.
590 */
[d9bbe45]591 ext4_directory_dx_block_t dx_blocks[2];
[38542dc]592 ext4_directory_dx_block_t *dx_block;
593 ext4_directory_dx_block_t *tmp;
594
595 rc = ext4_directory_dx_get_leaf(&hinfo, inode_ref, root_block,
596 &dx_block, dx_blocks);
[0dc91833]597 if (rc != EOK) {
598 block_put(root_block);
599 return EXT4_ERR_BAD_DX_DIR;
600 }
[38542dc]601
[d9bbe45]602 do {
[06d85e5]603 /* Load leaf block */
[38542dc]604 uint32_t leaf_block_idx =
605 ext4_directory_dx_entry_get_block(dx_block->position);
[d9bbe45]606 uint32_t leaf_block_addr;
[38542dc]607
608 rc = ext4_filesystem_get_inode_data_block_index(inode_ref,
609 leaf_block_idx, &leaf_block_addr);
610 if (rc != EOK)
[e63ce679]611 goto cleanup;
[38542dc]612
613 block_t *leaf_block;
614 rc = block_get(&leaf_block, fs->device, leaf_block_addr,
615 BLOCK_FLAGS_NONE);
616 if (rc != EOK)
617 goto cleanup;
618
[06d85e5]619 /* Linear search inside block */
[d9bbe45]620 ext4_directory_entry_ll_t *res_dentry;
[38542dc]621 rc = ext4_directory_find_in_block(leaf_block, fs->superblock,
622 name_len, name, &res_dentry);
623
[06d85e5]624 /* Found => return it */
[7689590]625 if (rc == EOK) {
626 result->block = leaf_block;
627 result->dentry = res_dentry;
[e8d054a]628 goto cleanup;
[0dc91833]629 }
[38542dc]630
[06d85e5]631 /* Not found, leave untouched */
[e5a1ace3]632 rc2 = block_put(leaf_block);
633 if (rc2 != EOK)
634 goto cleanup;
[38542dc]635
636 if (rc != ENOENT)
[e63ce679]637 goto cleanup;
[38542dc]638
[06d85e5]639 /* check if the next block could be checked */
[38542dc]640 rc = ext4_directory_dx_next_block(inode_ref, hinfo.hash,
641 dx_block, &dx_blocks[0]);
[e5a1ace3]642 if (rc != EOK)
[e63ce679]643 goto cleanup;
[e5a1ace3]644
[38542dc]645 } while (rc == ENOENT);
646
[06d85e5]647 /* Entry not found */
[e8d054a]648 rc = ENOENT;
[38542dc]649
[e63ce679]650cleanup:
[06d85e5]651 /* The whole path must be released (preventing memory leak) */
[e63ce679]652 tmp = dx_blocks;
[38542dc]653
[e63ce679]654 while (tmp <= dx_block) {
[e5a1ace3]655 rc2 = block_put(tmp->block);
656 if (rc == EOK && rc2 != EOK)
657 rc = rc2;
[e63ce679]658 ++tmp;
659 }
[38542dc]660
[e63ce679]661 return rc;
[0dc91833]662}
663
[e6f6260]664/** Compare function used to pass in quicksort implementation.
665 *
666 * It can compare two entries by hash value.
667 *
[38542dc]668 * @param arg1 First entry
669 * @param arg2 Second entry
670 * @param dummy Unused parameter, can be NULL
671 *
672 * @return Classic compare result
673 * (0: equal, -1: arg1 < arg2, 1: arg1 > arg2)
674 *
[e6f6260]675 */
[b191acae]676static int ext4_directory_dx_entry_comparator(void *arg1, void *arg2, void *dummy)
[f577058]677{
678 ext4_dx_sort_entry_t *entry1 = arg1;
679 ext4_dx_sort_entry_t *entry2 = arg2;
[38542dc]680
681 if (entry1->hash == entry2->hash)
[f577058]682 return 0;
[38542dc]683
684 if (entry1->hash < entry2->hash)
[f577058]685 return -1;
[38542dc]686 else
[f577058]687 return 1;
688}
689
[e6f6260]690/** Insert new index entry to block.
691 *
692 * Note that space for new entry must be checked by caller.
693 *
[38542dc]694 * @param index_block Block where to insert new entry
695 * @param hash Hash value covered by child node
696 * @param iblock Logical number of child block
[e6f6260]697 *
698 */
[c0964cd7]699static void ext4_directory_dx_insert_entry(
[38542dc]700 ext4_directory_dx_block_t *index_block, uint32_t hash, uint32_t iblock)
[c0964cd7]701{
702 ext4_directory_dx_entry_t *old_index_entry = index_block->position;
703 ext4_directory_dx_entry_t *new_index_entry = old_index_entry + 1;
[38542dc]704
[c0964cd7]705 ext4_directory_dx_countlimit_t *countlimit =
[38542dc]706 (ext4_directory_dx_countlimit_t *) index_block->entries;
[c0964cd7]707 uint32_t count = ext4_directory_dx_countlimit_get_count(countlimit);
[38542dc]708
[c0964cd7]709 ext4_directory_dx_entry_t *start_index = index_block->entries;
[38542dc]710 size_t bytes = (void *) (start_index + count) - (void *) (new_index_entry);
711
[c0964cd7]712 memmove(new_index_entry + 1, new_index_entry, bytes);
[38542dc]713
[c0964cd7]714 ext4_directory_dx_entry_set_block(new_index_entry, iblock);
715 ext4_directory_dx_entry_set_hash(new_index_entry, hash);
[38542dc]716
[c0964cd7]717 ext4_directory_dx_countlimit_set_count(countlimit, count + 1);
[38542dc]718
[c0964cd7]719 index_block->block->dirty = true;
720}
721
[e6f6260]722/** Split directory entries to two parts preventing node overflow.
723 *
[38542dc]724 * @param inode_ref Directory i-node
725 * @param hinfo Hash info
726 * @param old_data_block Block with data to be split
727 * @param index_block Block where index entries are located
728 * @param new_data_block Output value for newly allocated data block
729 *
[e6f6260]730 */
731static int ext4_directory_dx_split_data(ext4_inode_ref_t *inode_ref,
[38542dc]732 ext4_hash_info_t *hinfo, block_t *old_data_block,
733 ext4_directory_dx_block_t *index_block, block_t **new_data_block)
[f577058]734{
[d0d7afb]735 int rc = EOK;
[38542dc]736
[06d85e5]737 /* Allocate buffer for directory entries */
[e6f6260]738 uint32_t block_size =
[38542dc]739 ext4_superblock_get_block_size(inode_ref->fs->superblock);
[f577058]740 void *entry_buffer = malloc(block_size);
[38542dc]741 if (entry_buffer == NULL)
[f577058]742 return ENOMEM;
[38542dc]743
[06d85e5]744 /* dot entry has the smallest size available */
[38542dc]745 uint32_t max_entry_count =
746 block_size / sizeof(ext4_directory_dx_dot_entry_t);
747
[06d85e5]748 /* Allocate sort entry */
[38542dc]749 ext4_dx_sort_entry_t *sort_array =
750 malloc(max_entry_count * sizeof(ext4_dx_sort_entry_t));
[f577058]751 if (sort_array == NULL) {
752 free(entry_buffer);
753 return ENOMEM;
754 }
[38542dc]755
[1d68621]756 uint32_t idx = 0;
[ccac91e]757 uint32_t real_size = 0;
[38542dc]758
[06d85e5]759 /* Initialize hinfo */
[1d68621]760 ext4_hash_info_t tmp_hinfo;
761 memcpy(&tmp_hinfo, hinfo, sizeof(ext4_hash_info_t));
[38542dc]762
[06d85e5]763 /* Load all valid entries to the buffer */
[e8d054a]764 ext4_directory_entry_ll_t *dentry = old_data_block->data;
765 void *entry_buffer_ptr = entry_buffer;
[ccac91e]766 while ((void *)dentry < old_data_block->data + block_size) {
[06d85e5]767 /* Read only valid entries */
[412f813]768 if (ext4_directory_entry_ll_get_inode(dentry) != 0) {
[e6f6260]769 uint8_t len = ext4_directory_entry_ll_get_name_length(
[38542dc]770 inode_ref->fs->superblock, dentry);
771 ext4_hash_string(&tmp_hinfo, len, (char *) dentry->name);
772
[412f813]773 uint32_t rec_len = 8 + len;
[38542dc]774
775 if ((rec_len % 4) != 0)
[412f813]776 rec_len += 4 - (rec_len % 4);
[38542dc]777
[412f813]778 memcpy(entry_buffer_ptr, dentry, rec_len);
[38542dc]779
[412f813]780 sort_array[idx].dentry = entry_buffer_ptr;
781 sort_array[idx].rec_len = rec_len;
782 sort_array[idx].hash = tmp_hinfo.hash;
[38542dc]783
[412f813]784 entry_buffer_ptr += rec_len;
785 real_size += rec_len;
786 idx++;
787 }
[38542dc]788
789 dentry = (void *) dentry +
790 ext4_directory_entry_ll_get_entry_length(dentry);
[f577058]791 }
[38542dc]792
[06d85e5]793 /* Sort all entries */
[5b16912]794 qsort(sort_array, idx, sizeof(ext4_dx_sort_entry_t),
[38542dc]795 ext4_directory_dx_entry_comparator, NULL);
796
[06d85e5]797 /* Allocate new block for store the second part of entries */
[f577058]798 uint32_t new_fblock;
[c4f318d6]799 uint32_t new_iblock;
[38542dc]800 rc = ext4_filesystem_append_inode_block(inode_ref, &new_fblock,
801 &new_iblock);
[f577058]802 if (rc != EOK) {
803 free(sort_array);
804 free(entry_buffer);
805 return rc;
806 }
[38542dc]807
[06d85e5]808 /* Load new block */
[ccac91e]809 block_t *new_data_block_tmp;
[e6f6260]810 rc = block_get(&new_data_block_tmp, inode_ref->fs->device,
[38542dc]811 new_fblock, BLOCK_FLAGS_NOREAD);
[ccac91e]812 if (rc != EOK) {
813 free(sort_array);
814 free(entry_buffer);
815 return rc;
816 }
[38542dc]817
818 /*
819 * Distribute entries to two blocks (by size)
[06d85e5]820 * - compute the half
821 */
[ccac91e]822 uint32_t new_hash = 0;
823 uint32_t current_size = 0;
[1d68621]824 uint32_t mid = 0;
825 for (uint32_t i = 0; i < idx; ++i) {
826 if ((current_size + sort_array[i].rec_len) > (real_size / 2)) {
[ccac91e]827 new_hash = sort_array[i].hash;
828 mid = i;
829 break;
830 }
[38542dc]831
[ccac91e]832 current_size += sort_array[i].rec_len;
833 }
[38542dc]834
[06d85e5]835 /* Check hash collision */
[412f813]836 uint32_t continued = 0;
[38542dc]837 if (new_hash == sort_array[mid-1].hash)
[412f813]838 continued = 1;
[38542dc]839
[ccac91e]840 uint32_t offset = 0;
841 void *ptr;
[38542dc]842
[06d85e5]843 /* First part - to the old block */
[1d68621]844 for (uint32_t i = 0; i < mid; ++i) {
[ccac91e]845 ptr = old_data_block->data + offset;
846 memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
[38542dc]847
[ccac91e]848 ext4_directory_entry_ll_t *tmp = ptr;
[38542dc]849 if (i < (mid - 1))
850 ext4_directory_entry_ll_set_entry_length(tmp,
851 sort_array[i].rec_len);
852 else
853 ext4_directory_entry_ll_set_entry_length(tmp,
854 block_size - offset);
855
[ccac91e]856 offset += sort_array[i].rec_len;
857 }
[38542dc]858
[06d85e5]859 /* Second part - to the new block */
[ccac91e]860 offset = 0;
[1d68621]861 for (uint32_t i = mid; i < idx; ++i) {
[ccac91e]862 ptr = new_data_block_tmp->data + offset;
863 memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
[38542dc]864
[ccac91e]865 ext4_directory_entry_ll_t *tmp = ptr;
[38542dc]866 if (i < (idx - 1))
867 ext4_directory_entry_ll_set_entry_length(tmp,
868 sort_array[i].rec_len);
869 else
870 ext4_directory_entry_ll_set_entry_length(tmp,
871 block_size - offset);
872
[ccac91e]873 offset += sort_array[i].rec_len;
874 }
[38542dc]875
[06d85e5]876 /* Do some steps to finish operation */
[ccac91e]877 old_data_block->dirty = true;
878 new_data_block_tmp->dirty = true;
[38542dc]879
[ccac91e]880 free(sort_array);
881 free(entry_buffer);
[38542dc]882
883 ext4_directory_dx_insert_entry(index_block, new_hash + continued,
884 new_iblock);
885
[ccac91e]886 *new_data_block = new_data_block_tmp;
[38542dc]887
[f577058]888 return EOK;
889}
890
[dfac604]891/** Split index node and maybe some parent nodes in the tree hierarchy.
[e6f6260]892 *
[38542dc]893 * @param inode_ref Directory i-node
894 * @param dx_blocks Array with path from root to leaf node
895 * @param dx_block Leaf block to be split if needed
896 *
897 * @return Error code
898 *
[e6f6260]899 */
[dfac604]900static int ext4_directory_dx_split_index(ext4_inode_ref_t *inode_ref,
901 ext4_directory_dx_block_t *dx_blocks, ext4_directory_dx_block_t *dx_block)
[565b6ff]902{
[2f2feadb]903 ext4_directory_dx_entry_t *entries;
[38542dc]904 if (dx_block == dx_blocks)
905 entries =
906 ((ext4_directory_dx_root_t *) dx_block->block->data)->entries;
907 else
908 entries =
909 ((ext4_directory_dx_node_t *) dx_block->block->data)->entries;
910
[2f2feadb]911 ext4_directory_dx_countlimit_t *countlimit =
[38542dc]912 (ext4_directory_dx_countlimit_t *) entries;
913
914 uint16_t leaf_limit =
915 ext4_directory_dx_countlimit_get_limit(countlimit);
916 uint16_t leaf_count =
917 ext4_directory_dx_countlimit_get_count(countlimit);
918
[06d85e5]919 /* Check if is necessary to split index block */
[1ebb66f]920 if (leaf_limit == leaf_count) {
[38542dc]921 size_t levels = dx_block - dx_blocks;
922
[2f2feadb]923 ext4_directory_dx_entry_t *root_entries =
[38542dc]924 ((ext4_directory_dx_root_t *) dx_blocks[0].block->data)->entries;
925
[2f2feadb]926 ext4_directory_dx_countlimit_t *root_countlimit =
[38542dc]927 (ext4_directory_dx_countlimit_t *) root_entries;
[2f2feadb]928 uint16_t root_limit =
[38542dc]929 ext4_directory_dx_countlimit_get_limit(root_countlimit);
[2f2feadb]930 uint16_t root_count =
[38542dc]931 ext4_directory_dx_countlimit_get_count(root_countlimit);
932
[06d85e5]933 /* Linux limitation */
[38542dc]934 if ((levels > 0) && (root_limit == root_count))
[2f2feadb]935 return ENOSPC;
[38542dc]936
[06d85e5]937 /* Add new block to directory */
[c0964cd7]938 uint32_t new_fblock;
939 uint32_t new_iblock;
[38542dc]940 int rc = ext4_filesystem_append_inode_block(inode_ref,
941 &new_fblock, &new_iblock);
942 if (rc != EOK)
[2f2feadb]943 return rc;
[38542dc]944
[06d85e5]945 /* load new block */
[38542dc]946 block_t *new_block;
[dfac604]947 rc = block_get(&new_block, inode_ref->fs->device,
[38542dc]948 new_fblock, BLOCK_FLAGS_NOREAD);
949 if (rc != EOK)
[2f2feadb]950 return rc;
[38542dc]951
[6f731f0a]952 ext4_directory_dx_node_t *new_node = new_block->data;
953 ext4_directory_dx_entry_t *new_entries = new_node->entries;
[38542dc]954
955 uint32_t block_size =
956 ext4_superblock_get_block_size(inode_ref->fs->superblock);
957
[06d85e5]958 /* Split leaf node */
[c0964cd7]959 if (levels > 0) {
960 uint32_t count_left = leaf_count / 2;
961 uint32_t count_right = leaf_count - count_left;
[2f2feadb]962 uint32_t hash_right =
[38542dc]963 ext4_directory_dx_entry_get_hash(entries + count_left);
964
[06d85e5]965 /* Copy data to new node */
[c0964cd7]966 memcpy((void *) new_entries, (void *) (entries + count_left),
[38542dc]967 count_right * sizeof(ext4_directory_dx_entry_t));
968
[06d85e5]969 /* Initialize new node */
[2f2feadb]970 ext4_directory_dx_countlimit_t *left_countlimit =
[38542dc]971 (ext4_directory_dx_countlimit_t *) entries;
[2f2feadb]972 ext4_directory_dx_countlimit_t *right_countlimit =
[38542dc]973 (ext4_directory_dx_countlimit_t *) new_entries;
974
[c0964cd7]975 ext4_directory_dx_countlimit_set_count(left_countlimit, count_left);
976 ext4_directory_dx_countlimit_set_count(right_countlimit, count_right);
[38542dc]977
978 uint32_t entry_space =
979 block_size - sizeof(ext4_fake_directory_entry_t);
980 uint32_t node_limit =
981 entry_space / sizeof(ext4_directory_dx_entry_t);
[2f2feadb]982 ext4_directory_dx_countlimit_set_limit(right_countlimit, node_limit);
[38542dc]983
[06d85e5]984 /* Which index block is target for new entry */
[2f2feadb]985 uint32_t position_index = (dx_block->position - dx_block->entries);
986 if (position_index >= count_left) {
987 dx_block->block->dirty = true;
[38542dc]988
[2f2feadb]989 block_t *block_tmp = dx_block->block;
990 dx_block->block = new_block;
[38542dc]991 dx_block->position =
992 new_entries + position_index - count_left;
[2f2feadb]993 dx_block->entries = new_entries;
[38542dc]994
[2f2feadb]995 new_block = block_tmp;
996 }
[38542dc]997
[06d85e5]998 /* Finally insert new entry */
[2f2feadb]999 ext4_directory_dx_insert_entry(dx_blocks, hash_right, new_iblock);
[38542dc]1000
[2f2feadb]1001 return block_put(new_block);
[c0964cd7]1002 } else {
[06d85e5]1003 /* Create second level index */
[38542dc]1004
[06d85e5]1005 /* Copy data from root to child block */
[6f731f0a]1006 memcpy((void *) new_entries, (void *) entries,
[38542dc]1007 leaf_count * sizeof(ext4_directory_dx_entry_t));
1008
[6f731f0a]1009 ext4_directory_dx_countlimit_t *new_countlimit =
[38542dc]1010 (ext4_directory_dx_countlimit_t *) new_entries;
1011
1012 uint32_t entry_space =
1013 block_size - sizeof(ext4_fake_directory_entry_t);
1014 uint32_t node_limit =
1015 entry_space / sizeof(ext4_directory_dx_entry_t);
[2f2feadb]1016 ext4_directory_dx_countlimit_set_limit(new_countlimit, node_limit);
[38542dc]1017
[06d85e5]1018 /* Set values in root node */
[2f2feadb]1019 ext4_directory_dx_countlimit_t *new_root_countlimit =
[38542dc]1020 (ext4_directory_dx_countlimit_t *) entries;
1021
[2f2feadb]1022 ext4_directory_dx_countlimit_set_count(new_root_countlimit, 1);
1023 ext4_directory_dx_entry_set_block(entries, new_iblock);
[38542dc]1024
1025 ((ext4_directory_dx_root_t *)
1026 dx_blocks[0].block->data)->info.indirect_levels = 1;
1027
[06d85e5]1028 /* Add new entry to the path */
[2f2feadb]1029 dx_block = dx_blocks + 1;
1030 dx_block->position = dx_block->position - entries + new_entries;
1031 dx_block->entries = new_entries;
1032 dx_block->block = new_block;
[c0964cd7]1033 }
[2f2feadb]1034 }
[38542dc]1035
[2f2feadb]1036 return EOK;
1037}
1038
[dfac604]1039/** Add new entry to indexed directory
1040 *
[38542dc]1041 * @param parent Directory i-node
1042 * @param child I-node to be referenced from directory entry
1043 * @param name Name of new directory entry
1044 *
1045 * @return Error code
1046 *
[dfac604]1047 */
[1ac1ab4]1048int ext4_directory_dx_add_entry(ext4_inode_ref_t *parent,
[38542dc]1049 ext4_inode_ref_t *child, const char *name)
[2f2feadb]1050{
1051 int rc2 = EOK;
[38542dc]1052
1053 /* Get direct block 0 (index root) */
[2f2feadb]1054 uint32_t root_block_addr;
[38542dc]1055 int rc = ext4_filesystem_get_inode_data_block_index(parent, 0,
1056 &root_block_addr);
1057 if (rc != EOK)
[2f2feadb]1058 return rc;
[38542dc]1059
[1ac1ab4]1060 ext4_filesystem_t *fs = parent->fs;
[38542dc]1061
[2f2feadb]1062 block_t *root_block;
[38542dc]1063 rc = block_get(&root_block, fs->device, root_block_addr,
1064 BLOCK_FLAGS_NONE);
1065 if (rc != EOK)
[2f2feadb]1066 return rc;
[38542dc]1067
[06d85e5]1068 /* Initialize hinfo structure (mainly compute hash) */
[38542dc]1069 uint32_t name_len = str_size(name);
[2f2feadb]1070 ext4_hash_info_t hinfo;
[38542dc]1071 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock,
1072 name_len, name);
[2f2feadb]1073 if (rc != EOK) {
1074 block_put(root_block);
1075 return EXT4_ERR_BAD_DX_DIR;
1076 }
[38542dc]1077
1078 /*
1079 * Hardcoded number 2 means maximum height of index
1080 * tree defined in Linux.
1081 */
[2f2feadb]1082 ext4_directory_dx_block_t dx_blocks[2];
[38542dc]1083 ext4_directory_dx_block_t *dx_block;
1084 ext4_directory_dx_block_t *dx_it;
1085
1086 rc = ext4_directory_dx_get_leaf(&hinfo, parent, root_block,
1087 &dx_block, dx_blocks);
[2f2feadb]1088 if (rc != EOK) {
1089 rc = EXT4_ERR_BAD_DX_DIR;
1090 goto release_index;
1091 }
[38542dc]1092
[06d85e5]1093 /* Try to insert to existing data block */
[38542dc]1094 uint32_t leaf_block_idx =
1095 ext4_directory_dx_entry_get_block(dx_block->position);
[2f2feadb]1096 uint32_t leaf_block_addr;
[38542dc]1097 rc = ext4_filesystem_get_inode_data_block_index(parent, leaf_block_idx,
1098 &leaf_block_addr);
1099 if (rc != EOK)
1100 goto release_index;
1101
1102 block_t *target_block;
1103 rc = block_get(&target_block, fs->device, leaf_block_addr,
1104 BLOCK_FLAGS_NONE);
1105 if (rc != EOK)
1106 goto release_index;
1107
1108 /* Check if insert operation passed */
1109 rc = ext4_directory_try_insert_entry(fs->superblock, target_block, child,
1110 name, name_len);
1111 if (rc == EOK)
1112 goto release_target_index;
1113
1114 /*
1115 * Check if there is needed to split index node
1116 * (and recursively also parent nodes)
1117 */
[dfac604]1118 rc = ext4_directory_dx_split_index(parent, dx_blocks, dx_block);
[38542dc]1119 if (rc != EOK)
[2f2feadb]1120 goto release_target_index;
[38542dc]1121
[06d85e5]1122 /* Split entries to two blocks (includes sorting by hash value) */
[c4f318d6]1123 block_t *new_block = NULL;
[38542dc]1124 rc = ext4_directory_dx_split_data(parent, &hinfo, target_block,
1125 dx_block, &new_block);
[c4f318d6]1126 if (rc != EOK) {
[e63ce679]1127 rc2 = rc;
1128 goto release_target_index;
[c4f318d6]1129 }
[38542dc]1130
[06d85e5]1131 /* Where to save new entry */
[38542dc]1132 uint32_t new_block_hash =
1133 ext4_directory_dx_entry_get_hash(dx_block->position + 1);
1134 if (hinfo.hash >= new_block_hash)
1135 rc = ext4_directory_try_insert_entry(fs->superblock, new_block,
1136 child, name, name_len);
1137 else
1138 rc = ext4_directory_try_insert_entry(fs->superblock, target_block,
1139 child, name, name_len);
1140
[06d85e5]1141 /* Cleanup */
[d0d7afb]1142 rc = block_put(new_block);
[38542dc]1143 if (rc != EOK)
[60b8b99]1144 return rc;
[38542dc]1145
[06d85e5]1146 /* Cleanup operations */
[38542dc]1147
[e63ce679]1148release_target_index:
[d0d7afb]1149 rc2 = rc;
[38542dc]1150
[412f813]1151 rc = block_put(target_block);
[38542dc]1152 if (rc != EOK)
[60b8b99]1153 return rc;
[38542dc]1154
[e63ce679]1155release_index:
[38542dc]1156 if (rc != EOK)
[60b8b99]1157 rc2 = rc;
[38542dc]1158
[e63ce679]1159 dx_it = dx_blocks;
[38542dc]1160
[c4f318d6]1161 while (dx_it <= dx_block) {
[412f813]1162 rc = block_put(dx_it->block);
[38542dc]1163 if (rc != EOK)
[60b8b99]1164 return rc;
[38542dc]1165
[c4f318d6]1166 dx_it++;
1167 }
[38542dc]1168
[d0d7afb]1169 return rc2;
[565b6ff]1170}
[0dc91833]1171
1172/**
1173 * @}
[38542dc]1174 */
Note: See TracBrowser for help on using the repository browser.