mirror of
https://github.com/versity/scoutfs.git
synced 2026-05-03 19:35:43 +00:00
Compare commits
7 Commits
v1.6
...
zab/cluste
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1f917d5bb | ||
|
|
68aa9e5ce6 | ||
|
|
28079610ed | ||
|
|
05cd4ebe92 | ||
|
|
0041b599ab | ||
|
|
f30e545870 | ||
|
|
cf046f26c4 |
@@ -1,41 +1,6 @@
|
||||
Versity ScoutFS Release Notes
|
||||
=============================
|
||||
|
||||
---
|
||||
v1.6
|
||||
\
|
||||
*Jul 7, 2022*
|
||||
|
||||
* **Fix memory leaks in rare corner cases**
|
||||
\
|
||||
Analysis tools found a few corner cases that leaked small structures,
|
||||
generally around error handling or startup and shutdown.
|
||||
|
||||
* **Add --skip-likely-huge scoutfs print command option**
|
||||
\
|
||||
Add an option to scoutfs print to reduce the size of the output
|
||||
so that it can be used to see system-wide metadata without being
|
||||
overwhelmed by file-level details.
|
||||
|
||||
---
|
||||
v1.5
|
||||
\
|
||||
*Jun 21, 2022*
|
||||
|
||||
* **Fix persistent error during server startup**
|
||||
\
|
||||
Fixed a case where the server would always hit a consistent error on
|
||||
seartup, preventing the system from mounting. This required a rare
|
||||
but valid state across the clients.
|
||||
|
||||
* **Fix a client hang that would lead to fencing**
|
||||
\
|
||||
The client module's use of in-kernel networking was missing annotation
|
||||
that could lead to communication hanging. The server would fence the
|
||||
client when it stopped communicating. This could be identified by the
|
||||
server fencing a client after it disconnected with no attempt by the
|
||||
client to reconnect.
|
||||
|
||||
---
|
||||
v1.4
|
||||
\
|
||||
|
||||
765
kmod/src/lock.c
765
kmod/src/lock.c
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
#ifndef _SCOUTFS_LOCK_H_
|
||||
#define _SCOUTFS_LOCK_H_
|
||||
|
||||
#include <linux/rhashtable.h>
|
||||
|
||||
#include "key.h"
|
||||
#include "tseq.h"
|
||||
|
||||
@@ -19,20 +21,24 @@ struct inode_deletion_lock_data;
|
||||
*/
|
||||
struct scoutfs_lock {
|
||||
struct super_block *sb;
|
||||
atomic_t refcount;
|
||||
spinlock_t lock;
|
||||
struct rcu_head rcu_head;
|
||||
struct scoutfs_key start;
|
||||
struct scoutfs_key end;
|
||||
struct rb_node node;
|
||||
struct rhash_head ht_head;
|
||||
struct rb_node range_node;
|
||||
u64 refresh_gen;
|
||||
u64 write_seq;
|
||||
u64 dirty_trans_seq;
|
||||
struct list_head lru_head;
|
||||
int lru_on_list;
|
||||
wait_queue_head_t waitq;
|
||||
unsigned long request_pending:1,
|
||||
invalidate_pending:1;
|
||||
|
||||
struct list_head inv_head; /* entry in linfo's list of locks with invalidations */
|
||||
struct list_head inv_list; /* list of lock's invalidation requests */
|
||||
struct list_head inv_req_list; /* list of lock's invalidation requests */
|
||||
struct list_head shrink_head;
|
||||
|
||||
spinlock_t cov_list_lock;
|
||||
|
||||
@@ -355,7 +355,6 @@ static int submit_send(struct super_block *sb,
|
||||
}
|
||||
if (rid != 0) {
|
||||
spin_unlock(&conn->lock);
|
||||
kfree(msend);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
}
|
||||
@@ -992,8 +991,6 @@ static void scoutfs_net_listen_worker(struct work_struct *work)
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
acc_sock->sk->sk_allocation = GFP_NOFS;
|
||||
|
||||
/* inherit accepted request funcs from listening conn */
|
||||
acc_conn = scoutfs_net_alloc_conn(sb, conn->notify_up,
|
||||
conn->notify_down,
|
||||
@@ -1056,8 +1053,6 @@ static void scoutfs_net_connect_worker(struct work_struct *work)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
sock->sk->sk_allocation = GFP_NOFS;
|
||||
|
||||
/* caller specified connect timeout */
|
||||
tv.tv_sec = conn->connect_timeout_ms / MSEC_PER_SEC;
|
||||
tv.tv_usec = (conn->connect_timeout_ms % MSEC_PER_SEC) * USEC_PER_MSEC;
|
||||
@@ -1346,12 +1341,10 @@ scoutfs_net_alloc_conn(struct super_block *sb,
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
if (info_size) {
|
||||
conn->info = kzalloc(info_size, GFP_NOFS);
|
||||
if (!conn->info) {
|
||||
kfree(conn);
|
||||
return NULL;
|
||||
}
|
||||
conn->info = kzalloc(info_size, GFP_NOFS);
|
||||
if (!conn->info) {
|
||||
kfree(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->workq = alloc_workqueue("scoutfs_net_%s",
|
||||
@@ -1457,8 +1450,6 @@ int scoutfs_net_bind(struct super_block *sb,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
sock->sk->sk_allocation = GFP_NOFS;
|
||||
|
||||
optval = 1;
|
||||
ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&optval, sizeof(optval));
|
||||
|
||||
@@ -157,15 +157,6 @@ static int free_rid(struct omap_rid_list *list, struct omap_rid_entry *entry)
|
||||
return nr;
|
||||
}
|
||||
|
||||
static void free_rid_list(struct omap_rid_list *list)
|
||||
{
|
||||
struct omap_rid_entry *entry;
|
||||
struct omap_rid_entry *tmp;
|
||||
|
||||
list_for_each_entry_safe(entry, tmp, &list->head, head)
|
||||
free_rid(list, entry);
|
||||
}
|
||||
|
||||
static int copy_rids(struct omap_rid_list *to, struct omap_rid_list *from, spinlock_t *from_lock)
|
||||
{
|
||||
struct omap_rid_entry *entry;
|
||||
@@ -813,10 +804,6 @@ void scoutfs_omap_server_shutdown(struct super_block *sb)
|
||||
llist_for_each_entry_safe(req, tmp, requests, llnode)
|
||||
kfree(req);
|
||||
|
||||
spin_lock(&ominf->lock);
|
||||
free_rid_list(&ominf->rids);
|
||||
spin_unlock(&ominf->lock);
|
||||
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
@@ -877,10 +864,6 @@ void scoutfs_omap_destroy(struct super_block *sb)
|
||||
rhashtable_walk_stop(&iter);
|
||||
rhashtable_walk_exit(&iter);
|
||||
|
||||
spin_lock(&ominf->lock);
|
||||
free_rid_list(&ominf->rids);
|
||||
spin_unlock(&ominf->lock);
|
||||
|
||||
rhashtable_destroy(&ominf->group_ht);
|
||||
rhashtable_destroy(&ominf->req_ht);
|
||||
kfree(ominf);
|
||||
|
||||
@@ -1023,6 +1023,7 @@ DECLARE_EVENT_CLASS(scoutfs_lock_class,
|
||||
__field(unsigned char, request_pending)
|
||||
__field(unsigned char, invalidate_pending)
|
||||
__field(int, mode)
|
||||
__field(unsigned int, refcount)
|
||||
__field(unsigned int, waiters_cw)
|
||||
__field(unsigned int, waiters_pr)
|
||||
__field(unsigned int, waiters_ex)
|
||||
@@ -1038,6 +1039,7 @@ DECLARE_EVENT_CLASS(scoutfs_lock_class,
|
||||
__entry->request_pending = lck->request_pending;
|
||||
__entry->invalidate_pending = lck->invalidate_pending;
|
||||
__entry->mode = lck->mode;
|
||||
__entry->refcount = atomic_read(&lck->refcount);
|
||||
__entry->waiters_pr = lck->waiters[SCOUTFS_LOCK_READ];
|
||||
__entry->waiters_ex = lck->waiters[SCOUTFS_LOCK_WRITE];
|
||||
__entry->waiters_cw = lck->waiters[SCOUTFS_LOCK_WRITE_ONLY];
|
||||
@@ -1045,10 +1047,10 @@ DECLARE_EVENT_CLASS(scoutfs_lock_class,
|
||||
__entry->users_ex = lck->users[SCOUTFS_LOCK_WRITE];
|
||||
__entry->users_cw = lck->users[SCOUTFS_LOCK_WRITE_ONLY];
|
||||
),
|
||||
TP_printk(SCSBF" start "SK_FMT" end "SK_FMT" mode %u reqpnd %u invpnd %u rfrgen %llu waiters: pr %u ex %u cw %u users: pr %u ex %u cw %u",
|
||||
TP_printk(SCSBF" start "SK_FMT" end "SK_FMT" mode %u reqpnd %u invpnd %u rfrgen %llu rfcnt %d waiters: pr %u ex %u cw %u users: pr %u ex %u cw %u",
|
||||
SCSB_TRACE_ARGS, sk_trace_args(start), sk_trace_args(end),
|
||||
__entry->mode, __entry->request_pending,
|
||||
__entry->invalidate_pending, __entry->refresh_gen,
|
||||
__entry->invalidate_pending, __entry->refresh_gen, __entry->refcount,
|
||||
__entry->waiters_pr, __entry->waiters_ex, __entry->waiters_cw,
|
||||
__entry->users_pr, __entry->users_ex, __entry->users_cw)
|
||||
);
|
||||
|
||||
@@ -1267,7 +1267,6 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
char *err_str = NULL;
|
||||
u64 nr;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
if (arg_len != 0) {
|
||||
ret = -EINVAL;
|
||||
@@ -1311,27 +1310,16 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (ret != -ENOENT) {
|
||||
/* need to sync lt with respect to changes in other structures */
|
||||
scoutfs_key_init_log_trees(&key, le64_to_cpu(lt.rid), le64_to_cpu(lt.nr));
|
||||
ret = scoutfs_btree_dirty(sb, &server->alloc, &server->wri,
|
||||
&super->logs_root, &key);
|
||||
if (ret < 0) {
|
||||
err_str = "dirtying lt btree key";
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* drops and re-acquires the mutex and commit if it has to wait */
|
||||
ret = finalize_and_start_log_merge(sb, <, rid, &hold);
|
||||
if (ret < 0)
|
||||
goto update;
|
||||
goto unlock;
|
||||
|
||||
if (get_volopt_val(server, SCOUTFS_VOLOPT_DATA_ALLOC_ZONE_BLOCKS_NR, &data_zone_blocks)) {
|
||||
ret = get_data_alloc_zone_bits(sb, rid, exclusive, vacant, data_zone_blocks);
|
||||
if (ret < 0) {
|
||||
err_str = "getting alloc zone bits";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
} else {
|
||||
data_zone_blocks = 0;
|
||||
@@ -1348,13 +1336,13 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
<.meta_freed);
|
||||
if (ret < 0) {
|
||||
err_str = "splicing committed meta_freed";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = alloc_move_empty(sb, &super->data_alloc, <.data_freed, 0);
|
||||
if (ret < 0) {
|
||||
err_str = "emptying committed data_freed";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = scoutfs_alloc_fill_list(sb, &server->alloc, &server->wri,
|
||||
@@ -1363,7 +1351,7 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
SCOUTFS_SERVER_META_FILL_TARGET);
|
||||
if (ret < 0) {
|
||||
err_str = "filling meta_avail";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (le64_to_cpu(server->meta_avail->total_len) <= scoutfs_server_reserved_meta_blocks(sb))
|
||||
@@ -1376,7 +1364,7 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
exclusive, vacant, data_zone_blocks);
|
||||
if (ret < 0) {
|
||||
err_str = "refilling data_avail";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (le64_to_cpu(lt.data_avail.total_len) < SCOUTFS_SERVER_DATA_FILL_LO)
|
||||
@@ -1396,7 +1384,7 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
if (ret < 0) {
|
||||
zero_data_alloc_zone_bits(<);
|
||||
err_str = "setting data_avail zone bits";
|
||||
goto update;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
lt.data_alloc_zone_blocks = cpu_to_le64(data_zone_blocks);
|
||||
@@ -1405,18 +1393,13 @@ static int server_get_log_trees(struct super_block *sb,
|
||||
/* give the transaction a new seq (must have been ==) */
|
||||
lt.get_trans_seq = cpu_to_le64(scoutfs_server_next_seq(sb));
|
||||
|
||||
update:
|
||||
/* update client's log tree's item */
|
||||
scoutfs_key_init_log_trees(&key, le64_to_cpu(lt.rid), le64_to_cpu(lt.nr));
|
||||
err = scoutfs_btree_force(sb, &server->alloc, &server->wri,
|
||||
scoutfs_key_init_log_trees(&key, le64_to_cpu(lt.rid),
|
||||
le64_to_cpu(lt.nr));
|
||||
ret = scoutfs_btree_force(sb, &server->alloc, &server->wri,
|
||||
&super->logs_root, &key, <, sizeof(lt));
|
||||
BUG_ON(err < 0); /* can duplicate extents.. move dst in super, still in in lt src */
|
||||
if (err < 0) {
|
||||
if (ret == 0) {
|
||||
ret = err;
|
||||
err_str = "updating log trees";
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
err_str = "updating log trees";
|
||||
|
||||
unlock:
|
||||
if (unlock_alloc)
|
||||
|
||||
@@ -496,7 +496,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
ret = assign_random_id(sbi);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&sbi->next_ino_lock);
|
||||
spin_lock_init(&sbi->data_wait_root.lock);
|
||||
@@ -505,7 +505,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
/* parse options early for use during setup */
|
||||
ret = scoutfs_options_early_setup(sb, data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
scoutfs_options_read(sb, &opts);
|
||||
|
||||
ret = sb_set_blocksize(sb, SCOUTFS_BLOCK_SM_SIZE);
|
||||
|
||||
@@ -597,7 +597,7 @@ format.
|
||||
.PD
|
||||
|
||||
.TP
|
||||
.BI "print {-S|--skip-likely-huge} META-DEVICE"
|
||||
.BI "print META-DEVICE"
|
||||
.sp
|
||||
Prints out all of the metadata in the file system. This makes no effort
|
||||
to ensure that the structures are consistent as they're traversed and
|
||||
@@ -607,20 +607,6 @@ output.
|
||||
.PD 0
|
||||
.TP
|
||||
.sp
|
||||
.B "-S, --skip-likely-huge"
|
||||
Skip printing structures that are likely to be very large. The
|
||||
structures that are skipped tend to be global and whose size tends to be
|
||||
related to the size of the volume. Examples of skipped structures include
|
||||
the global fs items, srch files, and metadata and data
|
||||
allocators. Similar structures that are not skipped are related to the
|
||||
number of mounts and are maintained at a relatively reasonable size.
|
||||
These include per-mount log trees, srch files, allocators, and the
|
||||
metadata allocators used by server commits.
|
||||
.sp
|
||||
Skipping the larger structures limits the print output to a relatively
|
||||
constant size rather than being a large multiple of the used metadata
|
||||
space of the volume making the output much more useful for inspection.
|
||||
.TP
|
||||
.B "META-DEVICE"
|
||||
The path to the metadata device for the filesystem whose metadata will be
|
||||
printed. Since this command reads via the host's buffer cache, it may not
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -990,10 +989,9 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno)
|
||||
|
||||
struct print_args {
|
||||
char *meta_device;
|
||||
bool skip_likely_huge;
|
||||
};
|
||||
|
||||
static int print_volume(int fd, struct print_args *args)
|
||||
static int print_volume(int fd)
|
||||
{
|
||||
struct scoutfs_super_block *super = NULL;
|
||||
struct print_recursion_args pa;
|
||||
@@ -1043,26 +1041,23 @@ static int print_volume(int fd, struct print_args *args)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
if (!args->skip_likely_huge) {
|
||||
for (i = 0; i < array_size(super->meta_alloc); i++) {
|
||||
snprintf(str, sizeof(str), "meta_alloc[%u]", i);
|
||||
err = print_btree(fd, super, str, &super->meta_alloc[i].root,
|
||||
print_alloc_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
err = print_btree(fd, super, "data_alloc", &super->data_alloc.root,
|
||||
for (i = 0; i < array_size(super->meta_alloc); i++) {
|
||||
snprintf(str, sizeof(str), "meta_alloc[%u]", i);
|
||||
err = print_btree(fd, super, str, &super->meta_alloc[i].root,
|
||||
print_alloc_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
err = print_btree(fd, super, "data_alloc", &super->data_alloc.root,
|
||||
print_alloc_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
err = print_btree(fd, super, "srch_root", &super->srch_root,
|
||||
print_srch_root_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
err = print_btree(fd, super, "logs_root", &super->logs_root,
|
||||
print_log_trees_item, NULL);
|
||||
if (err && !ret)
|
||||
@@ -1070,23 +1065,19 @@ static int print_volume(int fd, struct print_args *args)
|
||||
|
||||
pa.super = super;
|
||||
pa.fd = fd;
|
||||
if (!args->skip_likely_huge) {
|
||||
err = print_btree_leaf_items(fd, super, &super->srch_root.ref,
|
||||
print_srch_root_files, &pa);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
err = print_btree_leaf_items(fd, super, &super->srch_root.ref,
|
||||
print_srch_root_files, &pa);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
err = print_btree_leaf_items(fd, super, &super->logs_root.ref,
|
||||
print_log_trees_roots, &pa);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
if (!args->skip_likely_huge) {
|
||||
err = print_btree(fd, super, "fs_root", &super->fs_root,
|
||||
print_fs_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
err = print_btree(fd, super, "fs_root", &super->fs_root,
|
||||
print_fs_item, NULL);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
out:
|
||||
free(super);
|
||||
@@ -1107,7 +1098,7 @@ static int do_print(struct print_args *args)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = print_volume(fd, args);
|
||||
ret = print_volume(fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
};
|
||||
@@ -1117,9 +1108,6 @@ static int parse_opt(int key, char *arg, struct argp_state *state)
|
||||
struct print_args *args = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'S':
|
||||
args->skip_likely_huge = true;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (!args->meta_device)
|
||||
args->meta_device = strdup_or_error(state, arg);
|
||||
@@ -1137,13 +1125,8 @@ static int parse_opt(int key, char *arg, struct argp_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "skip-likely-huge", 'S', NULL, 0, "Skip large structures to minimize output size"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct argp argp = {
|
||||
options,
|
||||
NULL,
|
||||
parse_opt,
|
||||
"META-DEV",
|
||||
"Print metadata structures"
|
||||
|
||||
Reference in New Issue
Block a user