diff --git a/kmod/src/Makefile b/kmod/src/Makefile index 9e8a6703..61b12f70 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -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 \ diff --git a/kmod/src/alloc.c b/kmod/src/alloc.c deleted file mode 100644 index b501483c..00000000 --- a/kmod/src/alloc.c +++ /dev/null @@ -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 -#include -#include -#include - -#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, - ®_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(®_key, ®_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, - ®_key, sizeof(reg_key)); - else - ret = scoutfs_btree_update(sb, &super->alloc_root, - ®_key, sizeof(reg_key), - ®_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, - ®_key, sizeof(reg_key), &iref); - if (ret == -ENOENT) { - /* create a new item if we don't */ - ret = scoutfs_btree_insert(sb, &super->alloc_root, - ®_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(®_key, ®_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, - ®_key, sizeof(reg_key), - ®_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; - } -} diff --git a/kmod/src/alloc.h b/kmod/src/alloc.h deleted file mode 100644 index d6c8a5b0..00000000 --- a/kmod/src/alloc.h +++ /dev/null @@ -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 diff --git a/kmod/src/client.c b/kmod/src/client.c index 1ad2de21..c3c0bb91 100644 --- a/kmod/src/client.c +++ b/kmod/src/client.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #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; diff --git a/kmod/src/compact.c b/kmod/src/compact.c index 7ae99183..3efb88ed 100644 --- a/kmod/src/compact.c +++ b/kmod/src/compact.c @@ -22,7 +22,6 @@ #include "compact.h" #include "manifest.h" #include "counters.h" -#include "alloc.h" #include "server.h" #include "scoutfs_trace.h" diff --git a/kmod/src/counters.h b/kmod/src/counters.h index b07b5e46..621d72c0 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -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 diff --git a/kmod/src/format.h b/kmod/src/format.h index f0a28347..87655716 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -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, diff --git a/kmod/src/scoutfs_trace.h b/kmod/src/scoutfs_trace.h index 2c435714..5e480364 100644 --- a/kmod/src/scoutfs_trace.h +++ b/kmod/src/scoutfs_trace.h @@ -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), diff --git a/kmod/src/seg.c b/kmod/src/seg.c index 3b402f93..a69a226d 100644 --- a/kmod/src/seg.c +++ b/kmod/src/seg.c @@ -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" diff --git a/kmod/src/server.c b/kmod/src/server.c index 64c862c1..b9538f87 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #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, diff --git a/kmod/src/super.c b/kmod/src/super.c index 8b728d22..6b853766 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -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"