📄 extent40.c
字号:
/* Copyright (C) 2001-2005 by Hans Reiser, licensing governed by reiser4progs/COPYING. extent40.c -- reiser4 default extent plugin. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include "extent40.h"#include "extent40_repair.h"reiser4_core_t *extent40_core = NULL;/* Returns number of units in passed extent @place */uint32_t extent40_units(reiser4_place_t *place) { aal_assert("umka-1446", place != NULL);#ifdef ENABLE_DEBUG if (place->len % sizeof(extent40_t) != 0) { aal_error("Node (%llu), item (%u): Invalid extent " "item size (%u) detected.", place_blknr(place), place->pos.item, place->len); return 0; }#endif return place->len / sizeof(extent40_t);}/* Calculates extent size. */uint64_t extent40_offset(reiser4_place_t *place, uint32_t pos) { extent40_t *extent; uint64_t blocks = 0; uint32_t i; aal_assert("umka-2204", place != NULL); extent = extent40_body(place); for (i = 0; i < pos; i++, extent++) blocks += et40_get_width(extent); return blocks * place_blksize(place);}/* Builds the key of the unit at @pos and stores it inside passed @key variable. It is needed for updating item key after shifting, etc. */static errno_t extent40_fetch_key(reiser4_place_t *place, reiser4_key_t *key) { aal_assert("vpf-623", key != NULL); aal_assert("vpf-622", place != NULL); return body40_get_key(place, place->pos.unit, key, extent40_offset);}#ifndef ENABLE_MINIMAL/* Returns item size in bytes */static uint64_t extent40_size(reiser4_place_t *place) { uint32_t units = extent40_units(place); return extent40_offset(place, units);}/* Returns actual item size on disk */static uint64_t extent40_bytes(reiser4_place_t *place) { extent40_t *extent; uint64_t i, blocks; aal_assert("umka-2204", place != NULL); extent = extent40_body(place); /* Count only valuable units. */ for (blocks = 0, i = 0; i < extent40_units(place); i++, extent++) { if (et40_get_start(extent)) blocks += et40_get_width(extent); } return (blocks * place_blksize(place));}/* Gets the number of unit specified offset lies in. */uint32_t extent40_unit(reiser4_place_t *place, uint64_t offset) { uint32_t i; uint32_t width = 0; extent40_t *extent; extent = extent40_body(place); for (i = 0; i < extent40_units(place); i++, extent++) { width += et40_get_width(extent) * place_blksize(place); if (offset < width) return i; } return i;}/* Removes @count byte from passed @place at @pos */static errno_t extent40_remove_units(reiser4_place_t *place, trans_hint_t *hint) { uint32_t len; uint32_t pos; uint32_t units; void *src, *dst; aal_assert("vpf-941", place != NULL); aal_assert("umka-2402", hint != NULL); pos = place->pos.unit; units = extent40_units(place); /* Check for unit pos. */ if (pos == MAX_UINT32) pos = 0; aal_assert("umka-3026", pos + hint->count <= units); /* Calling @hint->region_func for removed region in order to let higher levels know that some extent region is released and perform some actions like release blocks in block allocator, etc. */ if (hint->region_func) { extent40_t *extent; uint32_t start; uint32_t width; uint32_t i; extent = extent40_body(place) + pos; for (i = pos; i < pos + hint->count; i++, extent++) { errno_t res; start = et40_get_start(extent); width = et40_get_width(extent); if (start != EXTENT_HOLE_UNIT) { if ((res = extent40_core->tree_ops.inc_free( place->node->tree, width))) { return res; } } if (start == EXTENT_UNALLOC_UNIT || start == EXTENT_HOLE_UNIT) continue; if ((res = hint->region_func(start, width, hint->data))) return res; } } /* Removing units from @pos to @hint->count. */ dst = extent40_body(place) + pos; src = extent40_body(place) + pos + hint->count; len = place->len - (pos + hint->count) * sizeof(extent40_t); aal_memmove(dst, src, len); /* Updating item's key by key of first unit. */ if (pos == 0) { if (extent40_fetch_key(place, &place->key)) return -EINVAL; } hint->overhead = 0; hint->len = sizeof(extent40_t) * hint->count; place_mkdirty(place); return 0;}/* Truncates extent item stating from left by @hint->count bytes. */static int64_t extent40_trunc_units(reiser4_place_t *place, trans_hint_t *hint){ int32_t size; uint32_t epos; uint32_t skip; uint64_t count; uint64_t esize; uint64_t offset; uint32_t blksize; reiser4_key_t key; extent40_t *extent; aal_assert("umka-2458", place != NULL); aal_assert("umka-2461", hint != NULL); hint->len = 0; hint->bytes = 0; hint->overhead = 0; /* Check for unit pos. */ if (place->pos.unit == MAX_UINT32) place->pos.unit = 0; blksize = place_blksize(place); extent = extent40_body(place) + place->pos.unit; offset = objcall(&hint->offset, get_offset); /* Get the amount of bytes that cannot be cut at the start. */ skip = (blksize - offset % blksize); if (skip == blksize) skip = 0; /* Set the start key offset to the block border. */ offset += skip; key = hint->offset; objcall(&key, set_offset, offset); /* Get the amount of bytes from @offset through the end of the item. */ offset -= objcall(&place->key, get_offset); esize = extent40_size(place) - offset; aal_assert("vpf-1759", offset % blksize == 0); /* Get number of blocks to be skipped within the unit. */ epos = (offset - extent40_offset(place, place->pos.unit)) / blksize; if (hint->count < skip) return hint->count; if ((count = hint->count - skip) > esize) count = esize; /* Loop though the units until @count of bytes are truncated. We do not increase @place->po.unit, because it will be the same for all ticks of the loop, as units will be removed fully or partially and this means, that @count is over. */ for (size = count; size > 0; ) { uint32_t remove; uint32_t start; uint32_t width; uint32_t eskip; errno_t res; uint32_t i; width = et40_get_width(extent); eskip = size == (int64_t)count ? epos : 0; aal_assert("vpf-1760", eskip < width); /* Calculating what is to be cut out. */ if ((remove = size / blksize) > width - eskip) remove = width - eskip; /* No one block needs to be removed anymore. */ if (remove == 0) break; aal_assert("vpf-1761", eskip == 0 || remove == width - eskip); aal_assert("vpf-1762", place->pos.unit == 0 || remove == width - eskip); /* Removing unit data from the cache */ for (i = 0; i < remove; i++) { aal_hash_table_remove(hint->blocks, &key); offset = objcall(&key, get_offset); objcall(&key, set_offset, (offset + blksize)); } start = et40_get_start(extent); if (start != EXTENT_HOLE_UNIT) { if ((res = extent40_core->tree_ops.inc_free( place->node->tree, remove))) { return res; } } /* Calling region remove notification function. */ if (start != EXTENT_HOLE_UNIT && start != EXTENT_UNALLOC_UNIT) { if ((res = hint->region_func(start + eskip, remove, hint->data))) { return res; } } if (start != EXTENT_HOLE_UNIT) hint->bytes += remove * blksize; /* Check if we remove whole unit. */ if (eskip) { et40_dec_width(extent, remove); hint->bytes += remove * blksize; } else if (remove < width) { if (start != EXTENT_HOLE_UNIT && start != EXTENT_UNALLOC_UNIT) { et40_inc_start(extent, remove); } et40_dec_width(extent, remove); hint->bytes += remove * blksize; } else { /* Here we remove whole unit. So, we count width blocks to be released, etc. */ hint->len += sizeof(extent40_t); /* Taking care about the rest of extent units if we're bot on the last unit. */ if (place->pos.unit < extent40_units(place) - 1) { uint32_t size = sizeof(extent40_t) * extent40_units(place) - (place->pos.unit + 1); aal_memmove(extent, extent + 1, size); } } size -= remove * blksize; } /* Updating key if it makes sense. */ if (place->pos.unit == 0 && epos == 0 && count) { offset = objcall(&place->key, get_offset); objcall(&place->key, set_offset, offset + count / blksize * blksize); } return count + skip;}/* Builds maximal real key in use for specified @place */errno_t extent40_maxreal_key(reiser4_place_t *place, reiser4_key_t *key) { aal_assert("vpf-438", key != NULL); aal_assert("vpf-437", place != NULL); return body40_maxreal_key(place, key, extent40_offset);}#endif/* Builds maximal possible key for the extent item */errno_t extent40_maxposs_key(reiser4_place_t *place, reiser4_key_t *key) { aal_assert("umka-1211", place != NULL); aal_assert("umka-1212", key != NULL); return body40_maxposs_key(place, key);}/* Performs lookup for specified @key inside the passed @place. Result of lookup will be stored in @pos. */lookup_t extent40_lookup(reiser4_place_t *place, lookup_hint_t *hint, lookup_bias_t bias){ uint64_t offset; uint64_t wanted; uint32_t i, units; extent40_t *extent; aal_assert("umka-1500", place != NULL); aal_assert("umka-1501", hint != NULL); extent = extent40_body(place); units = extent40_units(place); wanted = objcall(hint->key, get_offset); offset = objcall(&place->key, get_offset); for (i = 0; i < units; i++, extent++) { offset += (et40_get_width(extent) * place_blksize(place)); if (offset > wanted) { place->pos.unit = i; return PRESENT; } } place->pos.unit = units; return (bias == FIND_CONV ? PRESENT : ABSENT);}#ifndef ENABLE_MINIMAL/* Reads @count bytes of extent data from the extent item at passed @pos into specified @buff. Uses data cache. */static int64_t extent40_read_units(reiser4_place_t *place, trans_hint_t *hint){ void *buff; uint32_t i; errno_t res; uint64_t read; uint64_t count; uint32_t blksize; reiser4_key_t key; aal_block_t *block; uint64_t rel_offset; uint64_t read_offset; uint64_t block_offset; aal_assert("umka-1421", place != NULL); aal_assert("umka-1422", hint != NULL); count = hint->count; buff = hint->specific; if (place->pos.unit == MAX_UINT32) place->pos.unit = 0; extent40_fetch_key(place, &key); blksize = place_blksize(place); read = count; /* Initializing read offset */ read_offset = objcall(&hint->offset, get_offset); rel_offset = read_offset - objcall(&key, get_offset); /* Loop through the units until needed amount of data is read or extent item is over. */ for (i = place->pos.unit; i < extent40_units(place) && count > 0; i++) { uint32_t size; extent40_t *extent; uint64_t blk, start; extent = extent40_body(place); /* Calculating start block for read. */ start = et40_get_start(extent + i); blk = start + (rel_offset / blksize); if (start == EXTENT_HOLE_UNIT) { /* Handle the holes. Here we fill @buff by zeros, as hole is detected during read. */ uint64_t width = et40_get_width(extent + i) - (rel_offset / blksize); for (; width > 0 && count > 0; count -= size, buff += size, read_offset += size, width--) { uint32_t rest; rest = blksize - (read_offset % blksize); if ((size = count) > rest) size = rest; aal_memset(buff, 0, size); } } else while (blk < start + et40_get_width(extent + i) && count > 0) { /* Loop though the one unit. */ uint32_t rest; rest = blksize - (read_offset % blksize); if ((size = count) > rest) size = rest; /* Initilaizing offset of block needed data lie in. It is needed for getting block from data cache. */ block_offset = read_offset - (read_offset & (blksize - 1)); objcall(&key, set_offset, block_offset); /* Getting block from the cache. */ block = aal_hash_table_lookup(hint->blocks, &key); if (!block) { reiser4_key_t *ins_key; /* If block is not found in cache, we read it and put to cache. */ aal_device_t *device = extent40_device(place); block = aal_block_load(device, blksize, blk); if (!block) return -EIO; ins_key = aal_calloc(sizeof(*ins_key), 0); if (!ins_key) return -ENOMEM; aal_memcpy(ins_key, &key, sizeof(key)); aal_hash_table_insert(hint->blocks, ins_key, block); } /* Copying data from found (loaded) block to @buff. */ aal_memcpy(buff, block->data + (read_offset % blksize), size); buff += size; count -= size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -