mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 11:10:44 +00:00
scoutfs: remove dead block mapping code
Remove all the code for tracking block mapping items and storing free blocks in bitmaps. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -224,23 +224,6 @@ static inline const struct scoutfs_item_count SIC_WRITE_BEGIN(void)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncating a block mapping item's worth of blocks can modify both
|
||||
* free blkno and free segno items per block. Then the largest possible
|
||||
* mapping item.
|
||||
*/
|
||||
static inline const struct scoutfs_item_count SIC_TRUNC_BLOCK(void)
|
||||
{
|
||||
struct scoutfs_item_count cnt = {0,};
|
||||
unsigned nr_free = (2 * SCOUTFS_BLOCK_MAPPING_BLOCKS);
|
||||
|
||||
cnt.items += 1 + nr_free;
|
||||
cnt.vals += SCOUTFS_BLOCK_MAPPING_MAX_BYTES +
|
||||
(nr_free * sizeof(struct scoutfs_free_bits));
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncating an extent can:
|
||||
* - delete existing file extent,
|
||||
|
||||
733
kmod/src/data.c
733
kmod/src/data.c
@@ -18,7 +18,6 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include "format.h"
|
||||
@@ -84,488 +83,6 @@ struct task_cursor {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Block mapping items and their native decoded form can be pretty big.
|
||||
* Let's allocate them to avoid blowing the stack.
|
||||
*/
|
||||
struct block_mapping {
|
||||
/* native representation */
|
||||
unsigned long offline[DIV_ROUND_UP(SCOUTFS_BLOCK_MAPPING_BLOCKS,
|
||||
BITS_PER_LONG)];
|
||||
u64 blknos[SCOUTFS_BLOCK_MAPPING_BLOCKS];
|
||||
|
||||
/* encoded persistent item */
|
||||
u8 encoded[SCOUTFS_BLOCK_MAPPING_MAX_BYTES];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* We encode u64 blknos as a vlq zigzag encoded delta from the previous
|
||||
* blkno. zigzag moves the sign bit down into the lsb so that small
|
||||
* negative values have very few bits set. Then vlq outputs the least
|
||||
* significant set bits into bytes in groups of 7.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Variable-length_quantity
|
||||
*
|
||||
* The end result is that a series of blknos, which are limited by
|
||||
* device size and often allocated near each other, are encoded with a
|
||||
* handful of bytes.
|
||||
*/
|
||||
static unsigned zigzag_encode(u8 *bytes, u64 prev, u64 x)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
|
||||
x -= prev;
|
||||
/* careful, relying on shifting extending the sign bit */
|
||||
x = (x << 1) ^ ((s64)x >> 63);
|
||||
|
||||
do {
|
||||
bytes[pos++] = x & 127;
|
||||
x >>= 7;
|
||||
} while (x);
|
||||
|
||||
bytes[pos - 1] |= 128;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int zigzag_decode(u64 *res, u64 prev, u8 *bytes, unsigned len)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
int ret = -EIO;
|
||||
u64 x = 0;
|
||||
int i;
|
||||
u8 b;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
b = bytes[i];
|
||||
x |= (u64)(b & 127) << shift;
|
||||
if (b & 128) {
|
||||
ret = i + 1;
|
||||
break;
|
||||
}
|
||||
shift += 7;
|
||||
|
||||
/* falls through to return -EIO if we run out of bytes */
|
||||
}
|
||||
|
||||
x = (x >> 1) ^ (-(x & 1));
|
||||
*res = prev + x;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block mappings are encoded into a byte stream.
|
||||
*
|
||||
* The first byte's low bits contains the last mapping index that will
|
||||
* be decoded.
|
||||
*
|
||||
* As we walk through the encoded blocks we add control bits to the
|
||||
* current control byte for the encoding of the block: zero, offline,
|
||||
* increment from prev, or zigzag encoding.
|
||||
*
|
||||
* When the control byte is full we start filling the next byte in the
|
||||
* output as the control byte for the coming blocks. When we zigzag
|
||||
* encode blocks we add them to the output stream. The result is an
|
||||
* interleaving of control bytes and zigzag blocks, when they're needed.
|
||||
*
|
||||
* In practice the typical mapping will have a zigzag for the first
|
||||
* block and then the rest will be described by the control bits.
|
||||
* Regions of sparse, advancing allocations, and offline are all
|
||||
* described only by control bits, getting us down to 2 bits per block.
|
||||
*/
|
||||
static unsigned encode_mapping(struct block_mapping *map)
|
||||
{
|
||||
unsigned shift;
|
||||
unsigned len;
|
||||
u64 blkno;
|
||||
u64 prev;
|
||||
u8 *enc;
|
||||
u8 *ctl;
|
||||
u8 last;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
enc = map->encoded;
|
||||
ctl = enc++;
|
||||
len = 1;
|
||||
|
||||
/* find the last set block in the mapping */
|
||||
last = SCOUTFS_BLOCK_MAPPING_BLOCKS;
|
||||
for (i = 0; i < SCOUTFS_BLOCK_MAPPING_BLOCKS; i++) {
|
||||
if (map->blknos[i] || test_bit(i, map->offline))
|
||||
last = i;
|
||||
}
|
||||
|
||||
if (last == SCOUTFS_BLOCK_MAPPING_BLOCKS)
|
||||
return 0;
|
||||
|
||||
/* start with 6 bits of last */
|
||||
*ctl = last;
|
||||
shift = 6;
|
||||
|
||||
prev = 0;
|
||||
for (i = 0; i <= last; i++) {
|
||||
blkno = map->blknos[i];
|
||||
|
||||
|
||||
if (shift == 8) {
|
||||
ctl = enc++;
|
||||
len++;
|
||||
*ctl = 0;
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
|
||||
if (blkno == prev + 1)
|
||||
*ctl |= (SCOUTFS_BLOCK_ENC_INC << shift);
|
||||
else if (test_bit(i, map->offline))
|
||||
*ctl |= (SCOUTFS_BLOCK_ENC_OFFLINE << shift);
|
||||
else if (!blkno)
|
||||
*ctl |= (SCOUTFS_BLOCK_ENC_ZERO << shift);
|
||||
else {
|
||||
*ctl |= (SCOUTFS_BLOCK_ENC_DELTA << shift);
|
||||
|
||||
ret = zigzag_encode(enc, prev, blkno);
|
||||
enc += ret;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
shift += 2;
|
||||
if (blkno)
|
||||
prev = blkno;
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int decode_mapping(struct block_mapping *map, int size)
|
||||
{
|
||||
unsigned ctl_bits;
|
||||
u64 blkno;
|
||||
u64 prev;
|
||||
u8 *enc;
|
||||
u8 ctl;
|
||||
u8 last;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (size < 1 || size > SCOUTFS_BLOCK_MAPPING_MAX_BYTES)
|
||||
return -EIO;
|
||||
|
||||
memset(map->blknos, 0, sizeof(map->blknos));
|
||||
memset(map->offline, 0, sizeof(map->offline));
|
||||
|
||||
enc = map->encoded;
|
||||
ctl = *(enc++);
|
||||
size--;
|
||||
|
||||
/* start with lsb 6 bits of last */
|
||||
last = ctl & SCOUTFS_BLOCK_MAPPING_MASK;
|
||||
ctl >>= 6;
|
||||
ctl_bits = 2;
|
||||
|
||||
prev = 0;
|
||||
for (i = 0; i <= last; i++) {
|
||||
|
||||
if (ctl_bits == 0) {
|
||||
if (size-- == 0)
|
||||
return -EIO;
|
||||
ctl = *(enc++);
|
||||
ctl_bits = 8;
|
||||
}
|
||||
|
||||
|
||||
switch(ctl & SCOUTFS_BLOCK_ENC_MASK) {
|
||||
case SCOUTFS_BLOCK_ENC_INC:
|
||||
blkno = prev + 1;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_OFFLINE:
|
||||
set_bit(i, map->offline);
|
||||
blkno = 0;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_ZERO:
|
||||
blkno = 0;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_DELTA:
|
||||
ret = zigzag_decode(&blkno, prev, enc, size);
|
||||
/* XXX corruption, ran out of encoded bytes */
|
||||
if (ret <= 0)
|
||||
return -EIO;
|
||||
enc += ret;
|
||||
size -= ret;
|
||||
break;
|
||||
}
|
||||
|
||||
ctl >>= 2;
|
||||
ctl_bits -= 2;
|
||||
|
||||
map->blknos[i] = blkno;
|
||||
if (blkno)
|
||||
prev = blkno;
|
||||
}
|
||||
|
||||
/* XXX corruption: didn't use up all the bytes */
|
||||
if (size != 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_mapping_key(struct scoutfs_key *key, u64 ino, u64 iblock)
|
||||
{
|
||||
*key = (struct scoutfs_key) {
|
||||
.sk_zone = SCOUTFS_FS_ZONE,
|
||||
.skm_ino = cpu_to_le64(ino),
|
||||
.sk_type = SCOUTFS_BLOCK_MAPPING_TYPE,
|
||||
.skm_base = cpu_to_le64(iblock >> SCOUTFS_BLOCK_MAPPING_SHIFT),
|
||||
};
|
||||
}
|
||||
|
||||
static void init_free_key(struct scoutfs_key *key, u64 node_id, u64 full_bit,
|
||||
u8 type)
|
||||
{
|
||||
*key = (struct scoutfs_key) {
|
||||
.sk_zone = SCOUTFS_NODE_ZONE,
|
||||
.skf_node_id = cpu_to_le64(node_id),
|
||||
.sk_type = type,
|
||||
.skf_base = cpu_to_le64(full_bit >> SCOUTFS_FREE_BITS_SHIFT),
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the given segno as allocated. We set its bit in a free segno
|
||||
* item, possibly after creating it.
|
||||
*/
|
||||
static int set_segno_free(struct super_block *sb, u64 segno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
int bit = 0;
|
||||
int ret;
|
||||
|
||||
init_free_key(&key, sbi->node_id, segno, SCOUTFS_FREE_BITS_SEGNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, &val, lock);
|
||||
if (ret && ret != -ENOENT)
|
||||
goto out;
|
||||
|
||||
bit = segno & SCOUTFS_FREE_BITS_MASK;
|
||||
|
||||
if (ret == -ENOENT) {
|
||||
memset(&frb, 0, sizeof(frb));
|
||||
set_bit_le(bit, &frb);
|
||||
ret = scoutfs_item_create(sb, &key, &val, lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_and_set_bit_le(bit, frb.bits)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_item_update(sb, &key, &val, lock);
|
||||
out:
|
||||
trace_scoutfs_data_set_segno_free(sb, segno, le64_to_cpu(key.skf_base),
|
||||
bit, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new free blkno item with all but the given blkno marked
|
||||
* free. We use the caller's key so they can delete it later if they
|
||||
* need to.
|
||||
*/
|
||||
static int create_blkno_free(struct super_block *sb, u64 blkno,
|
||||
struct scoutfs_key *key)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct kvec val;
|
||||
int bit;
|
||||
|
||||
init_free_key(key, sbi->node_id, blkno, SCOUTFS_FREE_BITS_BLKNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
|
||||
bit = blkno & SCOUTFS_FREE_BITS_MASK;
|
||||
memset(&frb, 0xff, sizeof(frb));
|
||||
clear_bit_le(bit, frb.bits);
|
||||
|
||||
return scoutfs_item_create(sb, key, &val, lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the first block in the segno as allocated. This isn't a general
|
||||
* purpose bit clear. It knows that it's only called from allocation
|
||||
* that found the bit so it won't create the segno item.
|
||||
*
|
||||
* And because it's allocating a block in the segno, it also has to
|
||||
* create a free block item that marks the rest of the blknos in segno
|
||||
* as free.
|
||||
*
|
||||
* It deletes the free segno item if it clears the last bit.
|
||||
*/
|
||||
static int clear_segno_free(struct super_block *sb, u64 segno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key b_key;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
u64 blkno;
|
||||
int bit;
|
||||
int ret;
|
||||
|
||||
init_free_key(&key, sbi->node_id, segno, SCOUTFS_FREE_BITS_SEGNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, &val, lock);
|
||||
if (ret) {
|
||||
/* XXX corruption, caller saw item.. should still exist */
|
||||
if (ret == -ENOENT)
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX corruption, bit couldn't have been set */
|
||||
bit = segno & SCOUTFS_FREE_BITS_MASK;
|
||||
if (!test_and_clear_bit_le(bit, frb.bits)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create the new blkno item, we can safely delete it */
|
||||
blkno = segno << SCOUTFS_SEGMENT_BLOCK_SHIFT;
|
||||
ret = create_blkno_free(sb, blkno, &b_key);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (bitmap_empty((long *)frb.bits, SCOUTFS_FREE_BITS_BITS))
|
||||
ret = scoutfs_item_delete(sb, &key, lock);
|
||||
else
|
||||
ret = scoutfs_item_update(sb, &key, &val, lock);
|
||||
if (ret)
|
||||
scoutfs_item_delete_dirty(sb, &b_key);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the given blkno free. Set its bit in its free blkno item,
|
||||
* possibly after creating it. If all the bits are set we try to mark
|
||||
* its segno free and delete the blkno item.
|
||||
*/
|
||||
static int set_blkno_free(struct super_block *sb, u64 blkno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
u64 segno;
|
||||
int bit;
|
||||
int ret;
|
||||
|
||||
/* get the specified item */
|
||||
init_free_key(&key, sbi->node_id, blkno, SCOUTFS_FREE_BITS_BLKNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, &val, lock);
|
||||
if (ret && ret != -ENOENT)
|
||||
goto out;
|
||||
|
||||
bit = blkno & SCOUTFS_FREE_BITS_MASK;
|
||||
|
||||
if (ret == -ENOENT) {
|
||||
memset(&frb, 0, sizeof(frb));
|
||||
set_bit_le(bit, &frb);
|
||||
ret = scoutfs_item_create(sb, &key, &val, lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_and_set_bit_le(bit, frb.bits)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!bitmap_full((long *)frb.bits, SCOUTFS_FREE_BITS_BITS)) {
|
||||
ret = scoutfs_item_update(sb, &key, &val, lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* dirty so we can safely delete if set segno fails */
|
||||
ret = scoutfs_item_dirty(sb, &key, lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
segno = blkno >> SCOUTFS_SEGMENT_BLOCK_SHIFT;
|
||||
ret = set_segno_free(sb, segno);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
scoutfs_item_delete_dirty(sb, &key);
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the given blkno as allocated. This is working on behalf of a
|
||||
* caller who just saw the item, it must exist. We delete the free
|
||||
* blkno item if all its bits are empty.
|
||||
*/
|
||||
static int clear_blkno_free(struct super_block *sb, u64 blkno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
int bit;
|
||||
int ret;
|
||||
|
||||
/* get the specified item */
|
||||
init_free_key(&key, sbi->node_id, blkno, SCOUTFS_FREE_BITS_BLKNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, &val, lock);
|
||||
if (ret) {
|
||||
/* XXX corruption, bits should have existed */
|
||||
if (ret == -ENOENT)
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX corruption, bit couldn't have been set */
|
||||
bit = blkno & SCOUTFS_FREE_BITS_MASK;
|
||||
if (!test_and_clear_bit_le(bit, frb.bits)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bitmap_empty((long *)frb.bits, SCOUTFS_FREE_BITS_BITS))
|
||||
ret = scoutfs_item_delete(sb, &key, lock);
|
||||
else
|
||||
ret = scoutfs_item_update(sb, &key, &val, lock);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* In each iteration iblock is the logical block and i is the index into
|
||||
* blknos array and the bit in the offline bitmap. The iteration won't
|
||||
* advance past the last logical block.
|
||||
*/
|
||||
#define for_each_block(i, iblock, last) \
|
||||
for (i = iblock & SCOUTFS_BLOCK_MAPPING_MASK; \
|
||||
i < SCOUTFS_BLOCK_MAPPING_BLOCKS && iblock <= (last); \
|
||||
i++, iblock++)
|
||||
#endif
|
||||
|
||||
static void init_file_extent_key(struct scoutfs_key *key, u64 ino, u64 last)
|
||||
{
|
||||
*key = (struct scoutfs_key) {
|
||||
@@ -974,82 +491,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Find the free bit item that contains the blkno and return the next blkno
|
||||
* set starting with this blkno.
|
||||
*
|
||||
* Returns -ENOENT if there's no free blknos at or after the given blkno.
|
||||
*/
|
||||
static int find_free_blkno(struct super_block *sb, u64 blkno, u64 *blkno_ret)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
int ret;
|
||||
int bit;
|
||||
|
||||
init_free_key(&key, sbi->node_id, blkno, SCOUTFS_FREE_BITS_BLKNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, &val, lock);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
bit = blkno & SCOUTFS_FREE_BITS_MASK;
|
||||
bit = find_next_bit_le(frb.bits, SCOUTFS_FREE_BITS_BITS, bit);
|
||||
if (bit >= SCOUTFS_FREE_BITS_BITS) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*blkno_ret = (le64_to_cpu(key.skf_base) << SCOUTFS_FREE_BITS_SHIFT) +
|
||||
bit;
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a free segno to satisfy allocation by finding the first bit set
|
||||
* in the first free segno item.
|
||||
*/
|
||||
static int find_free_segno(struct super_block *sb, u64 *segno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_lock *lock = sbi->node_id_lock;
|
||||
struct scoutfs_free_bits frb;
|
||||
struct scoutfs_key last_key;
|
||||
struct scoutfs_key key;
|
||||
struct kvec val;
|
||||
int bit;
|
||||
int ret;
|
||||
|
||||
init_free_key(&key, sbi->node_id, 0, SCOUTFS_FREE_BITS_SEGNO_TYPE);
|
||||
init_free_key(&last_key, sbi->node_id, U64_MAX,
|
||||
SCOUTFS_FREE_BITS_SEGNO_TYPE);
|
||||
kvec_init(&val, &frb, sizeof(struct scoutfs_free_bits));
|
||||
|
||||
ret = scoutfs_item_next(sb, &key, &last_key, &val, lock);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
bit = find_next_bit_le(frb.bits, SCOUTFS_FREE_BITS_BITS, 0);
|
||||
/* XXX corruption, shouldn't see empty items */
|
||||
if (bit >= SCOUTFS_FREE_BITS_BITS) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*segno = (le64_to_cpu(key.skf_base) << SCOUTFS_FREE_BITS_SHIFT) + bit;
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate a single block for the logical block offset in the file.
|
||||
* The caller tells us if the block was offline or not. We modify the
|
||||
@@ -1412,61 +853,6 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct pending_fiemap {
|
||||
u64 logical;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The caller is iterating over mapped blocks. We merge the current
|
||||
* pending fiemap entry with the next block if we can. If we can't
|
||||
* merge then we fill the current entry and start on the next. We also
|
||||
* fill the pending mapping if the caller specifically tells us that
|
||||
* this will be the last call.
|
||||
*
|
||||
* returns 0 to continue, 1 to stop, and -errno to stop with error.
|
||||
*/
|
||||
static int merge_or_fill(struct fiemap_extent_info *fieinfo,
|
||||
struct pending_fiemap *pend, u64 logical, u64 phys,
|
||||
bool offline, bool last)
|
||||
{
|
||||
u32 flags = offline ? FIEMAP_EXTENT_UNKNOWN : 0;
|
||||
int ret;
|
||||
|
||||
/* merge if we can, returning if we don't have to fill last */
|
||||
if (pend->logical + pend->size == logical &&
|
||||
((pend->phys == 0 && phys == 0) ||
|
||||
(pend->phys + pend->size == phys)) &&
|
||||
pend->flags == flags) {
|
||||
pend->size += SCOUTFS_BLOCK_SIZE;
|
||||
if (!last)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pend->size) {
|
||||
if (last)
|
||||
pend->flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
/* returns 1 to end, including if we passed in _LAST */
|
||||
ret = fiemap_fill_next_extent(fieinfo, pend->logical,
|
||||
pend->phys, pend->size,
|
||||
pend->flags);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pend->logical = logical;
|
||||
pend->phys = phys;
|
||||
pend->size = SCOUTFS_BLOCK_SIZE;
|
||||
pend->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return all the file's extents whose blocks overlap with the caller's
|
||||
* byte region. We set _LAST on the last extent and _UNKNOWN on offline
|
||||
@@ -1614,122 +1000,3 @@ void scoutfs_data_destroy(struct super_block *sb)
|
||||
kfree(datinf);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Basic correctness tests of u64 and mapping encoding.
|
||||
*/
|
||||
int __init scoutfs_data_test(void)
|
||||
{
|
||||
u8 encoded[SCOUTFS_ZIGZAG_MAX_BYTES];
|
||||
struct block_mapping *input;
|
||||
struct block_mapping *output;
|
||||
u64 blkno;
|
||||
u8 bits;
|
||||
u64 prev;
|
||||
u64 in;
|
||||
u64 out;
|
||||
int ret;
|
||||
int len;
|
||||
int b;
|
||||
int i;
|
||||
|
||||
prev = 0;
|
||||
for (i = 0; i < 10000; i++) {
|
||||
get_random_bytes_arch(&bits, sizeof(bits));
|
||||
get_random_bytes_arch(&in, sizeof(in));
|
||||
in &= (1ULL << (bits % 64)) - 1;
|
||||
|
||||
len = zigzag_encode(encoded, prev, in);
|
||||
|
||||
ret = zigzag_decode(&out, prev, encoded, len);
|
||||
|
||||
if (ret <= 0 || ret > SCOUTFS_ZIGZAG_MAX_BYTES || in != out) {
|
||||
printk("i %d prev %llu in %llu out %llu len %d ret %d\n",
|
||||
i, prev, in, out, len, ret);
|
||||
|
||||
ret = -EINVAL;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prev = out;
|
||||
}
|
||||
|
||||
input = kmalloc(sizeof(struct block_mapping), GFP_KERNEL);
|
||||
output = kmalloc(sizeof(struct block_mapping), GFP_KERNEL);
|
||||
if (!input || !output) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
prev = 0;
|
||||
for (b = 0; b < SCOUTFS_BLOCK_MAPPING_BLOCKS; b++) {
|
||||
|
||||
if (b % (64 / 2) == 0)
|
||||
get_random_bytes_arch(&in, sizeof(in));
|
||||
|
||||
clear_bit(b, input->offline);
|
||||
|
||||
switch(in & SCOUTFS_BLOCK_ENC_MASK) {
|
||||
case SCOUTFS_BLOCK_ENC_INC:
|
||||
blkno = prev + 1;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_OFFLINE:
|
||||
set_bit(b, input->offline);
|
||||
blkno = 0;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_ZERO:
|
||||
blkno = 0;
|
||||
break;
|
||||
case SCOUTFS_BLOCK_ENC_DELTA:
|
||||
get_random_bytes_arch(&bits, sizeof(bits));
|
||||
get_random_bytes_arch(&blkno, sizeof(blkno));
|
||||
blkno &= (1ULL << (bits % 64)) - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
input->blknos[b] = blkno;
|
||||
|
||||
in >>= 2;
|
||||
if (blkno)
|
||||
prev = blkno;
|
||||
}
|
||||
|
||||
len = encode_mapping(input);
|
||||
if (len >= 1 && len < SCOUTFS_BLOCK_MAPPING_MAX_BYTES)
|
||||
memcpy(output->encoded, input->encoded, len);
|
||||
ret = decode_mapping(output, len);
|
||||
if (ret) {
|
||||
printk("map len %d decoding failed %d\n", len, ret);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (b = 0; b < SCOUTFS_BLOCK_MAPPING_BLOCKS; b++) {
|
||||
if (input->blknos[b] != output->blknos[b] ||
|
||||
!!test_bit(b, input->offline) !=
|
||||
!!test_bit(b, output->offline))
|
||||
break;
|
||||
}
|
||||
|
||||
if (b < SCOUTFS_BLOCK_MAPPING_BLOCKS) {
|
||||
printk("map ind %u: in %llu %u, out %llu %u\n",
|
||||
b, input->blknos[b],
|
||||
!!test_bit(b, input->offline),
|
||||
output->blknos[b],
|
||||
!!test_bit(b, output->offline));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
kfree(input);
|
||||
kfree(output);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -79,10 +79,6 @@ struct scoutfs_key {
|
||||
#define skii_major _sk_second
|
||||
#define skii_ino _sk_third
|
||||
|
||||
/* node free bit map */
|
||||
#define skf_node_id _sk_first
|
||||
#define skf_base _sk_second
|
||||
|
||||
/* node free extent */
|
||||
#define sknf_node_id _sk_first
|
||||
#define sknf_major _sk_second
|
||||
@@ -110,10 +106,6 @@ struct scoutfs_key {
|
||||
#define sks_ino _sk_first
|
||||
#define sks_nr _sk_second
|
||||
|
||||
/* file data mapping */
|
||||
#define skm_ino _sk_first
|
||||
#define skm_base _sk_second
|
||||
|
||||
/* file extent */
|
||||
#define skfe_ino _sk_first
|
||||
#define skfe_last _sk_second
|
||||
@@ -312,10 +304,8 @@ struct scoutfs_segment_block {
|
||||
#define SCOUTFS_INODE_INDEX_NR 3 /* don't forget to update */
|
||||
|
||||
/* node zone */
|
||||
#define SCOUTFS_FREE_BITS_SEGNO_TYPE 1
|
||||
#define SCOUTFS_FREE_BITS_BLKNO_TYPE 2
|
||||
#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 3
|
||||
#define SCOUTFS_FREE_EXTENT_BLOCKS_TYPE 4
|
||||
#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1
|
||||
#define SCOUTFS_FREE_EXTENT_BLOCKS_TYPE 2
|
||||
|
||||
/* fs zone */
|
||||
#define SCOUTFS_INODE_TYPE 1
|
||||
@@ -324,61 +314,11 @@ struct scoutfs_segment_block {
|
||||
#define SCOUTFS_READDIR_TYPE 4
|
||||
#define SCOUTFS_LINK_BACKREF_TYPE 5
|
||||
#define SCOUTFS_SYMLINK_TYPE 6
|
||||
#define SCOUTFS_BLOCK_MAPPING_TYPE 7
|
||||
#define SCOUTFS_FILE_EXTENT_TYPE 7
|
||||
#define SCOUTFS_ORPHAN_TYPE 8
|
||||
#define SCOUTFS_FILE_EXTENT_TYPE 9
|
||||
|
||||
#define SCOUTFS_MAX_TYPE 16 /* power of 2 is efficient */
|
||||
|
||||
/* each mapping item describes a fixed number of blocks */
|
||||
#define SCOUTFS_BLOCK_MAPPING_SHIFT 6
|
||||
#define SCOUTFS_BLOCK_MAPPING_BLOCKS (1 << SCOUTFS_BLOCK_MAPPING_SHIFT)
|
||||
#define SCOUTFS_BLOCK_MAPPING_MASK (SCOUTFS_BLOCK_MAPPING_BLOCKS - 1)
|
||||
|
||||
/*
|
||||
* The mapping item value is a byte stream that encodes the value of the
|
||||
* mapped blocks. The first byte contains the last index that contains
|
||||
* a mapped block in its low bits. The high bits contain the control
|
||||
* bits for the first (and possibly only) mapped block.
|
||||
*
|
||||
* From then on we consume the control bits in the current control byte
|
||||
* for each mapped block. Each block has two bits that describe the
|
||||
* block: zero, incremental from previous block, delta encoded, and
|
||||
* offline. If we run out of control bits then we consume the next byte
|
||||
* in the stream for additional control bits. If we have a delta
|
||||
* encoded block then we consume its encoded bytes from the byte stream.
|
||||
*/
|
||||
|
||||
#define SCOUTFS_BLOCK_ENC_ZERO 0
|
||||
#define SCOUTFS_BLOCK_ENC_INC 1
|
||||
#define SCOUTFS_BLOCK_ENC_DELTA 2
|
||||
#define SCOUTFS_BLOCK_ENC_OFFLINE 3
|
||||
#define SCOUTFS_BLOCK_ENC_MASK 3
|
||||
|
||||
#define SCOUTFS_ZIGZAG_MAX_BYTES (DIV_ROUND_UP(64, 7))
|
||||
|
||||
/*
|
||||
* the largest block mapping has: nr byte, ctl bytes for all blocks, and
|
||||
* worst case zigzag encodings for all blocks.
|
||||
*/
|
||||
#define SCOUTFS_BLOCK_MAPPING_MAX_BYTES \
|
||||
(1 + (SCOUTFS_BLOCK_MAPPING_BLOCKS / 4) + \
|
||||
(SCOUTFS_BLOCK_MAPPING_BLOCKS * SCOUTFS_ZIGZAG_MAX_BYTES))
|
||||
|
||||
/* free bit bitmaps contain a segment's worth of blocks */
|
||||
#define SCOUTFS_FREE_BITS_SHIFT \
|
||||
SCOUTFS_SEGMENT_BLOCK_SHIFT
|
||||
#define SCOUTFS_FREE_BITS_BITS \
|
||||
(1 << SCOUTFS_FREE_BITS_SHIFT)
|
||||
#define SCOUTFS_FREE_BITS_MASK \
|
||||
(SCOUTFS_FREE_BITS_BITS - 1)
|
||||
#define SCOUTFS_FREE_BITS_U64S \
|
||||
DIV_ROUND_UP(SCOUTFS_FREE_BITS_BITS, 64)
|
||||
|
||||
struct scoutfs_free_bits {
|
||||
__le64 bits[SCOUTFS_FREE_BITS_U64S];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* File extents have more data than easily fits in the key so we move
|
||||
* the non-indexed fields into the value.
|
||||
|
||||
@@ -26,8 +26,6 @@ char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = {
|
||||
char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = {
|
||||
[SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = "msq",
|
||||
[SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = "dsq",
|
||||
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_SEGNO_TYPE] = "fsg",
|
||||
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_BLKNO_TYPE] = "fbk",
|
||||
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLKNO_TYPE] = "fbn",
|
||||
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLOCKS_TYPE] = "fbs",
|
||||
[SCOUTFS_NODE_ZONE][SCOUTFS_ORPHAN_TYPE] = "orp",
|
||||
@@ -37,7 +35,6 @@ char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = {
|
||||
[SCOUTFS_FS_ZONE][SCOUTFS_READDIR_TYPE] = "rdr",
|
||||
[SCOUTFS_FS_ZONE][SCOUTFS_LINK_BACKREF_TYPE] = "lbr",
|
||||
[SCOUTFS_FS_ZONE][SCOUTFS_SYMLINK_TYPE] = "sym",
|
||||
[SCOUTFS_FS_ZONE][SCOUTFS_BLOCK_MAPPING_TYPE] = "bmp",
|
||||
[SCOUTFS_FS_ZONE][SCOUTFS_FILE_EXTENT_TYPE] = "fex",
|
||||
};
|
||||
|
||||
|
||||
@@ -526,32 +526,6 @@ TRACE_EVENT(scoutfs_data_truncate_items,
|
||||
__entry->iblock, __entry->last, __entry->offline)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_data_set_segno_free,
|
||||
TP_PROTO(struct super_block *sb, __u64 segno, __u64 base,
|
||||
unsigned int bit, int ret),
|
||||
|
||||
TP_ARGS(sb, segno, base, bit, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(__u64, fsid)
|
||||
__field(__u64, segno)
|
||||
__field(__u64, base)
|
||||
__field(unsigned int, bit)
|
||||
__field(int, ret)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->fsid = FSID_ARG(sb);
|
||||
__entry->segno = segno;
|
||||
__entry->base = base;
|
||||
__entry->bit = bit;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk(FSID_FMT" segno %llu base %llu bit %u ret %d", __entry->fsid,
|
||||
__entry->segno, __entry->base, __entry->bit, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_sync_fs,
|
||||
TP_PROTO(struct super_block *sb, int wait),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user