scoutfs: remove dead server allocator code

Remove the bitmap segno allocator code that the server used to use to
manage allocations.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2018-06-29 14:42:06 -07:00
committed by Zach Brown
parent c01a715852
commit 1b3645db8b
11 changed files with 2 additions and 597 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ CFLAGS_super.o = -DSCOUTFS_GIT_DESCRIBE=\"$(SCOUTFS_GIT_DESCRIBE)\" \
CFLAGS_scoutfs_trace.o = -I$(src) # define_trace.h double include
scoutfs-y += alloc.o bio.o btree.o client.o compact.o counters.o data.o dir.o \
scoutfs-y += bio.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 key.o lock.o \
manifest.o msg.o options.o per_task.o seg.o server.o \
scoutfs_trace.o sock.o sort_priv.o super.o sysfs.o trans.o \
-355
View File
@@ -1,355 +0,0 @@
/*
* Copyright (C) 2016 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/fs.h>
#include <linux/slab.h>
#include <linux/radix-tree.h>
#include "super.h"
#include "format.h"
#include "btree.h"
#include "cmp.h"
#include "alloc.h"
#include "counters.h"
#include "scoutfs_trace.h"
/*
* scoutfs allocates segments using regions of an allocation bitmap
* stored in btree items.
*
* Freed segments are recorded in nodes in an rbtree. The frees can't
* satisfy allocation until they're committed to prevent overwriting
* live data so they're only applied to the region nodes as their
* transaction is written.
*
* We allocate by sweeping a cursor through the volume. This gives
* racing unlocked readers more time to try to sample a stale freed
* segment, when its safe to do so, before it is reallocated and
* rewritten and they're forced to retry their racey read.
*/
struct seg_alloc {
struct rw_semaphore rwsem;
struct rb_root pending_root;
u64 next_segno;
};
#define DECLARE_SEG_ALLOC(sb, name) \
struct seg_alloc *name = SCOUTFS_SB(sb)->seg_alloc
struct pending_region {
struct rb_node node;
u64 ind;
struct scoutfs_alloc_region_btree_val reg_val;
};
static struct pending_region *find_pending(struct rb_root *root, u64 ind)
{
struct rb_node *node = root->rb_node;
struct pending_region *pend;
while (node) {
pend = container_of(node, struct pending_region, node);
if (ind < pend->ind)
node = node->rb_left;
else if (ind > pend->ind)
node = node->rb_right;
else
return pend;
}
return NULL;
}
static void insert_pending(struct rb_root *root, struct pending_region *ins)
{
struct rb_node **node = &root->rb_node;
struct rb_node *parent = NULL;
struct pending_region *pend;
while (*node) {
parent = *node;
pend = container_of(*node, struct pending_region, node);
if (ins->ind < pend->ind)
node = &(*node)->rb_left;
else if (ins->ind > pend->ind)
node = &(*node)->rb_right;
else
BUG();
}
rb_link_node(&ins->node, parent, node);
rb_insert_color(&ins->node, root);
}
static int copy_region_item(struct scoutfs_alloc_region_btree_key *reg_key,
struct scoutfs_alloc_region_btree_val *reg_val,
struct scoutfs_btree_item_ref *iref)
{
if (iref->key_len != sizeof(struct scoutfs_alloc_region_btree_key) ||
iref->val_len != sizeof(struct scoutfs_alloc_region_btree_val))
return -EIO;
memcpy(reg_key, iref->key, iref->key_len);
memcpy(reg_val, iref->val, iref->val_len);
return 0;
}
/*
* We're careful to copy the bitmaps out to aligned versions so that
* we can use native bitops that require aligned longs.
*/
int scoutfs_alloc_segno(struct super_block *sb, u64 *segno)
{
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
struct scoutfs_alloc_region_btree_key reg_key;
struct scoutfs_alloc_region_btree_val __aligned(sizeof(long)) reg_val;
SCOUTFS_BTREE_ITEM_REF(iref);
DECLARE_SEG_ALLOC(sb, sal);
u64 ind;
int ret;
int nr;
down_write(&sal->rwsem);
/* initially sweep through all segments */
if (super->alloc_uninit != super->total_segs) {
*segno = le64_to_cpu(super->alloc_uninit);
/* done when inc hits total_segs */
le64_add_cpu(&super->alloc_uninit, 1);
ret = 0;
goto out;
}
/* but usually search for region nodes */
ind = sal->next_segno >> SCOUTFS_ALLOC_REGION_SHIFT;
nr = sal->next_segno & SCOUTFS_ALLOC_REGION_MASK;
for (;;) {
reg_key.index = cpu_to_be64(ind);
ret = scoutfs_btree_next(sb, &super->alloc_root,
&reg_key, sizeof(reg_key), &iref);
if (ret == -ENOENT && ind != 0) {
ind = 0;
nr = 0;
continue;
}
if (ret < 0) {
if (ret == -ENOENT)
ret = -ENOSPC;
goto out;
}
ret = copy_region_item(&reg_key, &reg_val, &iref);
scoutfs_btree_put_iref(&iref);
if (ret)
goto out;
ind = be64_to_cpu(reg_key.index);
nr = find_next_bit_le(reg_val.bits, SCOUTFS_ALLOC_REGION_BITS, nr);
if (nr < SCOUTFS_ALLOC_REGION_BITS) {
break;
}
/* possible for nr to be after all free bits, keep going */
ind++;
nr = 0;
}
clear_bit_le(nr, reg_val.bits);
if (bitmap_empty((long *)reg_val.bits, SCOUTFS_ALLOC_REGION_BITS))
ret = scoutfs_btree_delete(sb, &super->alloc_root,
&reg_key, sizeof(reg_key));
else
ret = scoutfs_btree_update(sb, &super->alloc_root,
&reg_key, sizeof(reg_key),
&reg_val, sizeof(reg_val));
if (ret)
goto out;
*segno = (ind << SCOUTFS_ALLOC_REGION_SHIFT) + nr;
sal->next_segno = *segno + 1;
ret = 0;
out:
if (ret == 0) {
scoutfs_inc_counter(sb, alloc_alloc);
le64_add_cpu(&super->free_segs, -1);
}
up_write(&sal->rwsem);
trace_scoutfs_alloc_segno(sb, *segno, ret);
return ret;
}
/*
* Record newly freed sgements in pending regions. These are applied to
* persistent regions in btree items as the transaction commits.
*/
int scoutfs_alloc_free(struct super_block *sb, u64 segno)
{
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
struct pending_region *pend;
DECLARE_SEG_ALLOC(sb, sal);
u64 ind;
int ret;
int nr;
ind = segno >> SCOUTFS_ALLOC_REGION_SHIFT;
nr = segno & SCOUTFS_ALLOC_REGION_MASK;
down_write(&sal->rwsem);
pend = find_pending(&sal->pending_root, ind);
if (!pend) {
pend = kzalloc(sizeof(struct pending_region), GFP_NOFS);
if (!pend) {
ret = -ENOMEM;
goto out;
}
pend->ind = ind;
insert_pending(&sal->pending_root, pend);
}
set_bit_le(nr, pend->reg_val.bits);
scoutfs_inc_counter(sb, alloc_free);
le64_add_cpu(&super->free_segs, 1);
ret = 0;
out:
up_write(&sal->rwsem);
trace_scoutfs_alloc_free(sb, segno, ind, nr, ret);
return ret;
}
/*
* Apply the pending frees to create the final set of dirty btree
* blocks. The caller will write the btree blocks. We're destroying
* the pending free record here so from this point on the pending free
* blocks could be visible to allocation. The caller can't finish with
* the transaction until the btree is written successfully.
*/
int scoutfs_alloc_apply_pending(struct super_block *sb)
{
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
DECLARE_SEG_ALLOC(sb, sal);
struct pending_region *pend;
struct rb_node *node;
struct scoutfs_alloc_region_btree_key reg_key;
struct scoutfs_alloc_region_btree_val __aligned(sizeof(long)) reg_val;
SCOUTFS_BTREE_ITEM_REF(iref);
int ret;
down_write(&sal->rwsem);
ret = 0;
while ((node = rb_first(&sal->pending_root))) {
pend = container_of(node, struct pending_region, node);
/* see if we have a region for this index */
reg_key.index = cpu_to_be64(pend->ind);
ret = scoutfs_btree_lookup(sb, &super->alloc_root,
&reg_key, sizeof(reg_key), &iref);
if (ret == -ENOENT) {
/* create a new item if we don't */
ret = scoutfs_btree_insert(sb, &super->alloc_root,
&reg_key, sizeof(reg_key),
&pend->reg_val,
sizeof(pend->reg_val));
} else if (ret == 0) {
/* and update the existing item if we do */
ret = copy_region_item(&reg_key, &reg_val, &iref);
scoutfs_btree_put_iref(&iref);
if (ret)
break;
bitmap_or((long *)reg_val.bits, (long *)reg_val.bits,
(long *)pend->reg_val.bits,
SCOUTFS_ALLOC_REGION_BITS);
ret = scoutfs_btree_update(sb, &super->alloc_root,
&reg_key, sizeof(reg_key),
&reg_val, sizeof(reg_val));
}
if (ret < 0)
break;
rb_erase(&pend->node, &sal->pending_root);
kfree(pend);
}
up_write(&sal->rwsem);
return ret;
}
/*
* Return the number of blocks free for statfs.
*/
u64 scoutfs_alloc_bfree(struct super_block *sb)
{
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
DECLARE_SEG_ALLOC(sb, sal);
u64 bfree;
down_read(&sal->rwsem);
bfree = le64_to_cpu(super->free_segs) << SCOUTFS_SEGMENT_BLOCK_SHIFT;
up_read(&sal->rwsem);
return bfree;
}
int scoutfs_alloc_setup(struct super_block *sb)
{
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
struct seg_alloc *sal;
/* bits need to be aligned so hosts can use native bitops */
BUILD_BUG_ON(offsetof(struct scoutfs_alloc_region_btree_val, bits) &
(sizeof(long) - 1));
sal = kzalloc(sizeof(struct seg_alloc), GFP_KERNEL);
if (!sal)
return -ENOMEM;
init_rwsem(&sal->rwsem);
sal->pending_root = RB_ROOT;
/* XXX read next_segno from super? */
sbi->seg_alloc = sal;
return 0;
}
void scoutfs_alloc_destroy(struct super_block *sb)
{
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
DECLARE_SEG_ALLOC(sb, sal);
struct pending_region *pend;
struct rb_node *node;
if (sal) {
while ((node = rb_first(&sal->pending_root))) {
pend = container_of(node, struct pending_region, node);
rb_erase(&pend->node, &sal->pending_root);
kfree(pend);
}
kfree(sal);
sbi->seg_alloc = NULL;
}
}
-15
View File
@@ -1,15 +0,0 @@
#ifndef _SCOUTFS_ALLOC_H_
#define _SCOUTFS_ALLOC_H_
struct scoutfs_alloc_region;
int scoutfs_alloc_segno(struct super_block *sb, u64 *segno);
int scoutfs_alloc_free(struct super_block *sb, u64 segno);
int scoutfs_alloc_apply_pending(struct super_block *sb);
u64 scoutfs_alloc_bfree(struct super_block *sb);
int scoutfs_alloc_setup(struct super_block *sb);
void scoutfs_alloc_destroy(struct super_block *sb);
#endif
-92
View File
@@ -19,7 +19,6 @@
#include <linux/in.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/sort.h>
#include <asm/barrier.h>
#include "format.h"
@@ -607,97 +606,6 @@ int scoutfs_client_record_segment(struct super_block *sb,
sizeof(net_ment), NULL, 0);
}
static int sort_cmp_u64s(const void *A, const void *B)
{
const u64 *a = A;
const u64 *b = B;
return *a < *b ? -1 : *a > *b ? 1 : 0;
}
static void sort_swap_u64s(void *A, void *B, int size)
{
u64 *a = A;
u64 *b = B;
swap(*a, *b);
}
/*
* Returns a 0-terminated allocated array of segnos, the caller is
* responsible for freeing it.
*
* This double alloc is silly. But the caller does have an easier time
* with native u64s. We'll probably clean this up.
*/
u64 *scoutfs_client_bulk_alloc(struct super_block *sb)
{
struct client_info *client = SCOUTFS_SB(sb)->client_info;
struct scoutfs_net_segnos *ns = NULL;
u64 *segnos = NULL;
size_t size;
unsigned nr;
u64 prev;
int ret;
int i;
size = offsetof(struct scoutfs_net_segnos,
segnos[SCOUTFS_BULK_ALLOC_COUNT]);
ns = kmalloc(size, GFP_NOFS);
if (!ns) {
ret = -ENOMEM;
goto out;
}
ret = client_request(client, SCOUTFS_NET_BULK_ALLOC, NULL, 0, ns, size);
if (ret)
goto out;
nr = le16_to_cpu(ns->nr);
if (nr == 0) {
ret = -ENOSPC;
goto out;
}
if (nr > SCOUTFS_BULK_ALLOC_COUNT) {
ret = -EINVAL;
goto out;
}
segnos = kmalloc_array(nr + 1, sizeof(*segnos), GFP_NOFS);
if (segnos == NULL) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < nr; i++)
segnos[i] = le64_to_cpu(ns->segnos[i]);
segnos[nr] = 0;
/* sort segnos for the caller so they can merge easily */
sort(segnos, nr, sizeof(segnos[0]), sort_cmp_u64s, sort_swap_u64s);
/* make sure they're all non-zero and unique */
prev = 0;
for (i = 0; i < nr; i++) {
if (segnos[i] == prev) {
ret = -EINVAL;
goto out;
}
prev = segnos[i];
}
ret = 0;
out:
kfree(ns);
if (ret) {
kfree(segnos);
segnos = ERR_PTR(ret);
}
return segnos;
}
int scoutfs_client_advance_seq(struct super_block *sb, u64 *seq)
{
struct client_info *client = SCOUTFS_SB(sb)->client_info;
-1
View File
@@ -22,7 +22,6 @@
#include "compact.h"
#include "manifest.h"
#include "counters.h"
#include "alloc.h"
#include "server.h"
#include "scoutfs_trace.h"
+1 -3
View File
@@ -12,8 +12,6 @@
* other places by this macro. Don't forget to update LAST_COUNTER.
*/
#define EXPAND_EACH_COUNTER \
EXPAND_COUNTER(alloc_alloc) \
EXPAND_COUNTER(alloc_free) \
EXPAND_COUNTER(btree_read_error) \
EXPAND_COUNTER(btree_stale_read) \
EXPAND_COUNTER(btree_write_error) \
@@ -117,7 +115,7 @@
EXPAND_COUNTER(trans_level0_seg_writes)
#define FIRST_COUNTER alloc_alloc
#define FIRST_COUNTER btree_read_error
#define LAST_COUNTER trans_level0_seg_writes
#undef EXPAND_COUNTER
-25
View File
@@ -249,19 +249,6 @@ struct scoutfs_extent_btree_key {
__be64 minor;
} __packed;
#define SCOUTFS_ALLOC_REGION_SHIFT 8
#define SCOUTFS_ALLOC_REGION_BITS (1 << SCOUTFS_ALLOC_REGION_SHIFT)
#define SCOUTFS_ALLOC_REGION_MASK (SCOUTFS_ALLOC_REGION_BITS - 1)
struct scoutfs_alloc_region_btree_key {
__be64 index;
} __packed;
/* The bits need to be aligned so that the hosts can use native long bit ops */
struct scoutfs_alloc_region_btree_val {
__le64 bits[SCOUTFS_ALLOC_REGION_BITS / 64];
} __packed;
/*
* The max number of links defines the max number of entries that we can
* index in o(log n) and the static list head storage size in the
@@ -380,9 +367,6 @@ struct scoutfs_super_block {
__u8 uuid[SCOUTFS_UUID_BYTES];
__le64 next_ino;
__le64 next_seq;
__le64 alloc_uninit;
__le64 total_segs;
__le64 free_segs;
__le64 total_blocks;
__le64 free_blocks;
__le64 alloc_cursor;
@@ -571,14 +555,6 @@ struct scoutfs_net_manifest_entry {
__u8 keys[0];
} __packed;
/* XXX I dunno, totally made up */
#define SCOUTFS_BULK_ALLOC_COUNT 32
struct scoutfs_net_segnos {
__le16 nr;
__le64 segnos[0];
} __packed;
struct scoutfs_net_statfs {
__le64 total_blocks; /* total blocks in device */
__le64 next_ino; /* next unused inode number */
@@ -601,7 +577,6 @@ enum {
SCOUTFS_NET_ALLOC_EXTENT,
SCOUTFS_NET_ALLOC_SEGNO,
SCOUTFS_NET_RECORD_SEGMENT,
SCOUTFS_NET_BULK_ALLOC,
SCOUTFS_NET_ADVANCE_SEQ,
SCOUTFS_NET_GET_LAST_SEQ,
SCOUTFS_NET_GET_MANIFEST_ROOT,
-48
View File
@@ -1087,54 +1087,6 @@ TRACE_EVENT(scoutfs_compact_func,
TP_printk(FSID_FMT" ret %d", __entry->fsid, __entry->ret)
);
TRACE_EVENT(scoutfs_alloc_free,
TP_PROTO(struct super_block *sb, __u64 segno, __u64 index, int nr,
int ret),
TP_ARGS(sb, segno, index, nr, ret),
TP_STRUCT__entry(
__field(__u64, fsid)
__field(__u64, segno)
__field(__u64, index)
__field(int, nr)
__field(int, ret)
),
TP_fast_assign(
__entry->fsid = FSID_ARG(sb);
__entry->segno = segno;
__entry->index = index;
__entry->nr = nr;
__entry->ret = ret;
),
TP_printk(FSID_FMT" freeing segno %llu ind %llu nr %d ret %d",
__entry->fsid, __entry->segno, __entry->index, __entry->nr,
__entry->ret)
);
TRACE_EVENT(scoutfs_alloc_segno,
TP_PROTO(struct super_block *sb, __u64 segno, int ret),
TP_ARGS(sb, segno, ret),
TP_STRUCT__entry(
__field(__u64, fsid)
__field(__u64, segno)
__field(int, ret)
),
TP_fast_assign(
__entry->fsid = FSID_ARG(sb);
__entry->segno = segno;
__entry->ret = ret;
),
TP_printk(FSID_FMT" segno %llu ret %d", __entry->fsid, __entry->segno,
__entry->ret)
);
TRACE_EVENT(scoutfs_write_begin,
TP_PROTO(struct super_block *sb, u64 ino, loff_t pos, unsigned len),
-1
View File
@@ -23,7 +23,6 @@
#include "kvec.h"
#include "cmp.h"
#include "manifest.h"
#include "alloc.h"
#include "key.h"
#include "counters.h"
#include "triggers.h"
-55
View File
@@ -19,7 +19,6 @@
#include <linux/in.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/sort.h>
#include <linux/log2.h>
#include "format.h"
@@ -27,7 +26,6 @@
#include "inode.h"
#include "btree.h"
#include "manifest.h"
#include "alloc.h"
#include "seg.h"
#include "compact.h"
#include "scoutfs_trace.h"
@@ -811,58 +809,6 @@ out:
return send_reply(conn, id, type, ret, NULL, 0);
}
static int process_bulk_alloc(struct server_connection *conn, u64 id, u8 type,
void *data, unsigned data_len)
{
struct server_info *server = conn->server;
struct super_block *sb = server->sb;
struct scoutfs_net_segnos *ns = NULL;
struct commit_waiter cw;
size_t size;
u64 segno;
int ret;
int i;
if (data_len != 0) {
ret = -EINVAL;
goto out;
}
size = offsetof(struct scoutfs_net_segnos,
segnos[SCOUTFS_BULK_ALLOC_COUNT]);
ns = kmalloc(size, GFP_NOFS);
if (!ns) {
ret = -ENOMEM;
goto out;
}
down_read(&server->commit_rwsem);
ns->nr = cpu_to_le16(SCOUTFS_BULK_ALLOC_COUNT);
for (i = 0; i < SCOUTFS_BULK_ALLOC_COUNT; i++) {
ret = scoutfs_alloc_segno(sb, &segno);
if (ret) {
while (i-- > 0)
scoutfs_alloc_free(sb,
le64_to_cpu(ns->segnos[i]));
break;
}
ns->segnos[i] = cpu_to_le64(segno);
}
if (ret == 0)
queue_commit_work(server, &cw);
up_read(&server->commit_rwsem);
if (ret == 0)
ret = wait_for_commit(server, &cw, id, type);
out:
ret = send_reply(conn, id, type, ret, ns, size);
kfree(ns);
return ret;
}
struct pending_seq {
struct list_head head;
u64 seq;
@@ -1125,7 +1071,6 @@ static void scoutfs_server_process_func(struct work_struct *work)
[SCOUTFS_NET_ALLOC_EXTENT] = process_alloc_extent,
[SCOUTFS_NET_ALLOC_SEGNO] = process_alloc_segno,
[SCOUTFS_NET_RECORD_SEGMENT] = process_record_segment,
[SCOUTFS_NET_BULK_ALLOC] = process_bulk_alloc,
[SCOUTFS_NET_ADVANCE_SEQ] = process_advance_seq,
[SCOUTFS_NET_GET_LAST_SEQ] = process_get_last_seq,
[SCOUTFS_NET_GET_MANIFEST_ROOT] = process_get_manifest_root,
-1
View File
@@ -34,7 +34,6 @@
#include "manifest.h"
#include "seg.h"
#include "bio.h"
#include "alloc.h"
#include "compact.h"
#include "data.h"
#include "lock.h"