mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 11:10:44 +00:00
scoutfs: store manifest entries in the btree
Convert the manifest to store entries in persistent btree keys and values instead of using the rbtree in memory from the ring. The btree doesn't have a sort function. It just compares variable length keys. The most complicated part of this transformation is dealing with the fallout of this. The compare function can't compare different search keys and item keys so searches need to construct full synthetic btree keys to search. It also can't return different comparisons, like overlaping, so the caller needs to do a bit more work to use key comparisons to find overlapping segments. And it can't compare differently depending on the level of the manifest so we store the manifest in keys differently depending on whether its in level 0 or not. All mount clients can now see the manifest blocks. They can query the manifest directly when trying to find segments to read. We can get rid of all the networking calls that were finding the segments for readers. We change the manifest functions that relied on the ring that the to make changes in the manifest persistent. We don't touch the allocator or the rest of the manifest server, though, so this commit breaks the world. It'll be restored in future patches as we update the segment allocator and server to work with the btree. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -1768,7 +1768,7 @@ int scoutfs_btree_write_dirty(struct super_block *sb)
|
||||
struct scoutfs_super_block *super = &sbi->super;
|
||||
struct scoutfs_btree_ring *bring = &super->bring;
|
||||
struct scoutfs_btree_root *roots[] = {
|
||||
/* XXX super roots go here */
|
||||
&super->manifest.root,
|
||||
NULL,
|
||||
};
|
||||
struct scoutfs_btree_root *root;
|
||||
|
||||
@@ -457,15 +457,13 @@ void scoutfs_compact_describe(struct super_block *sb, void *data,
|
||||
* and is then possibly adding all the lower overlapping segments.
|
||||
*/
|
||||
int scoutfs_compact_add(struct super_block *sb, void *data,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last, u64 segno, u64 seq,
|
||||
u8 level)
|
||||
struct scoutfs_manifest_entry *ment)
|
||||
{
|
||||
struct compact_cursor *curs = data;
|
||||
struct compact_seg *cseg;
|
||||
int ret;
|
||||
|
||||
cseg = alloc_cseg(sb, first, last);
|
||||
cseg = alloc_cseg(sb, &ment->first, &ment->last);
|
||||
if (!cseg) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
@@ -473,9 +471,9 @@ int scoutfs_compact_add(struct super_block *sb, void *data,
|
||||
|
||||
list_add_tail(&cseg->entry, &curs->csegs);
|
||||
|
||||
cseg->segno = segno;
|
||||
cseg->seq = seq;
|
||||
cseg->level = level;
|
||||
cseg->segno = ment->segno;
|
||||
cseg->seq = ment->seq;
|
||||
cseg->level = ment->level;
|
||||
|
||||
if (!curs->upper)
|
||||
curs->upper = cseg;
|
||||
@@ -501,8 +499,8 @@ void scoutfs_compact_add_segno(struct super_block *sb, void *data, u64 segno)
|
||||
|
||||
/*
|
||||
* Commit the result of a compaction based on the state of the cursor.
|
||||
* The net caller stops the rings from being written while we're making
|
||||
* changes. We lock the manifest to atomically make our changes.
|
||||
* The net caller stops the manifest from being written while we're
|
||||
* making changes. We lock the manifest to atomically make our changes.
|
||||
*
|
||||
* The erorr handling is sketchy here because calling the manifest from
|
||||
* here is temporary. We should be sending a message to the server
|
||||
@@ -510,6 +508,7 @@ void scoutfs_compact_add_segno(struct super_block *sb, void *data, u64 segno)
|
||||
*/
|
||||
int scoutfs_compact_commit(struct super_block *sb, void *c, void *r)
|
||||
{
|
||||
struct scoutfs_manifest_entry ment;
|
||||
struct compact_cursor *curs = c;
|
||||
struct list_head *results = r;
|
||||
struct compact_seg *cseg;
|
||||
@@ -533,8 +532,9 @@ int scoutfs_compact_commit(struct super_block *sb, void *c, void *r)
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
ret = scoutfs_manifest_del(sb, cseg->first,
|
||||
cseg->seq, cseg->level);
|
||||
scoutfs_manifest_init_entry(&ment, cseg->level, 0, cseg->seq,
|
||||
cseg->first, NULL);
|
||||
ret = scoutfs_manifest_del(sb, &ment);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
@@ -542,12 +542,12 @@ int scoutfs_compact_commit(struct super_block *sb, void *c, void *r)
|
||||
list_for_each_entry(cseg, results, entry) {
|
||||
/* XXX moved upper segments won't have read the segment :P */
|
||||
if (cseg->seg)
|
||||
ret = scoutfs_seg_manifest_add(sb, cseg->seg,
|
||||
cseg->level);
|
||||
scoutfs_seg_init_ment(&ment, cseg->level, cseg->seg);
|
||||
else
|
||||
ret = scoutfs_manifest_add(sb, cseg->first,
|
||||
cseg->last, cseg->segno,
|
||||
cseg->seq, cseg->level);
|
||||
scoutfs_manifest_init_entry(&ment, cseg->level,
|
||||
cseg->segno, cseg->seq,
|
||||
cseg->first, cseg->last);
|
||||
ret = scoutfs_manifest_add(sb, &ment);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ void scoutfs_compact_kick(struct super_block *sb);
|
||||
void scoutfs_compact_describe(struct super_block *sb, void *data,
|
||||
u8 upper_level, u8 last_level, bool sticky);
|
||||
int scoutfs_compact_add(struct super_block *sb, void *data,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last, u64 segno, u64 seq,
|
||||
u8 level);
|
||||
struct scoutfs_manifest_entry *ment);
|
||||
void scoutfs_compact_add_segno(struct super_block *sb, void *data, u64 segno);
|
||||
int scoutfs_compact_commit(struct super_block *sb, void *c, void *r);
|
||||
|
||||
|
||||
@@ -169,16 +169,38 @@ struct scoutfs_btree_ring {
|
||||
#define SCOUTFS_MANIFEST_FANOUT 10
|
||||
|
||||
struct scoutfs_manifest {
|
||||
struct scoutfs_ring_descriptor ring;
|
||||
struct scoutfs_btree_root root;
|
||||
__le64 level_counts[SCOUTFS_MANIFEST_MAX_LEVEL];
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_manifest_entry {
|
||||
/*
|
||||
* Manifest entries are packed into btree keys and values in a very
|
||||
* fiddly way so that we can sort them with memcmp first by level then
|
||||
* by their position in the level. First comes the level.
|
||||
*
|
||||
* Level 0 segments are sorted by their seq so they don't have the first
|
||||
* segment key in the manifest btree key. Both of their keys are in the
|
||||
* value.
|
||||
*
|
||||
* Level 1 segments are sorted by their first key so their last key is
|
||||
* in the value.
|
||||
*
|
||||
* We go to all this trouble so that we can communicate a version of the
|
||||
* manifest with one btree root, have dense btree keys which are used as
|
||||
* seperators in parent blocks, and don't duplicate the large keys in
|
||||
* the manifest btree key and value.
|
||||
*/
|
||||
|
||||
struct scoutfs_manifest_btree_key {
|
||||
__u8 level;
|
||||
__u8 bkey[0];
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_manifest_btree_val {
|
||||
__le64 segno;
|
||||
__le64 seq;
|
||||
__le16 first_key_len;
|
||||
__le16 last_key_len;
|
||||
__u8 level;
|
||||
__u8 keys[0];
|
||||
} __packed;
|
||||
|
||||
@@ -536,9 +558,13 @@ struct scoutfs_net_key_range {
|
||||
__u8 key_bytes[0];
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_net_manifest_entries {
|
||||
__le16 nr;
|
||||
struct scoutfs_manifest_entry ments[0];
|
||||
struct scoutfs_net_manifest_entry {
|
||||
__le64 segno;
|
||||
__le64 seq;
|
||||
__le16 first_key_len;
|
||||
__le16 last_key_len;
|
||||
__u8 level;
|
||||
__u8 keys[0];
|
||||
} __packed;
|
||||
|
||||
/* XXX I dunno, totally made up */
|
||||
@@ -561,7 +587,6 @@ struct scoutfs_net_segnos {
|
||||
|
||||
enum {
|
||||
SCOUTFS_NET_ALLOC_INODES = 0,
|
||||
SCOUTFS_NET_MANIFEST_RANGE_ENTRIES,
|
||||
SCOUTFS_NET_ALLOC_SEGNO,
|
||||
SCOUTFS_NET_RECORD_SEGMENT,
|
||||
SCOUTFS_NET_BULK_ALLOC,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,39 @@
|
||||
#ifndef _SCOUTFS_MANIFEST_H_
|
||||
#define _SCOUTFS_MANIFEST_H_
|
||||
|
||||
struct scoutfs_key_buf;
|
||||
#include "key.h"
|
||||
|
||||
struct scoutfs_bio_completion;
|
||||
|
||||
/*
|
||||
* This native manifest entry references the physical storage of a
|
||||
* manifest entry which can exist in a segment header and its edge keys,
|
||||
* a network transmission of a packed entry and its keys, or in btree
|
||||
* blocks spread between an item key and value.
|
||||
*/
|
||||
struct scoutfs_manifest_entry {
|
||||
u8 level;
|
||||
u64 segno;
|
||||
u64 seq;
|
||||
struct scoutfs_key_buf first;
|
||||
struct scoutfs_key_buf last;
|
||||
};
|
||||
|
||||
void scoutfs_manifest_init_entry(struct scoutfs_manifest_entry *ment,
|
||||
u64 level, u64 segno, u64 seq,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last);
|
||||
int scoutfs_manifest_add(struct super_block *sb,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last, u64 segno, u64 seq,
|
||||
u8 level);
|
||||
int scoutfs_manifest_add_ment(struct super_block *sb,
|
||||
struct scoutfs_manifest_entry *add);
|
||||
int scoutfs_manifest_dirty(struct super_block *sb,
|
||||
struct scoutfs_key_buf *first, u64 seq, u8 level);
|
||||
int scoutfs_manifest_del(struct super_block *sb, struct scoutfs_key_buf *first,
|
||||
u64 seq, u8 level);
|
||||
int scoutfs_manifest_has_dirty(struct super_block *sb);
|
||||
int scoutfs_manifest_submit_write(struct super_block *sb,
|
||||
struct scoutfs_bio_completion *comp);
|
||||
void scoutfs_manifest_write_complete(struct super_block *sb);
|
||||
|
||||
int scoutfs_manifest_bytes(struct scoutfs_manifest_entry *ment);
|
||||
|
||||
struct scoutfs_manifest_entry *
|
||||
scoutfs_manifest_alloc_entry(struct super_block *sb,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last, u64 segno, u64 seq,
|
||||
u8 level);
|
||||
struct scoutfs_manifest_entry *ment);
|
||||
int scoutfs_manifest_del(struct super_block *sb,
|
||||
struct scoutfs_manifest_entry *ment);
|
||||
|
||||
int scoutfs_manifest_lock(struct super_block *sb);
|
||||
int scoutfs_manifest_unlock(struct super_block *sb);
|
||||
|
||||
struct scoutfs_manifest_entry **
|
||||
scoutfs_manifest_find_range_entries(struct super_block *sb,
|
||||
struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *end,
|
||||
unsigned *found_bytes);
|
||||
|
||||
int scoutfs_manifest_read_items(struct super_block *sb,
|
||||
struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *end);
|
||||
int scoutfs_manifest_add_ment_ref(struct super_block *sb,
|
||||
struct list_head *list,
|
||||
struct scoutfs_manifest_entry *ment);
|
||||
|
||||
int scoutfs_manifest_next_compact(struct super_block *sb, void *data);
|
||||
|
||||
|
||||
283
kmod/src/net.c
283
kmod/src/net.c
@@ -25,6 +25,7 @@
|
||||
#include "net.h"
|
||||
#include "counters.h"
|
||||
#include "inode.h"
|
||||
#include "btree.h"
|
||||
#include "manifest.h"
|
||||
#include "bio.h"
|
||||
#include "alloc.h"
|
||||
@@ -331,8 +332,8 @@ static void scoutfs_net_ring_commit_func(struct work_struct *work)
|
||||
|
||||
down_write(&nti->ring_commit_rwsem);
|
||||
|
||||
if (scoutfs_manifest_has_dirty(sb) || scoutfs_alloc_has_dirty(sb)) {
|
||||
ret = scoutfs_manifest_submit_write(sb, &comp) ?:
|
||||
if (scoutfs_btree_has_dirty(sb)) {
|
||||
ret = scoutfs_btree_write_dirty(sb) ?:
|
||||
scoutfs_alloc_submit_write(sb, &comp) ?:
|
||||
scoutfs_bio_wait_comp(sb, &comp) ?:
|
||||
scoutfs_write_dirty_super(sb);
|
||||
@@ -340,7 +341,7 @@ static void scoutfs_net_ring_commit_func(struct work_struct *work)
|
||||
/* we'd need to loop or something */
|
||||
BUG_ON(ret);
|
||||
|
||||
scoutfs_manifest_write_complete(sb);
|
||||
scoutfs_btree_write_complete(sb);
|
||||
scoutfs_alloc_write_complete(sb);
|
||||
|
||||
scoutfs_advance_dirty_super(sb);
|
||||
@@ -425,6 +426,69 @@ static struct send_buf *process_bulk_alloc(struct super_block *sb,void *req,
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
static void init_net_ment_keys(struct scoutfs_net_manifest_entry *net_ment,
|
||||
struct scoutfs_key_buf *first,
|
||||
struct scoutfs_key_buf *last)
|
||||
{
|
||||
scoutfs_key_init(first, net_ment->keys,
|
||||
le16_to_cpu(net_ment->first_key_len));
|
||||
scoutfs_key_init(last, net_ment->keys +
|
||||
le16_to_cpu(net_ment->first_key_len),
|
||||
le16_to_cpu(net_ment->last_key_len));
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a contiguous manifest entry for communication over the network.
|
||||
*/
|
||||
static struct scoutfs_net_manifest_entry *
|
||||
alloc_net_ment(struct scoutfs_manifest_entry *ment)
|
||||
{
|
||||
struct scoutfs_net_manifest_entry *net_ment;
|
||||
struct scoutfs_key_buf first;
|
||||
struct scoutfs_key_buf last;
|
||||
|
||||
net_ment = kmalloc(offsetof(struct scoutfs_net_manifest_entry,
|
||||
keys[ment->first.key_len +
|
||||
ment->last.key_len]), GFP_NOFS);
|
||||
if (!net_ment)
|
||||
return NULL;
|
||||
|
||||
net_ment->segno = cpu_to_le64(ment->segno);
|
||||
net_ment->seq = cpu_to_le64(ment->seq);
|
||||
net_ment->first_key_len = cpu_to_le16(ment->first.key_len);
|
||||
net_ment->last_key_len = cpu_to_le16(ment->last.key_len);
|
||||
net_ment->level = ment->level;
|
||||
|
||||
init_net_ment_keys(net_ment, &first, &last);
|
||||
scoutfs_key_copy(&first, &ment->first);
|
||||
scoutfs_key_copy(&last, &ment->last);
|
||||
|
||||
return net_ment;
|
||||
}
|
||||
|
||||
/* point a native manifest entry at a contiguous net manifest */
|
||||
static void init_ment_net_ment(struct scoutfs_manifest_entry *ment,
|
||||
struct scoutfs_net_manifest_entry *net_ment)
|
||||
{
|
||||
struct scoutfs_key_buf first;
|
||||
struct scoutfs_key_buf last;
|
||||
|
||||
init_net_ment_keys(net_ment, &first, &last);
|
||||
scoutfs_key_clone(&ment->first, &first);
|
||||
scoutfs_key_clone(&ment->last, &last);
|
||||
|
||||
ment->segno = le64_to_cpu(net_ment->segno);
|
||||
ment->seq = le64_to_cpu(net_ment->seq);
|
||||
ment->level = net_ment->level;
|
||||
}
|
||||
|
||||
static unsigned net_ment_bytes(struct scoutfs_net_manifest_entry *net_ment)
|
||||
{
|
||||
return offsetof(struct scoutfs_net_manifest_entry,
|
||||
keys[le16_to_cpu(net_ment->first_key_len) +
|
||||
le16_to_cpu(net_ment->last_key_len)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is new segments arriving. It needs to wait for level 0 to be
|
||||
* free. It has relatively little visibility into the manifest, though.
|
||||
@@ -443,19 +507,20 @@ static struct send_buf *process_record_segment(struct super_block *sb,
|
||||
void *req, int req_len)
|
||||
{
|
||||
DECLARE_NET_INFO(sb, nti);
|
||||
struct scoutfs_manifest_entry *ment;
|
||||
struct scoutfs_manifest_entry ment;
|
||||
struct scoutfs_net_manifest_entry *net_ment;
|
||||
struct commit_waiter cw;
|
||||
struct send_buf *sbuf;
|
||||
int ret;
|
||||
|
||||
if (req_len < sizeof(struct scoutfs_manifest_entry)) {
|
||||
if (req_len < sizeof(struct scoutfs_net_manifest_entry)) {
|
||||
sbuf = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ment = req;
|
||||
net_ment = req;
|
||||
|
||||
if (req_len != scoutfs_manifest_bytes(ment)) {
|
||||
if (req_len != net_ment_bytes(net_ment)) {
|
||||
sbuf = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
@@ -472,7 +537,9 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ret = scoutfs_manifest_add_ment(sb, ment);
|
||||
init_ment_net_ment(&ment, net_ment);
|
||||
|
||||
ret = scoutfs_manifest_add(sb, &ment);
|
||||
scoutfs_manifest_unlock(sb);
|
||||
|
||||
if (ret == 0)
|
||||
@@ -542,73 +609,6 @@ out:
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the manifest entries that intersect with the request's key
|
||||
* range. We lock the manifest and get pointers to the manifest entries
|
||||
* that intersect. We then allocate a reply buffer and copy them over.
|
||||
*/
|
||||
static struct send_buf *process_manifest_range_entries(struct super_block *sb,
|
||||
void *req, int req_len)
|
||||
{
|
||||
struct scoutfs_net_key_range *kr = req;
|
||||
struct scoutfs_net_manifest_entries *ments;
|
||||
struct scoutfs_manifest_entry **found = NULL;
|
||||
struct scoutfs_manifest_entry *ment;
|
||||
struct scoutfs_key_buf start;
|
||||
struct scoutfs_key_buf end;
|
||||
struct send_buf *sbuf;
|
||||
unsigned total;
|
||||
unsigned bytes;
|
||||
int i;
|
||||
|
||||
/* XXX this is a write lock and should be a read lock */
|
||||
scoutfs_manifest_lock(sb);
|
||||
|
||||
if (req_len < sizeof(struct scoutfs_net_key_range) ||
|
||||
req_len < offsetof(struct scoutfs_net_key_range,
|
||||
key_bytes[le16_to_cpu(kr->start_len) +
|
||||
le16_to_cpu(kr->end_len)])) {
|
||||
sbuf = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scoutfs_key_init(&start, kr->key_bytes, le16_to_cpu(kr->start_len));
|
||||
scoutfs_key_init(&end, kr->key_bytes + le16_to_cpu(kr->start_len),
|
||||
le16_to_cpu(kr->end_len));
|
||||
|
||||
found = scoutfs_manifest_find_range_entries(sb, &start, &end, &total);
|
||||
if (IS_ERR(found)) {
|
||||
sbuf = ERR_CAST(found);
|
||||
goto out;
|
||||
}
|
||||
|
||||
total += sizeof(struct scoutfs_net_manifest_entries);
|
||||
|
||||
sbuf = alloc_sbuf(total);
|
||||
if (!sbuf) {
|
||||
sbuf = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ments = (void *)sbuf->nh->data;
|
||||
ment = ments->ments;
|
||||
|
||||
for (i = 0; found[i]; i++) {
|
||||
bytes = scoutfs_manifest_bytes(found[i]);
|
||||
memcpy(ment, found[i], bytes);
|
||||
ment = (void *)((char *)ment + bytes);
|
||||
}
|
||||
|
||||
ments->nr = cpu_to_le16(i);
|
||||
sbuf->nh->status = SCOUTFS_NET_STATUS_SUCCESS;
|
||||
|
||||
out:
|
||||
scoutfs_manifest_unlock(sb);
|
||||
if (!IS_ERR_OR_NULL(found))
|
||||
kfree(found);
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX should this call into inodes? not sure about the layering here.
|
||||
*/
|
||||
@@ -790,8 +790,6 @@ static proc_func_t type_proc_func(u8 type)
|
||||
{
|
||||
static proc_func_t funcs[] = {
|
||||
[SCOUTFS_NET_ALLOC_INODES] = process_alloc_inodes,
|
||||
[SCOUTFS_NET_MANIFEST_RANGE_ENTRIES] =
|
||||
process_manifest_range_entries,
|
||||
[SCOUTFS_NET_ALLOC_SEGNO] = process_alloc_segno,
|
||||
[SCOUTFS_NET_RECORD_SEGMENT] = process_record_segment,
|
||||
[SCOUTFS_NET_BULK_ALLOC] = process_bulk_alloc,
|
||||
@@ -889,7 +887,8 @@ static void destroy_server_state(struct super_block *sb)
|
||||
|
||||
scoutfs_compact_destroy(sb);
|
||||
scoutfs_alloc_destroy(sb);
|
||||
scoutfs_manifest_destroy(sb);
|
||||
/* XXX this drops dirty data on the floor.. has it committed? */
|
||||
scoutfs_btree_write_complete(sb);
|
||||
|
||||
/* XXX these should be persistent and reclaimed during recovery */
|
||||
list_for_each_entry_safe(ps, tmp, &nti->pending_seqs, head) {
|
||||
@@ -918,6 +917,7 @@ static void scoutfs_net_proc_func(struct work_struct *work)
|
||||
mutex_lock(&nti->mutex);
|
||||
if (!nti->server_loaded) {
|
||||
ret = scoutfs_read_supers(sb, &SCOUTFS_SB(sb)->super) ?:
|
||||
scoutfs_btree_prepare_write(sb) ?:
|
||||
scoutfs_manifest_setup(sb) ?:
|
||||
scoutfs_alloc_setup(sb) ?:
|
||||
scoutfs_compact_setup(sb);
|
||||
@@ -1526,22 +1526,24 @@ static int record_segment_reply(struct super_block *sb, void *reply, int ret,
|
||||
int scoutfs_net_record_segment(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level)
|
||||
{
|
||||
struct scoutfs_manifest_entry *ment;
|
||||
struct scoutfs_net_manifest_entry *net_ment;
|
||||
struct record_segment_args args;
|
||||
struct scoutfs_manifest_entry ment;
|
||||
int ret;
|
||||
|
||||
ment = scoutfs_seg_manifest_entry(sb, seg, level);
|
||||
if (!ment) {
|
||||
scoutfs_seg_init_ment(&ment, level, seg);
|
||||
net_ment = alloc_net_ment(&ment);
|
||||
if (!net_ment) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
init_completion(&args.comp);
|
||||
|
||||
ret = add_send_buf(sb, SCOUTFS_NET_RECORD_SEGMENT, ment,
|
||||
scoutfs_manifest_bytes(ment),
|
||||
ret = add_send_buf(sb, SCOUTFS_NET_RECORD_SEGMENT, net_ment,
|
||||
net_ment_bytes(net_ment),
|
||||
record_segment_reply, &args);
|
||||
kfree(ment);
|
||||
kfree(net_ment);
|
||||
if (ret == 0) {
|
||||
wait_for_completion(&args.comp);
|
||||
ret = args.ret;
|
||||
@@ -1592,119 +1594,6 @@ int scoutfs_net_alloc_segno(struct super_block *sb, u64 *segno)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct manifest_range_entries_args {
|
||||
struct list_head *list;
|
||||
struct completion comp;
|
||||
int ret;
|
||||
};
|
||||
|
||||
/*
|
||||
* The server has given us entries that intersect with our request's
|
||||
* key range. Our caller is still blocked waiting for our completion.
|
||||
* We walk the manifest entries and add native manifest refs to their
|
||||
* list and wake them.
|
||||
*/
|
||||
static int manifest_range_entries_reply(struct super_block *sb, void *reply,
|
||||
int reply_bytes, void *arg)
|
||||
{
|
||||
struct manifest_range_entries_args *args = arg;
|
||||
struct scoutfs_net_manifest_entries *ments = reply;
|
||||
struct scoutfs_manifest_entry *ment;
|
||||
unsigned bytes;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (reply_bytes < 0) {
|
||||
ret = reply_bytes;
|
||||
goto out;
|
||||
}
|
||||
|
||||
reply_bytes -= sizeof(struct scoutfs_net_manifest_entries);
|
||||
if (reply_bytes < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ment = ments->ments;
|
||||
for (i = 0; i < le16_to_cpu(ments->nr); i++) {
|
||||
|
||||
|
||||
if (reply_bytes < sizeof(struct scoutfs_manifest_entry)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bytes = scoutfs_manifest_bytes(ment);
|
||||
reply_bytes -= bytes;
|
||||
if (reply_bytes < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_manifest_add_ment_ref(sb, args->list, ment);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ment = (void *)((char *)ment + bytes);
|
||||
}
|
||||
|
||||
out:
|
||||
args->ret = ret;
|
||||
complete(&args->comp); /* args can be freed from this point */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the manifest server for the manifest entries whose key range
|
||||
* intersects with the callers key range. The reply func will fill the
|
||||
* caller's list with the reply's entries.
|
||||
*
|
||||
* XXX for now this can't be interrupted. The reply func which is off
|
||||
* in work in a worker thread is blocking to allocate and put things on
|
||||
* a list in our stack. We'd need better lifetime support to let it
|
||||
* find out that we've returned and that it should stop processing the
|
||||
* reply.
|
||||
*/
|
||||
int scoutfs_net_manifest_range_entries(struct super_block *sb,
|
||||
struct scoutfs_key_buf *start,
|
||||
struct scoutfs_key_buf *end,
|
||||
struct list_head *list)
|
||||
{
|
||||
struct manifest_range_entries_args args;
|
||||
struct scoutfs_net_key_range *kr;
|
||||
struct scoutfs_key_buf start_key;
|
||||
struct scoutfs_key_buf end_key;
|
||||
unsigned len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(struct scoutfs_net_key_range) +
|
||||
start->key_len + end->key_len;
|
||||
kr = kmalloc(len, GFP_NOFS);
|
||||
if (!kr)
|
||||
return -ENOMEM;
|
||||
|
||||
kr->start_len = cpu_to_le16(start->key_len);
|
||||
kr->end_len = cpu_to_le16(end->key_len);
|
||||
|
||||
scoutfs_key_init(&start_key, kr->key_bytes, start->key_len);
|
||||
scoutfs_key_init(&end_key, kr->key_bytes + start->key_len,
|
||||
end->key_len);
|
||||
scoutfs_key_copy(&start_key, start);
|
||||
scoutfs_key_copy(&end_key, end);
|
||||
|
||||
args.list = list;
|
||||
init_completion(&args.comp);
|
||||
|
||||
ret = add_send_buf(sb, SCOUTFS_NET_MANIFEST_RANGE_ENTRIES, kr, len,
|
||||
manifest_range_entries_reply, &args);
|
||||
kfree(kr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
wait_for_completion(&args.comp);
|
||||
return args.ret;
|
||||
}
|
||||
|
||||
static int alloc_inodes_reply(struct super_block *sb, void *reply, int ret,
|
||||
void *arg)
|
||||
{
|
||||
|
||||
@@ -5,10 +5,6 @@ struct scoutfs_key_buf;
|
||||
struct scoutfs_segment;
|
||||
|
||||
int scoutfs_net_alloc_inodes(struct super_block *sb);
|
||||
int scoutfs_net_manifest_range_entries(struct super_block *sb,
|
||||
struct scoutfs_key_buf *start,
|
||||
struct scoutfs_key_buf *end,
|
||||
struct list_head *list);
|
||||
int scoutfs_net_alloc_segno(struct super_block *sb, u64 *segno);
|
||||
int scoutfs_net_record_segment(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level);
|
||||
|
||||
@@ -350,8 +350,7 @@ void *scoutfs_ring_prev(struct scoutfs_ring_info *ring, void *data)
|
||||
|
||||
/*
|
||||
* Calculate the most blocks we could have to use to store a given number
|
||||
* of bytes of entries. At worst each block has a header and leaves one
|
||||
* less than the max manifest entry unused.
|
||||
* of bytes of entries.
|
||||
*/
|
||||
static unsigned most_blocks(unsigned long bytes)
|
||||
{
|
||||
@@ -359,8 +358,7 @@ static unsigned most_blocks(unsigned long bytes)
|
||||
|
||||
space = SCOUTFS_BLOCK_SIZE -
|
||||
sizeof(struct scoutfs_ring_block) -
|
||||
(sizeof(struct scoutfs_manifest_entry) +
|
||||
(2 * SCOUTFS_MAX_KEY_SIZE) - 1);
|
||||
sizeof(struct scoutfs_alloc_region);
|
||||
|
||||
return DIV_ROUND_UP(bytes, space);
|
||||
}
|
||||
|
||||
@@ -673,11 +673,8 @@ bool scoutfs_seg_append_item(struct super_block *sb, struct scoutfs_segment *seg
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a dirty manifest entry for the given segment at the given level.
|
||||
*/
|
||||
int scoutfs_seg_manifest_add(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level)
|
||||
void scoutfs_seg_init_ment(struct scoutfs_manifest_entry *ment, int level,
|
||||
struct scoutfs_segment *seg)
|
||||
{
|
||||
struct scoutfs_segment_block *sblk = off_ptr(seg, 0);
|
||||
struct scoutfs_key_buf first;
|
||||
@@ -685,38 +682,8 @@ int scoutfs_seg_manifest_add(struct super_block *sb,
|
||||
|
||||
first_last_keys(seg, &first, &last);
|
||||
|
||||
return scoutfs_manifest_add(sb, &first, &last, le64_to_cpu(sblk->segno),
|
||||
le64_to_cpu(sblk->seq), level);
|
||||
}
|
||||
|
||||
int scoutfs_seg_manifest_del(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level)
|
||||
{
|
||||
struct scoutfs_segment_block *sblk = off_ptr(seg, 0);
|
||||
struct scoutfs_key_buf first;
|
||||
|
||||
first_last_keys(seg, &first, NULL);
|
||||
|
||||
return scoutfs_manifest_del(sb, &first, le64_to_cpu(sblk->seq), level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an allocated manifest entry that describes the segment, returns
|
||||
* NULL if it couldn't allocate.
|
||||
*/
|
||||
struct scoutfs_manifest_entry *
|
||||
scoutfs_seg_manifest_entry(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level)
|
||||
{
|
||||
struct scoutfs_segment_block *sblk = off_ptr(seg, 0);
|
||||
struct scoutfs_key_buf first;
|
||||
struct scoutfs_key_buf last;
|
||||
|
||||
first_last_keys(seg, &first, &last);
|
||||
|
||||
return scoutfs_manifest_alloc_entry(sb, &first, &last,
|
||||
le64_to_cpu(sblk->segno),
|
||||
le64_to_cpu(sblk->seq), level);
|
||||
scoutfs_manifest_init_entry(ment, level, le64_to_cpu(sblk->segno),
|
||||
le64_to_cpu(sblk->seq), &first, &last);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
struct scoutfs_bio_completion;
|
||||
struct scoutfs_key_buf;
|
||||
struct scoutfs_manifest_entry;
|
||||
struct kvec;
|
||||
|
||||
/* this is only visible for trace events */
|
||||
@@ -39,19 +40,13 @@ bool scoutfs_seg_fits_single(u32 nr_items, u32 key_bytes, u32 val_bytes);
|
||||
bool scoutfs_seg_append_item(struct super_block *sb, struct scoutfs_segment *seg,
|
||||
struct scoutfs_key_buf *key, struct kvec *val,
|
||||
u8 flags, __le32 **links);
|
||||
int scoutfs_seg_manifest_add(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level);
|
||||
int scoutfs_seg_manifest_del(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level);
|
||||
void scoutfs_seg_init_ment(struct scoutfs_manifest_entry *ment, int level,
|
||||
struct scoutfs_segment *seg);
|
||||
|
||||
int scoutfs_seg_submit_write(struct super_block *sb,
|
||||
struct scoutfs_segment *seg,
|
||||
struct scoutfs_bio_completion *comp);
|
||||
|
||||
struct scoutfs_manifest_entry *
|
||||
scoutfs_seg_manifest_entry(struct super_block *sb,
|
||||
struct scoutfs_segment *seg, u8 level);
|
||||
|
||||
int scoutfs_seg_setup(struct super_block *sb);
|
||||
void scoutfs_seg_destroy(struct super_block *sb);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user