mirror of
https://github.com/versity/scoutfs.git
synced 2026-04-28 00:46:57 +00:00
scoutfs: add sparse bitmap library
Add a quick library for maintaining a very large bitmap with sparse allocation. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -8,7 +8,7 @@ CFLAGS_scoutfs_trace.o = -I$(src) # define_trace.h double include
|
||||
scoutfs-y += bio.o block.o btree.o client.o compact.o counters.o data.o dir.o \
|
||||
export.o extents.o file.o inode.o ioctl.o item.o lock.o \
|
||||
manifest.o msg.o net.o options.o per_task.o seg.o server.o \
|
||||
scoutfs_trace.o sort_priv.o super.o sysfs.o trans.o \
|
||||
scoutfs_trace.o sort_priv.o spbm.o super.o sysfs.o trans.o \
|
||||
triggers.o tseq.o xattr.o
|
||||
|
||||
#
|
||||
|
||||
153
kmod/src/spbm.c
Normal file
153
kmod/src/spbm.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Versity Software, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include "spbm.h"
|
||||
|
||||
#define SPBM_BITS 128
|
||||
#define SPBM_SHIFT ilog2(SPBM_BITS)
|
||||
#define SPBM_MASK ((u64)SPBM_BITS - 1)
|
||||
#define SPBM_LONGS (SPBM_BITS / BITS_PER_LONG)
|
||||
|
||||
/*
|
||||
* Maintain a sparse bitmap in an rbtree. Setting bits can allocate and
|
||||
* fail but clearing will always succeed. Locking is left up to the
|
||||
* caller.
|
||||
*/
|
||||
|
||||
struct spbm_node {
|
||||
struct rb_node node;
|
||||
u64 index;
|
||||
unsigned long bits[SPBM_LONGS];
|
||||
};
|
||||
|
||||
void scoutfs_spbm_init(struct scoutfs_spbm *spbm)
|
||||
{
|
||||
BUILD_BUG_ON(!is_power_of_2(SPBM_BITS));
|
||||
|
||||
spbm->root = RB_ROOT;
|
||||
}
|
||||
|
||||
enum {
|
||||
/* if a node isn't found then return an allocated new node */
|
||||
SPBM_FIND_ALLOC = 0x1,
|
||||
};
|
||||
static struct spbm_node *find_node(struct scoutfs_spbm *spbm, u64 index,
|
||||
int flags)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
struct rb_node **node;
|
||||
struct spbm_node *sn;
|
||||
|
||||
node = &spbm->root.rb_node;
|
||||
parent = NULL;
|
||||
sn = NULL;
|
||||
while (*node) {
|
||||
parent = *node;
|
||||
sn = container_of(*node, struct spbm_node, node);
|
||||
|
||||
if (index < sn->index) {
|
||||
node = &(*node)->rb_left;
|
||||
} else if (index > sn->index) {
|
||||
node = &(*node)->rb_right;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
sn = NULL;
|
||||
}
|
||||
|
||||
if (!sn && (flags & SPBM_FIND_ALLOC)) {
|
||||
sn = kzalloc(sizeof(struct spbm_node), GFP_NOFS);
|
||||
if (sn) {
|
||||
sn->index = index;
|
||||
rb_link_node(&sn->node, parent, node);
|
||||
rb_insert_color(&sn->node, &spbm->root);
|
||||
}
|
||||
}
|
||||
|
||||
return sn;
|
||||
}
|
||||
|
||||
static void calc_index_nr(u64 *index, int *nr, u64 bit)
|
||||
{
|
||||
*index = bit >> SPBM_SHIFT;
|
||||
*nr = bit & SPBM_MASK;
|
||||
}
|
||||
|
||||
int scoutfs_spbm_set(struct scoutfs_spbm *spbm, u64 bit)
|
||||
{
|
||||
struct spbm_node *sn;
|
||||
u64 index;
|
||||
int nr;
|
||||
|
||||
calc_index_nr(&index, &nr, bit);
|
||||
|
||||
sn = find_node(spbm, index, SPBM_FIND_ALLOC);
|
||||
if (!sn)
|
||||
return -ENOMEM;
|
||||
|
||||
set_bit(nr, sn->bits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scoutfs_spbm_test(struct scoutfs_spbm *spbm, u64 bit)
|
||||
{
|
||||
struct spbm_node *sn;
|
||||
u64 index;
|
||||
int nr;
|
||||
|
||||
calc_index_nr(&index, &nr, bit);
|
||||
|
||||
sn = find_node(spbm, index, 0);
|
||||
if (sn)
|
||||
return !!test_bit(nr, sn->bits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_node(struct scoutfs_spbm *spbm, struct spbm_node *sn)
|
||||
{
|
||||
rb_erase(&sn->node, &spbm->root);
|
||||
kfree(sn);
|
||||
}
|
||||
|
||||
void scoutfs_spbm_clear(struct scoutfs_spbm *spbm, u64 bit)
|
||||
{
|
||||
struct spbm_node *sn;
|
||||
u64 index;
|
||||
int nr;
|
||||
|
||||
calc_index_nr(&index, &nr, bit);
|
||||
|
||||
sn = find_node(spbm, index, 0);
|
||||
if (sn) {
|
||||
clear_bit(nr, sn->bits);
|
||||
if (bitmap_empty(sn->bits, SPBM_BITS))
|
||||
free_node(spbm, sn);
|
||||
}
|
||||
}
|
||||
|
||||
void scoutfs_spbm_destroy(struct scoutfs_spbm *spbm)
|
||||
{
|
||||
struct spbm_node *sn;
|
||||
struct spbm_node *pos;
|
||||
|
||||
rbtree_postorder_for_each_entry_safe(sn, pos, &spbm->root, node)
|
||||
free_node(spbm, sn);
|
||||
}
|
||||
15
kmod/src/spbm.h
Normal file
15
kmod/src/spbm.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _SCOUTFS_SPBM_H_
|
||||
#define _SCOUTFS_SPBM_H_
|
||||
|
||||
struct scoutfs_spbm {
|
||||
struct rb_root root;
|
||||
};
|
||||
|
||||
void scoutfs_spbm_init(struct scoutfs_spbm *spbm);
|
||||
void scoutfs_spbm_destroy(struct scoutfs_spbm *spbm);
|
||||
|
||||
int scoutfs_spbm_set(struct scoutfs_spbm *spbm, u64 bit);
|
||||
int scoutfs_spbm_test(struct scoutfs_spbm *spbm, u64 bit);
|
||||
void scoutfs_spbm_clear(struct scoutfs_spbm *spbm, u64 bit);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user