mirror of
https://github.com/versity/scoutfs.git
synced 2026-06-08 12:42:35 +00:00
scoutfs: use full extents for data and alloc
Previously we'd avoided full extents in file data mapping items because we were deleting items from forest btrees directly. That created deletion items for every version of file extents as they were modified. Now we have the item cache which can remove deleted items from memory when deletion items aren't necessary. By layering file data extents on an extent layer, we can also transition allocators to use extents and fix a lot of problems in the radix block allocator. Most of this change is churn from changing allocator function and struct names. File data extents no longer have to manage loading and storing from and to packed extent items at a fixed granularity. All those loops are torn out and data operations now call the extent layer with their callbacks instead of calling its packed item extent functions. This now means that fallocate and especially restoring offline extents can use larger extents. Small file block allocation now comes from a cached extent which reduces item calls for small file data streaming writes. The big change in the server is to use more root structures to manage recursive modification instead of relying on the allocator to notice and do the right thing. The radix allocator tried to notice when it was actively operating on a root that it was also using to allocate and free metadata blocks. This resulted in a lot of bugs. Instead we now double buffer the server's avail and freed roots so that the server fills and drains the stable roots from the previous transaction. We also double buffer the core fs metadata avail root so that we can increase the time to reuse freed metadata blocks. The server now only moves free extents into client allocators when they fall below a low threshold. This reduces the shared modification of the client's allocator roots which requires cold block reads on both the client and server. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -53,9 +53,10 @@
|
||||
|
||||
/*
|
||||
* Each of the server meta_alloc roots will try to keep a minimum amount
|
||||
* of free blocks. The server will use the next root once its current
|
||||
* root gets this low. It must have room for all the largest allocation
|
||||
* attempted in a transaction on the server.
|
||||
* of free blocks. The server will swap roots when its current avail
|
||||
* falls below the threshold while the freed root is still above it. It
|
||||
* must have room for all the largest allocation attempted in a
|
||||
* transaction on the server.
|
||||
*/
|
||||
#define SCOUTFS_SERVER_META_ALLOC_MIN \
|
||||
(SCOUTFS_SERVER_META_FILL_TARGET * 2)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "options.h"
|
||||
#include "msg.h"
|
||||
#include "block.h"
|
||||
#include "radix.h"
|
||||
#include "alloc.h"
|
||||
#include "avl.h"
|
||||
#include "hash.h"
|
||||
|
||||
@@ -674,7 +674,7 @@ static void move_items(struct scoutfs_btree_block *dst,
|
||||
* error.
|
||||
*/
|
||||
static int get_ref_block(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri, int flags,
|
||||
struct scoutfs_btree_ref *ref,
|
||||
struct scoutfs_block **bl_ret)
|
||||
@@ -737,7 +737,7 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_radix_alloc(sb, alloc, wri, &blkno);
|
||||
ret = scoutfs_alloc_meta(sb, alloc, wri, &blkno);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -745,8 +745,8 @@ retry:
|
||||
|
||||
new_bl = scoutfs_block_create(sb, blkno);
|
||||
if (IS_ERR(new_bl)) {
|
||||
ret = scoutfs_radix_free(sb, alloc, wri, blkno);
|
||||
BUG_ON(ret); /* radix should have been dirty */
|
||||
ret = scoutfs_free_meta(sb, alloc, wri, blkno);
|
||||
BUG_ON(ret);
|
||||
ret = PTR_ERR(new_bl);
|
||||
goto out;
|
||||
}
|
||||
@@ -754,11 +754,11 @@ retry:
|
||||
|
||||
/* free old stable blkno we're about to overwrite */
|
||||
if (ref && ref->blkno) {
|
||||
ret = scoutfs_radix_free(sb, alloc, wri,
|
||||
le64_to_cpu(ref->blkno));
|
||||
ret = scoutfs_free_meta(sb, alloc, wri,
|
||||
le64_to_cpu(ref->blkno));
|
||||
if (ret) {
|
||||
ret = scoutfs_radix_free(sb, alloc, wri, blkno);
|
||||
BUG_ON(ret); /* radix should have been dirty */
|
||||
ret = scoutfs_free_meta(sb, alloc, wri, blkno);
|
||||
BUG_ON(ret);
|
||||
scoutfs_block_put(sb, new_bl);
|
||||
new_bl = NULL;
|
||||
goto out;
|
||||
@@ -861,7 +861,7 @@ static void init_btree_block(struct scoutfs_btree_block *bt, int level)
|
||||
* Returns -errno, 0 if nothing done, or 1 if we split.
|
||||
*/
|
||||
static int try_split(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key, unsigned val_len,
|
||||
@@ -901,8 +901,8 @@ static int try_split(struct super_block *sb,
|
||||
if (!parent) {
|
||||
ret = get_ref_block(sb, alloc, wri, BTW_ALLOC, NULL, &par_bl);
|
||||
if (ret) {
|
||||
err = scoutfs_radix_free(sb, alloc, wri,
|
||||
le64_to_cpu(left->hdr.blkno));
|
||||
err = scoutfs_free_meta(sb, alloc, wri,
|
||||
le64_to_cpu(left->hdr.blkno));
|
||||
BUG_ON(err); /* radix should have been dirty */
|
||||
scoutfs_block_put(sb, left_bl);
|
||||
return ret;
|
||||
@@ -937,7 +937,7 @@ static int try_split(struct super_block *sb,
|
||||
* block.
|
||||
*/
|
||||
static int try_join(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_btree_block *parent,
|
||||
@@ -990,9 +990,9 @@ static int try_join(struct super_block *sb,
|
||||
/* update or delete sibling's parent item */
|
||||
if (le16_to_cpu(sib->nr_items) == 0) {
|
||||
delete_item(parent, sib_par_item, NULL);
|
||||
ret = scoutfs_radix_free(sb, alloc, wri,
|
||||
le64_to_cpu(sib->hdr.blkno));
|
||||
BUG_ON(ret); /* could have dirtied alloc to avoid error */
|
||||
ret = scoutfs_free_meta(sb, alloc, wri,
|
||||
le64_to_cpu(sib->hdr.blkno));
|
||||
BUG_ON(ret);
|
||||
|
||||
} else if (move_right) {
|
||||
update_parent_item(parent, sib_par_item, sib);
|
||||
@@ -1003,9 +1003,9 @@ static int try_join(struct super_block *sb,
|
||||
root->height--;
|
||||
root->ref.blkno = bt->hdr.blkno;
|
||||
root->ref.seq = bt->hdr.seq;
|
||||
ret = scoutfs_radix_free(sb, alloc, wri,
|
||||
le64_to_cpu(parent->hdr.blkno));
|
||||
BUG_ON(ret); /* could have dirtied alloc to avoid error */
|
||||
ret = scoutfs_free_meta(sb, alloc, wri,
|
||||
le64_to_cpu(parent->hdr.blkno));
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
scoutfs_block_put(sb, sib_bl);
|
||||
@@ -1219,7 +1219,7 @@ struct btree_walk_key_range {
|
||||
* blocks themselves.
|
||||
*/
|
||||
static int btree_walk(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
int flags, struct scoutfs_key *key,
|
||||
@@ -1464,7 +1464,7 @@ static bool invalid_item(unsigned val_len)
|
||||
* length value.
|
||||
*/
|
||||
int scoutfs_btree_insert(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
@@ -1531,7 +1531,7 @@ static void update_item_value(struct scoutfs_btree_block *bt,
|
||||
* which doesn't fit.
|
||||
*/
|
||||
int scoutfs_btree_update(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
@@ -1571,7 +1571,7 @@ int scoutfs_btree_update(struct super_block *sb,
|
||||
* which will insert instead of returning -ENOENT.
|
||||
*/
|
||||
int scoutfs_btree_force(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
@@ -1615,7 +1615,7 @@ int scoutfs_btree_force(struct super_block *sb,
|
||||
* found.
|
||||
*/
|
||||
int scoutfs_btree_delete(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key)
|
||||
@@ -1636,8 +1636,8 @@ int scoutfs_btree_delete(struct super_block *sb,
|
||||
if (item) {
|
||||
if (le16_to_cpu(bt->nr_items) == 1) {
|
||||
/* remove final empty block */
|
||||
ret = scoutfs_radix_free(sb, alloc, wri,
|
||||
bl->blkno);
|
||||
ret = scoutfs_free_meta(sb, alloc, wri,
|
||||
bl->blkno);
|
||||
if (ret == 0) {
|
||||
root->height = 0;
|
||||
root->ref.blkno = 0;
|
||||
@@ -1753,7 +1753,7 @@ int scoutfs_btree_prev(struct super_block *sb, struct scoutfs_btree_root *root,
|
||||
* <0 is returned on error, including -ENOENT if the key isn't present.
|
||||
*/
|
||||
int scoutfs_btree_dirty(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key)
|
||||
@@ -1841,7 +1841,7 @@ out:
|
||||
* the caller to resolve this.
|
||||
*/
|
||||
int scoutfs_btree_insert_list(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_btree_item_list *lst)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <linux/uio.h>
|
||||
|
||||
struct scoutfs_radix_allocator;
|
||||
struct scoutfs_alloc;
|
||||
struct scoutfs_block_writer;
|
||||
struct scoutfs_block;
|
||||
|
||||
@@ -36,25 +36,25 @@ int scoutfs_btree_lookup(struct super_block *sb,
|
||||
struct scoutfs_key *key,
|
||||
struct scoutfs_btree_item_ref *iref);
|
||||
int scoutfs_btree_insert(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
void *val, unsigned val_len);
|
||||
int scoutfs_btree_update(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
void *val, unsigned val_len);
|
||||
int scoutfs_btree_force(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
void *val, unsigned val_len);
|
||||
int scoutfs_btree_delete(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key);
|
||||
@@ -65,7 +65,7 @@ int scoutfs_btree_prev(struct super_block *sb, struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key,
|
||||
struct scoutfs_btree_item_ref *iref);
|
||||
int scoutfs_btree_dirty(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_key *key);
|
||||
@@ -77,7 +77,7 @@ int scoutfs_btree_read_items(struct super_block *sb,
|
||||
struct scoutfs_key *end,
|
||||
scoutfs_btree_item_cb cb, void *arg);
|
||||
int scoutfs_btree_insert_list(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_btree_item_list *lst);
|
||||
|
||||
@@ -166,7 +166,6 @@
|
||||
EXPAND_COUNTER(radix_undo_ref) \
|
||||
EXPAND_COUNTER(radix_walk) \
|
||||
EXPAND_COUNTER(server_commit_hold) \
|
||||
EXPAND_COUNTER(server_commit_prepare) \
|
||||
EXPAND_COUNTER(server_commit_queue) \
|
||||
EXPAND_COUNTER(server_commit_worker) \
|
||||
EXPAND_COUNTER(srch_add_entry) \
|
||||
@@ -188,8 +187,9 @@
|
||||
EXPAND_COUNTER(srch_search_xattrs) \
|
||||
EXPAND_COUNTER(srch_read_stale) \
|
||||
EXPAND_COUNTER(trans_commit_data_alloc_low) \
|
||||
EXPAND_COUNTER(trans_commit_dirty_meta_full) \
|
||||
EXPAND_COUNTER(trans_commit_fsync) \
|
||||
EXPAND_COUNTER(trans_commit_full) \
|
||||
EXPAND_COUNTER(trans_commit_meta_alloc_low) \
|
||||
EXPAND_COUNTER(trans_commit_sync_fs) \
|
||||
EXPAND_COUNTER(trans_commit_timer) \
|
||||
EXPAND_COUNTER(trans_commit_written)
|
||||
|
||||
1380
kmod/src/data.c
1380
kmod/src/data.c
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ struct scoutfs_traced_extent {
|
||||
|
||||
extern const struct address_space_operations scoutfs_file_aops;
|
||||
extern const struct file_operations scoutfs_file_fops;
|
||||
struct scoutfs_radix_allocator;
|
||||
struct scoutfs_alloc;
|
||||
struct scoutfs_block_writer;
|
||||
|
||||
int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode,
|
||||
@@ -77,11 +77,12 @@ int scoutfs_data_waiting(struct super_block *sb, u64 ino, u64 iblock,
|
||||
unsigned int nr);
|
||||
|
||||
void scoutfs_data_init_btrees(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_log_trees *lt);
|
||||
void scoutfs_data_get_btrees(struct super_block *sb,
|
||||
struct scoutfs_log_trees *lt);
|
||||
int scoutfs_data_prepare_commit(struct super_block *sb);
|
||||
u64 scoutfs_data_alloc_free_bytes(struct super_block *sb);
|
||||
|
||||
int scoutfs_data_setup(struct super_block *sb);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "lock.h"
|
||||
#include "btree.h"
|
||||
#include "client.h"
|
||||
#include "radix.h"
|
||||
#include "alloc.h"
|
||||
#include "block.h"
|
||||
#include "forest.h"
|
||||
#include "hash.h"
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
struct forest_info {
|
||||
struct mutex mutex;
|
||||
struct scoutfs_radix_allocator *alloc;
|
||||
struct scoutfs_alloc *alloc;
|
||||
struct scoutfs_block_writer *wri;
|
||||
struct scoutfs_log_trees our_log;
|
||||
|
||||
@@ -421,22 +421,22 @@ int scoutfs_forest_set_bloom_bits(struct super_block *sb,
|
||||
|
||||
if (!ref->blkno || !scoutfs_block_writer_is_dirty(sb, bl)) {
|
||||
|
||||
ret = scoutfs_radix_alloc(sb, finf->alloc, finf->wri, &blkno);
|
||||
ret = scoutfs_alloc_meta(sb, finf->alloc, finf->wri, &blkno);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
new_bl = scoutfs_block_create(sb, blkno);
|
||||
if (IS_ERR(new_bl)) {
|
||||
err = scoutfs_radix_free(sb, finf->alloc, finf->wri,
|
||||
blkno);
|
||||
err = scoutfs_free_meta(sb, finf->alloc, finf->wri,
|
||||
blkno);
|
||||
BUG_ON(err); /* could have dirtied */
|
||||
ret = PTR_ERR(new_bl);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (bl) {
|
||||
err = scoutfs_radix_free(sb, finf->alloc, finf->wri,
|
||||
le64_to_cpu(ref->blkno));
|
||||
err = scoutfs_free_meta(sb, finf->alloc, finf->wri,
|
||||
le64_to_cpu(ref->blkno));
|
||||
BUG_ON(err); /* could have dirtied */
|
||||
memcpy(new_bl->data, bl->data, SCOUTFS_BLOCK_LG_SIZE);
|
||||
} else {
|
||||
@@ -517,7 +517,7 @@ int scoutfs_forest_srch_add(struct super_block *sb, u64 hash, u64 ino, u64 id)
|
||||
* serialized with all writers.
|
||||
*/
|
||||
void scoutfs_forest_init_btrees(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_log_trees *lt)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef _SCOUTFS_FOREST_H_
|
||||
#define _SCOUTFS_FOREST_H_
|
||||
|
||||
struct scoutfs_radix_allocator;
|
||||
struct scoutfs_alloc;
|
||||
struct scoutfs_block_writer;
|
||||
struct scoutfs_block;
|
||||
|
||||
@@ -28,7 +28,7 @@ int scoutfs_forest_insert_list(struct super_block *sb,
|
||||
int scoutfs_forest_srch_add(struct super_block *sb, u64 hash, u64 ino, u64 id);
|
||||
|
||||
void scoutfs_forest_init_btrees(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_log_trees *lt);
|
||||
void scoutfs_forest_get_btrees(struct super_block *sb,
|
||||
|
||||
@@ -144,10 +144,10 @@ struct scoutfs_key {
|
||||
#define sks_ino _sk_first
|
||||
#define sks_nr _sk_second
|
||||
|
||||
/* packed extents */
|
||||
#define skpe_ino _sk_first
|
||||
#define skpe_base _sk_second
|
||||
#define skpe_part _sk_fourth
|
||||
/* data extents */
|
||||
#define skdx_ino _sk_first
|
||||
#define skdx_end _sk_second
|
||||
#define skdx_len _sk_third
|
||||
|
||||
/* log trees */
|
||||
#define sklt_rid _sk_first
|
||||
@@ -163,6 +163,13 @@ struct scoutfs_key {
|
||||
/* mounted clients */
|
||||
#define skmc_rid _sk_first
|
||||
|
||||
/* free extents by blkno */
|
||||
#define skfb_end _sk_second
|
||||
#define skfb_len _sk_third
|
||||
/* free extents by len */
|
||||
#define skfl_neglen _sk_second
|
||||
#define skfl_blkno _sk_third
|
||||
|
||||
struct scoutfs_radix_block {
|
||||
struct scoutfs_block_header hdr;
|
||||
union {
|
||||
@@ -386,8 +393,8 @@ struct scoutfs_srch_block {
|
||||
#define SCOUTFS_SRCH_COMPACT_NR (1 << SCOUTFS_SRCH_COMPACT_ORDER)
|
||||
|
||||
struct scoutfs_srch_compact_input {
|
||||
struct scoutfs_radix_root meta_avail;
|
||||
struct scoutfs_radix_root meta_freed;
|
||||
struct scoutfs_alloc_list_head meta_avail;
|
||||
struct scoutfs_alloc_list_head meta_freed;
|
||||
__le64 id;
|
||||
__u8 nr;
|
||||
__u8 flags;
|
||||
@@ -395,8 +402,8 @@ struct scoutfs_srch_compact_input {
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_srch_compact_result {
|
||||
struct scoutfs_radix_root meta_avail;
|
||||
struct scoutfs_radix_root meta_freed;
|
||||
struct scoutfs_alloc_list_head meta_avail;
|
||||
struct scoutfs_alloc_list_head meta_freed;
|
||||
__le64 id;
|
||||
__u8 flags;
|
||||
struct scoutfs_srch_file sfl;
|
||||
@@ -413,24 +420,24 @@ struct scoutfs_srch_compact_result {
|
||||
* about item logs, it's about clients making changes to trees.
|
||||
*/
|
||||
struct scoutfs_log_trees {
|
||||
struct scoutfs_radix_root meta_avail;
|
||||
struct scoutfs_radix_root meta_freed;
|
||||
struct scoutfs_alloc_list_head meta_avail;
|
||||
struct scoutfs_alloc_list_head meta_freed;
|
||||
struct scoutfs_btree_root item_root;
|
||||
struct scoutfs_btree_ref bloom_ref;
|
||||
struct scoutfs_radix_root data_avail;
|
||||
struct scoutfs_radix_root data_freed;
|
||||
struct scoutfs_alloc_root data_avail;
|
||||
struct scoutfs_alloc_root data_freed;
|
||||
struct scoutfs_srch_file srch_file;
|
||||
__le64 rid;
|
||||
__le64 nr;
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_log_trees_val {
|
||||
struct scoutfs_radix_root meta_avail;
|
||||
struct scoutfs_radix_root meta_freed;
|
||||
struct scoutfs_alloc_list_head meta_avail;
|
||||
struct scoutfs_alloc_list_head meta_freed;
|
||||
struct scoutfs_btree_root item_root;
|
||||
struct scoutfs_btree_ref bloom_ref;
|
||||
struct scoutfs_radix_root data_avail;
|
||||
struct scoutfs_radix_root data_freed;
|
||||
struct scoutfs_alloc_root data_avail;
|
||||
struct scoutfs_alloc_root data_freed;
|
||||
struct scoutfs_srch_file srch_file;
|
||||
} __packed;
|
||||
|
||||
@@ -482,6 +489,7 @@ struct scoutfs_bloom_block {
|
||||
#define SCOUTFS_TRANS_SEQ_ZONE 8
|
||||
#define SCOUTFS_MOUNTED_CLIENT_ZONE 9
|
||||
#define SCOUTFS_SRCH_ZONE 10
|
||||
#define SCOUTFS_FREE_EXTENT_ZONE 11
|
||||
|
||||
/* inode index zone */
|
||||
#define SCOUTFS_INODE_INDEX_META_SEQ_TYPE 1
|
||||
@@ -498,7 +506,7 @@ struct scoutfs_bloom_block {
|
||||
#define SCOUTFS_READDIR_TYPE 4
|
||||
#define SCOUTFS_LINK_BACKREF_TYPE 5
|
||||
#define SCOUTFS_SYMLINK_TYPE 6
|
||||
#define SCOUTFS_PACKED_EXTENT_TYPE 7
|
||||
#define SCOUTFS_DATA_EXTENT_TYPE 7
|
||||
|
||||
/* lock zone, only ever found in lock ranges, never in persistent items */
|
||||
#define SCOUTFS_RENAME_TYPE 1
|
||||
@@ -508,6 +516,10 @@ struct scoutfs_bloom_block {
|
||||
#define SCOUTFS_SRCH_BLOCKS_TYPE 2
|
||||
#define SCOUTFS_SRCH_BUSY_TYPE 3
|
||||
|
||||
/* free extents in allocator btrees in client and server, by blkno or len */
|
||||
#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1
|
||||
#define SCOUTFS_FREE_EXTENT_LEN_TYPE 2
|
||||
|
||||
/*
|
||||
* The extents that map blocks in a fixed-size logical region of a file
|
||||
* are packed and stored in item values. The packed extents are
|
||||
@@ -539,6 +551,12 @@ struct scoutfs_packed_extent {
|
||||
#define SCOUTFS_PACKEXT_BASE_MASK (~((__u64)SCOUTFS_PACKEXT_BLOCKS - 1))
|
||||
#define SCOUTFS_PACKEXT_MAX_BYTES SCOUTFS_MAX_VAL_SIZE
|
||||
|
||||
/* file data extents have start and len in key */
|
||||
struct scoutfs_data_extent_val {
|
||||
__le64 blkno;
|
||||
__u8 flags;
|
||||
} __packed;
|
||||
|
||||
#define SEF_OFFLINE (1 << 0)
|
||||
#define SEF_UNWRITTEN (1 << 1)
|
||||
#define SEF_UNKNOWN (U8_MAX << 2)
|
||||
@@ -623,10 +641,10 @@ struct scoutfs_super_block {
|
||||
__le64 unmount_barrier;
|
||||
__u8 quorum_count;
|
||||
struct scoutfs_inet_addr server_addr;
|
||||
struct scoutfs_radix_root core_meta_avail;
|
||||
struct scoutfs_radix_root core_meta_freed;
|
||||
struct scoutfs_radix_root core_data_avail;
|
||||
struct scoutfs_radix_root core_data_freed;
|
||||
struct scoutfs_alloc_root meta_alloc[2];
|
||||
struct scoutfs_alloc_root data_alloc;
|
||||
struct scoutfs_alloc_list_head server_meta_avail[2];
|
||||
struct scoutfs_alloc_list_head server_meta_freed[2];
|
||||
struct scoutfs_btree_root fs_root;
|
||||
struct scoutfs_btree_root logs_root;
|
||||
struct scoutfs_btree_root lock_clients;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "tseq.h"
|
||||
#include "spbm.h"
|
||||
#include "block.h"
|
||||
#include "radix.h"
|
||||
#include "btree.h"
|
||||
#include "msg.h"
|
||||
#include "scoutfs_trace.h"
|
||||
@@ -87,7 +86,7 @@ struct lock_server_info {
|
||||
struct scoutfs_tseq_tree tseq_tree;
|
||||
struct dentry *tseq_dentry;
|
||||
|
||||
struct scoutfs_radix_allocator *alloc;
|
||||
struct scoutfs_alloc *alloc;
|
||||
struct scoutfs_block_writer *wri;
|
||||
};
|
||||
|
||||
@@ -956,7 +955,7 @@ static void lock_server_tseq_show(struct seq_file *m,
|
||||
* we time them out.
|
||||
*/
|
||||
int scoutfs_lock_server_setup(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
|
||||
@@ -12,7 +12,7 @@ int scoutfs_lock_server_response(struct super_block *sb, u64 rid,
|
||||
int scoutfs_lock_server_farewell(struct super_block *sb, u64 rid);
|
||||
|
||||
int scoutfs_lock_server_setup(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri);
|
||||
void scoutfs_lock_server_destroy(struct super_block *sb);
|
||||
|
||||
|
||||
@@ -170,35 +170,35 @@ TRACE_EVENT(scoutfs_data_fallocate,
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_data_fiemap,
|
||||
TP_PROTO(struct super_block *sb, __u64 off, int i, __u64 blkno),
|
||||
TP_PROTO(struct super_block *sb, __u64 start, __u64 len, int ret),
|
||||
|
||||
|
||||
TP_ARGS(sb, off, i, blkno),
|
||||
TP_ARGS(sb, start, len, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
__field(__u64, off)
|
||||
__field(int, i)
|
||||
__field(__u64, blkno)
|
||||
__field(__u64, start)
|
||||
__field(__u64, len)
|
||||
__field(int, ret)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->off = off;
|
||||
__entry->i = i;
|
||||
__entry->blkno = blkno;
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" blk_off %llu i %u blkno %llu", SCSB_TRACE_ARGS,
|
||||
__entry->off, __entry->i, __entry->blkno)
|
||||
TP_printk(SCSBF" start %llu len %llu ret %d", SCSB_TRACE_ARGS,
|
||||
__entry->start, __entry->len, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_get_block,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, __u64 iblock,
|
||||
int create, struct scoutfs_traced_extent *te,
|
||||
int create, struct scoutfs_extent *ext,
|
||||
int ret, __u64 blkno, size_t size),
|
||||
|
||||
TP_ARGS(sb, ino, iblock, create, te, ret, blkno, size),
|
||||
TP_ARGS(sb, ino, iblock, create, ext, ret, blkno, size),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
@@ -216,7 +216,7 @@ TRACE_EVENT(scoutfs_get_block,
|
||||
__entry->ino = ino;
|
||||
__entry->iblock = iblock;
|
||||
__entry->create = create;
|
||||
STE_ASSIGN(ext, te)
|
||||
STE_ASSIGN(ext, ext)
|
||||
__entry->ret = ret;
|
||||
__entry->blkno = blkno;
|
||||
__entry->size = size;
|
||||
@@ -228,11 +228,35 @@ TRACE_EVENT(scoutfs_get_block,
|
||||
__entry->blkno, __entry->size)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_data_file_extent_class,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TRACE_EVENT(scoutfs_data_alloc_block_enter,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, __u64 iblock,
|
||||
struct scoutfs_extent *ext),
|
||||
|
||||
TP_ARGS(sb, ino, te),
|
||||
TP_ARGS(sb, ino, iblock, ext),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
__field(__u64, ino)
|
||||
__field(__u64, iblock)
|
||||
STE_FIELDS(ext)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->ino = ino;
|
||||
__entry->iblock = iblock;
|
||||
STE_ASSIGN(ext, ext)
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" ino %llu iblock %llu ext "STE_FMT,
|
||||
SCSB_TRACE_ARGS, __entry->ino, __entry->iblock,
|
||||
STE_ENTRY_ARGS(ext))
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(scoutfs_data_file_extent_class,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
|
||||
TP_ARGS(sb, ino, ext),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
@@ -243,36 +267,35 @@ TRACE_EVENT(scoutfs_data_file_extent_class,
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->ino = ino;
|
||||
STE_ASSIGN(ext, te)
|
||||
STE_ASSIGN(ext, ext)
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" ino %llu ext "STE_FMT,
|
||||
SCSB_TRACE_ARGS, __entry->ino, STE_ENTRY_ARGS(ext))
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_alloc_block,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TP_ARGS(sb, ino, te)
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_alloc,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_convert_unwritten,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TP_ARGS(sb, ino, te)
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_prealloc,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_prealloc_unwritten,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TP_ARGS(sb, ino, te)
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_get_block_found,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_get_block_mapped,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_extent_truncated,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TP_ARGS(sb, ino, te)
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
DEFINE_EVENT(scoutfs_data_file_extent_class, scoutfs_data_fiemap_extent,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino,
|
||||
struct scoutfs_traced_extent *te),
|
||||
TP_ARGS(sb, ino, te)
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, struct scoutfs_extent *ext),
|
||||
TP_ARGS(sb, ino, ext)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_data_truncate_items,
|
||||
@@ -300,9 +323,9 @@ TRACE_EVENT(scoutfs_data_truncate_items,
|
||||
|
||||
TRACE_EVENT(scoutfs_data_wait_check,
|
||||
TP_PROTO(struct super_block *sb, __u64 ino, __u64 pos, __u64 len,
|
||||
__u8 sef, __u8 op, struct scoutfs_traced_extent *te, int ret),
|
||||
__u8 sef, __u8 op, struct scoutfs_extent *ext, int ret),
|
||||
|
||||
TP_ARGS(sb, ino, pos, len, sef, op, te, ret),
|
||||
TP_ARGS(sb, ino, pos, len, sef, op, ext, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
@@ -322,7 +345,7 @@ TRACE_EVENT(scoutfs_data_wait_check,
|
||||
__entry->len = len;
|
||||
__entry->sef = sef;
|
||||
__entry->op = op;
|
||||
STE_ASSIGN(ext, te)
|
||||
STE_ASSIGN(ext, ext)
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "counters.h"
|
||||
#include "inode.h"
|
||||
#include "block.h"
|
||||
#include "radix.h"
|
||||
#include "btree.h"
|
||||
#include "scoutfs_trace.h"
|
||||
#include "msg.h"
|
||||
@@ -37,6 +36,7 @@
|
||||
#include "quorum.h"
|
||||
#include "trans.h"
|
||||
#include "srch.h"
|
||||
#include "alloc.h"
|
||||
|
||||
/*
|
||||
* Every active mount can act as the server that listens on a net
|
||||
@@ -66,13 +66,10 @@ struct server_info {
|
||||
struct rw_semaphore commit_rwsem;
|
||||
struct llist_head commit_waiters;
|
||||
struct work_struct commit_work;
|
||||
bool prepared_commit;
|
||||
|
||||
/* server tracks seq use */
|
||||
struct rw_semaphore seq_rwsem;
|
||||
|
||||
struct rw_semaphore alloc_rwsem;
|
||||
|
||||
struct list_head clients;
|
||||
unsigned long nr_clients;
|
||||
|
||||
@@ -81,7 +78,15 @@ struct server_info {
|
||||
struct list_head farewell_requests;
|
||||
struct work_struct farewell_work;
|
||||
|
||||
struct scoutfs_radix_allocator alloc;
|
||||
struct mutex alloc_mutex;
|
||||
/* swap between two fs meta roots to increase time to reuse */
|
||||
struct scoutfs_alloc_root *meta_avail;
|
||||
struct scoutfs_alloc_root *meta_freed;
|
||||
/* server's meta allocators alternate between persistent heads */
|
||||
struct scoutfs_alloc alloc;
|
||||
int other_ind;
|
||||
struct scoutfs_alloc_list_head *other_avail;
|
||||
struct scoutfs_alloc_list_head *other_freed;
|
||||
struct scoutfs_block_writer wri;
|
||||
|
||||
struct mutex logs_mutex;
|
||||
@@ -119,15 +124,7 @@ static void stop_server(struct server_info *server)
|
||||
/*
|
||||
* Hold the shared rwsem that lets multiple holders modify blocks in the
|
||||
* current commit and prevents the commit worker from acquiring the
|
||||
* exclusive write lock to write the commit. This can fail for the
|
||||
* first holder failing to prepare a new commit.
|
||||
*
|
||||
* We reclaim the server's stable meta_freed blocks. This is run before
|
||||
* anything has modified allocators in the server. We know that the
|
||||
* stable meta_freed tree in the super contains all the stable free
|
||||
* blocks which can be merged back into avail. We reference the stable
|
||||
* freed tree in the super because the server allocator's freed tree is
|
||||
* going to be added to as blocks are freed during the merge.
|
||||
* exclusive write lock to write the commit.
|
||||
*
|
||||
* This is exported for server components isolated in their own files
|
||||
* (lock_server) and which are not called directly by the server core
|
||||
@@ -135,43 +132,13 @@ static void stop_server(struct server_info *server)
|
||||
*/
|
||||
int scoutfs_server_hold_commit(struct super_block *sb)
|
||||
{
|
||||
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
u64 tot;
|
||||
int ret = 0;
|
||||
|
||||
scoutfs_inc_counter(sb, server_commit_hold);
|
||||
|
||||
down_read(&server->commit_rwsem);
|
||||
|
||||
while (!server->prepared_commit) {
|
||||
up_read(&server->commit_rwsem);
|
||||
down_write(&server->commit_rwsem);
|
||||
|
||||
if (!server->prepared_commit) {
|
||||
scoutfs_inc_counter(sb, server_commit_prepare);
|
||||
BUG_ON(scoutfs_block_writer_dirty_bytes(sb,
|
||||
&server->wri));
|
||||
tot = le64_to_cpu(super->core_meta_freed.ref.sm_total);
|
||||
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc,
|
||||
&server->wri,
|
||||
&server->alloc.avail,
|
||||
&server->alloc.freed,
|
||||
&super->core_meta_freed,
|
||||
true, tot);
|
||||
if (ret == 0)
|
||||
server->prepared_commit = true;
|
||||
}
|
||||
|
||||
up_write(&server->commit_rwsem);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
down_read(&server->commit_rwsem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -214,18 +181,6 @@ int scoutfs_server_apply_commit(struct super_block *sb, int err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller is about to overwrite a ref to an alloc tree. As we do
|
||||
* so we update the given super free block counter with the difference
|
||||
* between the old and new allocator roots.
|
||||
*/
|
||||
static void update_free_blocks(__le64 *blocks, struct scoutfs_radix_root *prev,
|
||||
struct scoutfs_radix_root *next)
|
||||
{
|
||||
le64_add_cpu(blocks, le64_to_cpu(next->ref.sm_total) -
|
||||
le64_to_cpu(prev->ref.sm_total));
|
||||
}
|
||||
|
||||
void scoutfs_server_get_roots(struct super_block *sb,
|
||||
struct scoutfs_net_roots *roots)
|
||||
{
|
||||
@@ -286,6 +241,31 @@ static void scoutfs_server_commit_func(struct work_struct *work)
|
||||
|
||||
down_write(&server->commit_rwsem);
|
||||
|
||||
/* make sure next avail has sufficient blocks */
|
||||
ret = scoutfs_alloc_fill_list(sb, &server->alloc, &server->wri,
|
||||
server->other_avail,
|
||||
server->meta_avail,
|
||||
SCOUTFS_SERVER_META_FILL_LO,
|
||||
SCOUTFS_SERVER_META_FILL_TARGET);
|
||||
if (ret) {
|
||||
scoutfs_err(sb, "server error refilling avail: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* merge freed blocks into extents, might be partial */
|
||||
ret = scoutfs_alloc_empty_list(sb, &server->alloc, &server->wri,
|
||||
server->meta_freed,
|
||||
server->other_freed);
|
||||
if (ret) {
|
||||
scoutfs_err(sb, "server error emptying freed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_alloc_prepare_commit(sb, &server->alloc, &server->wri);
|
||||
if (ret < 0) {
|
||||
scoutfs_err(sb, "server error prepare alloc commit: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_block_writer_write(sb, &server->wri);
|
||||
if (ret) {
|
||||
@@ -293,13 +273,8 @@ static void scoutfs_server_commit_func(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
update_free_blocks(&super->free_meta_blocks, &super->core_meta_avail,
|
||||
&server->alloc.avail);
|
||||
update_free_blocks(&super->free_meta_blocks, &super->core_meta_freed,
|
||||
&server->alloc.freed);
|
||||
|
||||
super->core_meta_avail = server->alloc.avail;
|
||||
super->core_meta_freed = server->alloc.freed;
|
||||
super->server_meta_avail[server->other_ind ^ 1] = server->alloc.avail;
|
||||
super->server_meta_freed[server->other_ind ^ 1] = server->alloc.freed;
|
||||
|
||||
ret = scoutfs_write_super(sb, super);
|
||||
if (ret) {
|
||||
@@ -307,9 +282,23 @@ static void scoutfs_server_commit_func(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
server->prepared_commit = false;
|
||||
set_roots(server, &super->fs_root, &super->logs_root,
|
||||
&super->srch_root);
|
||||
|
||||
/* swizzle the active and idle server alloc/freed heads */
|
||||
server->other_ind ^= 1;
|
||||
server->alloc.avail = super->server_meta_avail[server->other_ind ^ 1];
|
||||
server->alloc.freed = super->server_meta_freed[server->other_ind ^ 1];
|
||||
server->other_avail = &super->server_meta_avail[server->other_ind];
|
||||
server->other_freed = &super->server_meta_freed[server->other_ind];
|
||||
|
||||
/* swap avail/free if avail gets low and freed is high */
|
||||
if (le64_to_cpu(server->meta_avail->total_len) <=
|
||||
SCOUTFS_SERVER_META_ALLOC_MIN &&
|
||||
le64_to_cpu(server->meta_freed->total_len) >
|
||||
SCOUTFS_SERVER_META_ALLOC_MIN)
|
||||
swap(server->meta_avail, server->meta_freed);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
node = llist_del_all(&server->commit_waiters);
|
||||
@@ -362,6 +351,34 @@ out:
|
||||
return scoutfs_net_response(sb, conn, cmd, id, ret, &ial, sizeof(ial));
|
||||
}
|
||||
|
||||
/*
|
||||
* Refill the destination root if it's fallen below the lo threshold by
|
||||
* moving from the src root to bring it up to the target.
|
||||
*/
|
||||
static int alloc_move_refill(struct super_block *sb,
|
||||
struct scoutfs_alloc_root *dst,
|
||||
struct scoutfs_alloc_root *src, u64 lo, u64 target)
|
||||
{
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
|
||||
if (le64_to_cpu(dst->total_len) >= lo)
|
||||
return 0;
|
||||
|
||||
return scoutfs_alloc_move(sb, &server->alloc, &server->wri, dst, src,
|
||||
min(target - le64_to_cpu(dst->total_len),
|
||||
le64_to_cpu(src->total_len)));
|
||||
}
|
||||
|
||||
static int alloc_move_empty(struct super_block *sb,
|
||||
struct scoutfs_alloc_root *dst,
|
||||
struct scoutfs_alloc_root *src)
|
||||
{
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
|
||||
return scoutfs_alloc_move(sb, &server->alloc, &server->wri,
|
||||
dst, src, le64_to_cpu(src->total_len));
|
||||
}
|
||||
|
||||
/*
|
||||
* Give the client roots to all the trees that they'll use to build
|
||||
* their transaction.
|
||||
@@ -383,8 +400,6 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
struct scoutfs_log_trees_val ltv;
|
||||
struct scoutfs_log_trees lt;
|
||||
struct scoutfs_key key;
|
||||
u64 count;
|
||||
u64 target;
|
||||
int ret;
|
||||
|
||||
if (arg_len != 0) {
|
||||
@@ -422,50 +437,25 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
key.sklt_rid = cpu_to_le64(rid);
|
||||
key.sklt_nr = cpu_to_le64(1);
|
||||
memset(<v, 0, sizeof(ltv));
|
||||
scoutfs_radix_root_init(sb, <v.meta_avail, true);
|
||||
scoutfs_radix_root_init(sb, <v.meta_freed, true);
|
||||
scoutfs_radix_root_init(sb, <v.data_avail, false);
|
||||
scoutfs_radix_root_init(sb, <v.data_freed, false);
|
||||
}
|
||||
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.avail,
|
||||
<v.meta_freed, <v.meta_freed, true,
|
||||
le64_to_cpu(ltv.meta_freed.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&super->core_data_avail,
|
||||
<v.data_freed, <v.data_freed, false,
|
||||
le64_to_cpu(ltv.data_freed.ref.sm_total));
|
||||
/* return freed to server for emptying, refill avail */
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
ret = scoutfs_alloc_splice_list(sb, &server->alloc, &server->wri,
|
||||
server->other_freed,
|
||||
<v.meta_freed) ?:
|
||||
alloc_move_empty(sb, &super->data_alloc, <v.data_freed) ?:
|
||||
scoutfs_alloc_fill_list(sb, &server->alloc, &server->wri,
|
||||
<v.meta_avail, server->meta_avail,
|
||||
SCOUTFS_SERVER_META_FILL_LO,
|
||||
SCOUTFS_SERVER_META_FILL_TARGET) ?:
|
||||
alloc_move_refill(sb, <v.data_avail, &super->data_alloc,
|
||||
SCOUTFS_SERVER_DATA_FILL_LO,
|
||||
SCOUTFS_SERVER_DATA_FILL_TARGET);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
/* ensure client has enough free metadata blocks for a transaction */
|
||||
target = (64*1024*1024) / SCOUTFS_BLOCK_LG_SIZE;
|
||||
if (le64_to_cpu(ltv.meta_avail.ref.sm_total) < target) {
|
||||
count = target - le64_to_cpu(ltv.meta_avail.ref.sm_total);
|
||||
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
<v.meta_avail,
|
||||
&server->alloc.avail,
|
||||
&server->alloc.avail, true, count);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* ensure client has enough free data blocks for a transaction */
|
||||
target = SCOUTFS_TRANS_DATA_ALLOC_HWM / SCOUTFS_BLOCK_SM_SIZE;
|
||||
if (le64_to_cpu(ltv.data_avail.ref.sm_total) < target) {
|
||||
count = target - le64_to_cpu(ltv.data_avail.ref.sm_total);
|
||||
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
<v.data_avail,
|
||||
&super->core_data_avail,
|
||||
&super->core_data_avail, false,
|
||||
count);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* update client's log tree's item */
|
||||
ret = scoutfs_btree_force(sb, &server->alloc, &server->wri,
|
||||
&super->logs_root, &key, <v, sizeof(ltv));
|
||||
@@ -553,21 +543,12 @@ static int server_commit_log_trees(struct super_block *sb,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
update_free_blocks(&super->free_meta_blocks, <v.meta_avail,
|
||||
<->meta_avail);
|
||||
update_free_blocks(&super->free_meta_blocks, <v.meta_freed,
|
||||
<->meta_freed);
|
||||
update_free_blocks(&super->free_data_blocks, <v.data_avail,
|
||||
<->data_avail);
|
||||
update_free_blocks(&super->free_data_blocks, <v.data_freed,
|
||||
<->data_freed);
|
||||
|
||||
ltv.meta_avail = lt->meta_avail;
|
||||
ltv.meta_freed = lt->meta_freed;
|
||||
ltv.item_root = lt->item_root;
|
||||
ltv.bloom_ref = lt->bloom_ref;
|
||||
ltv.data_avail = lt->data_avail;
|
||||
ltv.data_freed = lt->data_freed;
|
||||
ltv.item_root = lt->item_root;
|
||||
ltv.bloom_ref = lt->bloom_ref;
|
||||
ltv.srch_file = lt->srch_file;
|
||||
|
||||
ret = scoutfs_btree_update(sb, &server->alloc, &server->wri,
|
||||
@@ -638,7 +619,6 @@ static int reclaim_log_trees(struct super_block *sb, u64 rid)
|
||||
int err;
|
||||
|
||||
mutex_lock(&server->logs_mutex);
|
||||
down_write(&server->alloc_rwsem);
|
||||
|
||||
/* find the client's existing item */
|
||||
scoutfs_key_init_log_trees(&key, rid, 0);
|
||||
@@ -662,32 +642,25 @@ static int reclaim_log_trees(struct super_block *sb, u64 rid)
|
||||
|
||||
/*
|
||||
* All of these can return errors after having modified the
|
||||
* radix trees. We have to try and update the roots in the
|
||||
* allocator trees. We have to try and update the roots in the
|
||||
* log item.
|
||||
*/
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.avail,
|
||||
<v.meta_avail, <v.meta_avail, true,
|
||||
le64_to_cpu(ltv.meta_avail.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.avail,
|
||||
<v.meta_freed, <v.meta_freed, true,
|
||||
le64_to_cpu(ltv.meta_freed.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&super->core_data_avail,
|
||||
<v.data_avail, <v.data_avail, false,
|
||||
le64_to_cpu(ltv.data_avail.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&super->core_data_avail,
|
||||
<v.data_freed, <v.data_freed, false,
|
||||
le64_to_cpu(ltv.data_freed.ref.sm_total));
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
ret = scoutfs_alloc_splice_list(sb, &server->alloc, &server->wri,
|
||||
server->other_freed,
|
||||
<v.meta_freed) ?:
|
||||
scoutfs_alloc_splice_list(sb, &server->alloc, &server->wri,
|
||||
server->other_freed,
|
||||
<v.meta_avail) ?:
|
||||
alloc_move_empty(sb, &super->data_alloc, <v.data_avail) ?:
|
||||
alloc_move_empty(sb, &super->data_alloc, <v.data_freed);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
|
||||
err = scoutfs_btree_update(sb, &server->alloc, &server->wri,
|
||||
&super->logs_root, &key, <v, sizeof(ltv));
|
||||
BUG_ON(err != 0); /* alloc and log item roots out of sync */
|
||||
|
||||
out:
|
||||
up_write(&server->alloc_rwsem);
|
||||
mutex_unlock(&server->logs_mutex);
|
||||
|
||||
return ret;
|
||||
@@ -892,14 +865,14 @@ static int server_statfs(struct super_block *sb,
|
||||
nstatfs.next_ino = super->next_ino;
|
||||
spin_unlock(&sbi->next_ino_lock);
|
||||
|
||||
down_read(&server->alloc_rwsem);
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
nstatfs.total_blocks = le64_lg_to_sm(super->total_meta_blocks);
|
||||
le64_add_cpu(&nstatfs.total_blocks,
|
||||
le64_to_cpu(super->total_data_blocks));
|
||||
nstatfs.bfree = le64_lg_to_sm(super->free_meta_blocks);
|
||||
le64_add_cpu(&nstatfs.bfree,
|
||||
le64_to_cpu(super->free_data_blocks));
|
||||
up_read(&server->alloc_rwsem);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
@@ -1002,8 +975,6 @@ static int server_srch_get_compact(struct super_block *sb,
|
||||
int i;
|
||||
|
||||
memset(&scin, 0, sizeof(scin));
|
||||
scoutfs_radix_root_init(sb, &scin.meta_avail, true);
|
||||
scoutfs_radix_root_init(sb, &scin.meta_freed, true);
|
||||
|
||||
if (arg_len != 0) {
|
||||
ret = -EINVAL;
|
||||
@@ -1028,9 +999,11 @@ static int server_srch_get_compact(struct super_block *sb,
|
||||
for (i = 0; i < scin.nr; i++)
|
||||
blocks += le64_to_cpu(scin.sfl[i].blocks);
|
||||
blocks *= 3;
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&scin.meta_avail, &server->alloc.avail,
|
||||
&server->alloc.avail, true, blocks);
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
ret = scoutfs_alloc_fill_list(sb, &server->alloc, &server->wri,
|
||||
&scin.meta_avail, server->meta_avail,
|
||||
blocks, blocks);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
if (ret < 0)
|
||||
goto apply;
|
||||
|
||||
@@ -1047,6 +1020,12 @@ out:
|
||||
&scin, sizeof(scin));
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit the client's compaction. Their freed allocator contains the
|
||||
* source srch files blocks that are currently in use which can't be
|
||||
* available for allocation until after the commit. We move them into
|
||||
* freed so they won't satisfy allocations.
|
||||
*/
|
||||
static int server_srch_commit_compact(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn,
|
||||
u8 cmd, u64 id, void *arg, u16 arg_len)
|
||||
@@ -1056,8 +1035,8 @@ static int server_srch_commit_compact(struct super_block *sb,
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct scoutfs_super_block *super = &sbi->super;
|
||||
struct scoutfs_srch_compact_result *scres;
|
||||
struct scoutfs_radix_root av;
|
||||
struct scoutfs_radix_root fr;
|
||||
struct scoutfs_alloc_list_head av;
|
||||
struct scoutfs_alloc_list_head fr;
|
||||
int ret;
|
||||
|
||||
scres = arg;
|
||||
@@ -1078,15 +1057,12 @@ static int server_srch_commit_compact(struct super_block *sb,
|
||||
if (ret < 0) /* XXX very bad, leaks allocators */
|
||||
goto apply;
|
||||
|
||||
/* XXX like all merges, doesn't reclaim allocator blocks themselves */
|
||||
|
||||
/* merge the client's allocators into freed, commit before reuse */
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.freed, &av, &av, true,
|
||||
le64_to_cpu(av.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.freed, &fr, &fr, true,
|
||||
le64_to_cpu(fr.ref.sm_total));
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
ret = scoutfs_alloc_splice_list(sb, &server->alloc, &server->wri,
|
||||
server->other_freed, &av) ?:
|
||||
scoutfs_alloc_splice_list(sb, &server->alloc, &server->wri,
|
||||
server->other_freed, &fr);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
apply:
|
||||
ret = scoutfs_server_apply_commit(sb, ret);
|
||||
out:
|
||||
@@ -1149,14 +1125,15 @@ static int delete_mounted_client(struct super_block *sb, u64 rid)
|
||||
|
||||
/*
|
||||
* Remove all the busy items for srch compactions that the mount might
|
||||
* have been responsible for and reclaim all their allocators.
|
||||
* have been responsible for and reclaim all their allocators. The freed
|
||||
* allocator could still contain stable srch file blknos.
|
||||
*/
|
||||
static int cancel_srch_compact(struct super_block *sb, u64 rid)
|
||||
{
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super;
|
||||
struct scoutfs_radix_root av;
|
||||
struct scoutfs_radix_root fr;
|
||||
struct scoutfs_alloc_list_head av;
|
||||
struct scoutfs_alloc_list_head fr;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
@@ -1172,12 +1149,14 @@ static int cancel_srch_compact(struct super_block *sb, u64 rid)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.freed, &av, &av, true,
|
||||
le64_to_cpu(av.ref.sm_total)) ?:
|
||||
scoutfs_radix_merge(sb, &server->alloc, &server->wri,
|
||||
&server->alloc.freed, &fr, &fr, true,
|
||||
le64_to_cpu(fr.ref.sm_total));
|
||||
mutex_lock(&server->alloc_mutex);
|
||||
ret = scoutfs_alloc_splice_list(sb, &server->alloc,
|
||||
&server->wri,
|
||||
server->other_freed, &av) ?:
|
||||
scoutfs_alloc_splice_list(sb, &server->alloc,
|
||||
&server->wri,
|
||||
server->other_freed, &fr);
|
||||
mutex_unlock(&server->alloc_mutex);
|
||||
if (WARN_ON_ONCE(ret < 0))
|
||||
break;
|
||||
}
|
||||
@@ -1650,10 +1629,27 @@ static void scoutfs_server_worker(struct work_struct *work)
|
||||
|
||||
set_roots(server, &super->fs_root, &super->logs_root,
|
||||
&super->srch_root);
|
||||
scoutfs_radix_init_alloc(&server->alloc, &super->core_meta_avail,
|
||||
&super->core_meta_freed);
|
||||
scoutfs_block_writer_init(sb, &server->wri);
|
||||
|
||||
/* prepare server alloc for this transaction, larger first */
|
||||
if (le64_to_cpu(super->server_meta_avail[0].total_nr) <
|
||||
le64_to_cpu(super->server_meta_avail[1].total_nr))
|
||||
server->other_ind = 0;
|
||||
else
|
||||
server->other_ind = 1;
|
||||
scoutfs_alloc_init(&server->alloc,
|
||||
&super->server_meta_avail[server->other_ind ^ 1],
|
||||
&super->server_meta_freed[server->other_ind ^ 1]);
|
||||
server->other_avail = &super->server_meta_avail[server->other_ind];
|
||||
server->other_freed = &super->server_meta_freed[server->other_ind];
|
||||
|
||||
/* use largest meta_alloc to start */
|
||||
server->meta_avail = &super->meta_alloc[0];
|
||||
server->meta_freed = &super->meta_alloc[1];
|
||||
if (le64_to_cpu(server->meta_freed->total_len) >
|
||||
le64_to_cpu(server->meta_avail->total_len))
|
||||
swap(server->meta_avail, server->meta_freed);
|
||||
|
||||
ret = scoutfs_lock_server_setup(sb, &server->alloc, &server->wri);
|
||||
if (ret)
|
||||
goto shutdown;
|
||||
@@ -1783,11 +1779,11 @@ int scoutfs_server_setup(struct super_block *sb)
|
||||
init_llist_head(&server->commit_waiters);
|
||||
INIT_WORK(&server->commit_work, scoutfs_server_commit_func);
|
||||
init_rwsem(&server->seq_rwsem);
|
||||
init_rwsem(&server->alloc_rwsem);
|
||||
INIT_LIST_HEAD(&server->clients);
|
||||
mutex_init(&server->farewell_mutex);
|
||||
INIT_LIST_HEAD(&server->farewell_requests);
|
||||
INIT_WORK(&server->farewell_work, farewell_worker);
|
||||
mutex_init(&server->alloc_mutex);
|
||||
mutex_init(&server->logs_mutex);
|
||||
mutex_init(&server->srch_mutex);
|
||||
seqcount_init(&server->roots_seqcount);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "format.h"
|
||||
#include "counters.h"
|
||||
#include "block.h"
|
||||
#include "radix.h"
|
||||
#include "alloc.h"
|
||||
#include "srch.h"
|
||||
#include "btree.h"
|
||||
#include "spbm.h"
|
||||
@@ -309,7 +309,7 @@ enum {
|
||||
GFB_DIRTY = (1 << 1),
|
||||
};
|
||||
static int get_file_block(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl,
|
||||
int gfb, u64 blk, struct scoutfs_block **bl_ret)
|
||||
@@ -335,7 +335,7 @@ static int get_file_block(struct super_block *sb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_radix_alloc(sb, alloc, wri, &blkno);
|
||||
ret = scoutfs_alloc_meta(sb, alloc, wri, &blkno);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -383,7 +383,7 @@ static int get_file_block(struct super_block *sb,
|
||||
/* allocate a new block if we need it */
|
||||
if (!ref->blkno || ((gfb & GFB_DIRTY) &&
|
||||
!scoutfs_block_writer_is_dirty(sb, bl))) {
|
||||
ret = scoutfs_radix_alloc(sb, alloc, wri, &blkno);
|
||||
ret = scoutfs_alloc_meta(sb, alloc, wri, &blkno);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -395,8 +395,8 @@ static int get_file_block(struct super_block *sb,
|
||||
|
||||
if (bl) {
|
||||
/* cow old block if we have one */
|
||||
ret = scoutfs_radix_free(sb, alloc, wri,
|
||||
bl->blkno);
|
||||
ret = scoutfs_free_meta(sb, alloc, wri,
|
||||
bl->blkno);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -442,7 +442,7 @@ out:
|
||||
|
||||
/* return allocated blkno on error */
|
||||
if (blkno > 0) {
|
||||
err = scoutfs_radix_free(sb, alloc, wri, blkno);
|
||||
err = scoutfs_free_meta(sb, alloc, wri, blkno);
|
||||
BUG_ON(err); /* radix should have been dirty */
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ out:
|
||||
}
|
||||
|
||||
int scoutfs_srch_add(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl,
|
||||
struct scoutfs_block **bl_ret,
|
||||
@@ -988,7 +988,7 @@ out:
|
||||
* it's large enough.
|
||||
*/
|
||||
int scoutfs_srch_rotate_log(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_srch_file *sfl)
|
||||
@@ -1018,13 +1018,13 @@ int scoutfs_srch_rotate_log(struct super_block *sb,
|
||||
* items.
|
||||
*/
|
||||
int scoutfs_srch_get_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
u64 rid,
|
||||
struct scoutfs_srch_compact_input *scin)
|
||||
{
|
||||
struct scoutfs_srch_compact_input busy_scin = {{0,}};
|
||||
struct scoutfs_srch_compact_input busy_scin = {{{0,}}};
|
||||
struct scoutfs_srch_file sfl;
|
||||
SCOUTFS_BTREE_ITEM_REF(iref);
|
||||
struct scoutfs_spbm busy;
|
||||
@@ -1147,7 +1147,7 @@ out:
|
||||
* copy.
|
||||
*/
|
||||
int scoutfs_srch_update_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_srch_compact_input *scin)
|
||||
@@ -1160,7 +1160,7 @@ int scoutfs_srch_update_compact(struct super_block *sb,
|
||||
}
|
||||
|
||||
static int mod_srch_items(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u8 scom_flags,
|
||||
bool ins, struct scoutfs_srch_file *sfls, int nr)
|
||||
@@ -1213,12 +1213,12 @@ static int mod_srch_items(struct super_block *sb,
|
||||
* We give the caller the allocator trees to merge if we return success.
|
||||
*/
|
||||
int scoutfs_srch_commit_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_srch_compact_result *scres,
|
||||
struct scoutfs_radix_root *av,
|
||||
struct scoutfs_radix_root *fr)
|
||||
struct scoutfs_alloc_list_head *av,
|
||||
struct scoutfs_alloc_list_head *fr)
|
||||
{
|
||||
struct scoutfs_srch_compact_input scin;
|
||||
SCOUTFS_BTREE_ITEM_REF(iref);
|
||||
@@ -1268,11 +1268,11 @@ out:
|
||||
* allocators. Returns -ENOENT when there are no more items.
|
||||
*/
|
||||
int scoutfs_srch_cancel_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_radix_root *av,
|
||||
struct scoutfs_radix_root *fr)
|
||||
struct scoutfs_alloc_list_head *av,
|
||||
struct scoutfs_alloc_list_head *fr)
|
||||
{
|
||||
struct scoutfs_srch_compact_input scin;
|
||||
SCOUTFS_BTREE_ITEM_REF(iref);
|
||||
@@ -1331,7 +1331,7 @@ typedef int (*kway_next_func_t)(struct super_block *sb,
|
||||
struct scoutfs_srch_entry *sre_ret, void *arg);
|
||||
|
||||
static int kway_merge(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl,
|
||||
kway_next_func_t kway_next, void **args, int nr)
|
||||
@@ -1526,7 +1526,7 @@ static void swap_page_sre(void *A, void *B, int size)
|
||||
* typically, ~10x worst case).
|
||||
*/
|
||||
static int compact_logs(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl_out,
|
||||
struct scoutfs_srch_file *sfls, int nr_sfls)
|
||||
@@ -1715,7 +1715,7 @@ out:
|
||||
* which reads blocks and decodes entries.
|
||||
*/
|
||||
static int compact_sorted(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl_out,
|
||||
struct scoutfs_srch_file *sfls, int nr)
|
||||
@@ -1760,7 +1760,7 @@ out:
|
||||
* up our entire operation, partial state doesn't matter.
|
||||
*/
|
||||
static int free_file(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl)
|
||||
{
|
||||
@@ -1818,7 +1818,7 @@ static int free_file(struct super_block *sb,
|
||||
if (blkno == 0)
|
||||
continue;
|
||||
|
||||
ret = scoutfs_radix_free(sb, alloc, wri, blkno);
|
||||
ret = scoutfs_free_meta(sb, alloc, wri, blkno);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
scoutfs_inc_counter(sb, srch_compact_free_block);
|
||||
@@ -1830,7 +1830,7 @@ static int free_file(struct super_block *sb,
|
||||
}
|
||||
|
||||
free_root:
|
||||
ret = scoutfs_radix_free(sb, alloc, wri, le64_to_cpu(sfl->ref.blkno));
|
||||
ret = scoutfs_free_meta(sb, alloc, wri, le64_to_cpu(sfl->ref.blkno));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -1868,7 +1868,7 @@ static void scoutfs_srch_compact_worker(struct work_struct *work)
|
||||
struct srch_info *srinf = container_of(work, struct srch_info,
|
||||
compact_dwork.work);
|
||||
struct super_block *sb = srinf->sb;
|
||||
struct scoutfs_radix_allocator alloc;
|
||||
struct scoutfs_alloc alloc;
|
||||
struct scoutfs_srch_compact_result scres;
|
||||
struct scoutfs_srch_compact_input scin;
|
||||
struct scoutfs_block_writer wri;
|
||||
@@ -1883,7 +1883,7 @@ static void scoutfs_srch_compact_worker(struct work_struct *work)
|
||||
if (ret < 0 || scin.nr == 0)
|
||||
goto out;
|
||||
|
||||
scoutfs_radix_init_alloc(&alloc, &scin.meta_avail, &scin.meta_freed);
|
||||
scoutfs_alloc_init(&alloc, &scin.meta_avail, &scin.meta_freed);
|
||||
|
||||
if (scin.flags & SCOUTFS_SRCH_COMPACT_FLAG_LOG)
|
||||
ret = compact_logs(sb, &alloc, &wri, &scres.sfl,
|
||||
|
||||
@@ -22,7 +22,7 @@ struct scoutfs_srch_rb_node {
|
||||
node = rb_next(node))
|
||||
|
||||
int scoutfs_srch_add(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_srch_file *sfl,
|
||||
struct scoutfs_block **bl_ret,
|
||||
@@ -34,34 +34,34 @@ int scoutfs_srch_search_xattrs(struct super_block *sb,
|
||||
u64 hash, u64 ino, u64 last_ino, bool *done);
|
||||
|
||||
int scoutfs_srch_rotate_log(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
struct scoutfs_srch_file *sfl);
|
||||
int scoutfs_srch_get_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root,
|
||||
u64 rid,
|
||||
struct scoutfs_srch_compact_input *scin_ret);
|
||||
int scoutfs_srch_update_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_srch_compact_input *scin);
|
||||
int scoutfs_srch_commit_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_srch_compact_result *scres,
|
||||
struct scoutfs_radix_root *av,
|
||||
struct scoutfs_radix_root *fr);
|
||||
struct scoutfs_alloc_list_head *av,
|
||||
struct scoutfs_alloc_list_head *fr);
|
||||
int scoutfs_srch_cancel_compact(struct super_block *sb,
|
||||
struct scoutfs_radix_allocator *alloc,
|
||||
struct scoutfs_alloc *alloc,
|
||||
struct scoutfs_block_writer *wri,
|
||||
struct scoutfs_btree_root *root, u64 rid,
|
||||
struct scoutfs_radix_root *av,
|
||||
struct scoutfs_radix_root *fr);
|
||||
struct scoutfs_alloc_list_head *av,
|
||||
struct scoutfs_alloc_list_head *fr);
|
||||
|
||||
void scoutfs_srch_destroy(struct super_block *sb);
|
||||
int scoutfs_srch_setup(struct super_block *sb);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "counters.h"
|
||||
#include "client.h"
|
||||
#include "inode.h"
|
||||
#include "radix.h"
|
||||
#include "alloc.h"
|
||||
#include "block.h"
|
||||
#include "msg.h"
|
||||
#include "item.h"
|
||||
@@ -66,7 +66,7 @@ struct trans_info {
|
||||
bool writing;
|
||||
|
||||
struct scoutfs_log_trees lt;
|
||||
struct scoutfs_radix_allocator alloc;
|
||||
struct scoutfs_alloc alloc;
|
||||
struct scoutfs_block_writer wri;
|
||||
};
|
||||
|
||||
@@ -112,8 +112,7 @@ int scoutfs_trans_get_log_trees(struct super_block *sb)
|
||||
ret = scoutfs_client_get_log_trees(sb, <);
|
||||
if (ret == 0) {
|
||||
tri->lt = lt;
|
||||
scoutfs_radix_init_alloc(&tri->alloc, <.meta_avail,
|
||||
<.meta_freed);
|
||||
scoutfs_alloc_init(&tri->alloc, <.meta_avail, <.meta_freed);
|
||||
scoutfs_block_writer_init(sb, &tri->wri);
|
||||
|
||||
scoutfs_forest_init_btrees(sb, &tri->alloc, &tri->wri, <);
|
||||
@@ -195,6 +194,9 @@ void scoutfs_trans_write_func(struct work_struct *work)
|
||||
/* XXX this all needs serious work for dealing with errors */
|
||||
ret = (s = "data submit", scoutfs_inode_walk_writeback(sb, true)) ?:
|
||||
(s = "item dirty", scoutfs_item_write_dirty(sb)) ?:
|
||||
(s = "data prepare", scoutfs_data_prepare_commit(sb)) ?:
|
||||
(s = "alloc prepare", scoutfs_alloc_prepare_commit(sb,
|
||||
&tri->alloc, &tri->wri)) ?:
|
||||
(s = "meta write", scoutfs_block_writer_write(sb, &tri->wri)) ?:
|
||||
(s = "data wait", scoutfs_inode_walk_writeback(sb, false)) ?:
|
||||
(s = "commit log trees", commit_btrees(sb)) ?:
|
||||
@@ -369,7 +371,13 @@ static bool acquired_hold(struct super_block *sb,
|
||||
|
||||
/* XXX arbitrarily limit to 8 meg transactions */
|
||||
if (scoutfs_item_dirty_bytes(sb) >= (8 * 1024 * 1024)) {
|
||||
scoutfs_inc_counter(sb, trans_commit_full);
|
||||
scoutfs_inc_counter(sb, trans_commit_dirty_meta_full);
|
||||
queue_trans_work(sbi);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (scoutfs_alloc_meta_lo_thresh(sb, &tri->alloc)) {
|
||||
scoutfs_inc_counter(sb, trans_commit_meta_alloc_low);
|
||||
queue_trans_work(sbi);
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user