mirror of
https://github.com/versity/scoutfs.git
synced 2025-12-23 13:35:18 +00:00
Add orphan_scan_delay_ms mount option
Add a mount option to set the delay betwen scanning of the orphan list. The sysfs file for the option is writable so this option can be set at run time. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -1745,18 +1745,26 @@ void scoutfs_inode_queue_iput(struct inode *inode)
|
|||||||
/*
|
/*
|
||||||
* All mounts are performing this work concurrently. We introduce
|
* All mounts are performing this work concurrently. We introduce
|
||||||
* significant jitter between them to try and keep them from all
|
* significant jitter between them to try and keep them from all
|
||||||
* bunching up and working on the same inodes.
|
* bunching up and working on the same inodes. We always try to delay
|
||||||
|
* for at least one jiffy if precision tricks us into calculating no
|
||||||
|
* delay.
|
||||||
*/
|
*/
|
||||||
static void schedule_orphan_dwork(struct inode_sb_info *inf)
|
void scoutfs_inode_schedule_orphan_dwork(struct super_block *sb)
|
||||||
{
|
{
|
||||||
#define ORPHAN_SCAN_MIN_MS (10 * MSEC_PER_SEC)
|
DECLARE_INODE_SB_INFO(sb, inf);
|
||||||
#define ORPHAN_SCAN_JITTER_MS (40 * MSEC_PER_SEC)
|
struct scoutfs_mount_options opts;
|
||||||
|
unsigned long low;
|
||||||
|
unsigned long high;
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
|
|
||||||
if (!inf->stopped) {
|
if (!inf->stopped) {
|
||||||
delay = msecs_to_jiffies(ORPHAN_SCAN_MIN_MS +
|
scoutfs_options_read(sb, &opts);
|
||||||
prandom_u32_max(ORPHAN_SCAN_JITTER_MS));
|
|
||||||
schedule_delayed_work(&inf->orphan_scan_dwork, delay);
|
low = (opts.orphan_scan_delay_ms * 80) / 100;
|
||||||
|
high = (opts.orphan_scan_delay_ms * 120) / 100;
|
||||||
|
delay = msecs_to_jiffies(low + prandom_u32_max(high - low)) ?: 1;
|
||||||
|
|
||||||
|
mod_delayed_work(system_wq, &inf->orphan_scan_dwork, delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1885,7 +1893,7 @@ out:
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
scoutfs_inc_counter(sb, orphan_scan_error);
|
scoutfs_inc_counter(sb, orphan_scan_error);
|
||||||
|
|
||||||
schedule_orphan_dwork(inf);
|
scoutfs_inode_schedule_orphan_dwork(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2010,9 +2018,7 @@ int scoutfs_inode_setup(struct super_block *sb)
|
|||||||
*/
|
*/
|
||||||
void scoutfs_inode_start(struct super_block *sb)
|
void scoutfs_inode_start(struct super_block *sb)
|
||||||
{
|
{
|
||||||
DECLARE_INODE_SB_INFO(sb, inf);
|
scoutfs_inode_schedule_orphan_dwork(sb);
|
||||||
|
|
||||||
schedule_orphan_dwork(inf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ int scoutfs_setattr(struct dentry *dentry, struct iattr *attr);
|
|||||||
|
|
||||||
int scoutfs_inode_orphan_create(struct super_block *sb, u64 ino, struct scoutfs_lock *lock);
|
int scoutfs_inode_orphan_create(struct super_block *sb, u64 ino, struct scoutfs_lock *lock);
|
||||||
int scoutfs_inode_orphan_delete(struct super_block *sb, u64 ino, struct scoutfs_lock *lock);
|
int scoutfs_inode_orphan_delete(struct super_block *sb, u64 ino, struct scoutfs_lock *lock);
|
||||||
|
void scoutfs_inode_schedule_orphan_dwork(struct super_block *sb);
|
||||||
|
|
||||||
void scoutfs_inode_queue_writeback(struct inode *inode);
|
void scoutfs_inode_queue_writeback(struct inode *inode);
|
||||||
int scoutfs_inode_walk_writeback(struct super_block *sb, bool write);
|
int scoutfs_inode_walk_writeback(struct super_block *sb, bool write);
|
||||||
|
|||||||
@@ -26,16 +26,19 @@
|
|||||||
#include "msg.h"
|
#include "msg.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
|
#include "inode.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Opt_quorum_slot_nr,
|
|
||||||
Opt_metadev_path,
|
Opt_metadev_path,
|
||||||
|
Opt_orphan_scan_delay_ms,
|
||||||
|
Opt_quorum_slot_nr,
|
||||||
Opt_err,
|
Opt_err,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const match_table_t tokens = {
|
static const match_table_t tokens = {
|
||||||
{Opt_quorum_slot_nr, "quorum_slot_nr=%s"},
|
|
||||||
{Opt_metadev_path, "metadev_path=%s"},
|
{Opt_metadev_path, "metadev_path=%s"},
|
||||||
|
{Opt_orphan_scan_delay_ms, "orphan_scan_delay_ms=%s"},
|
||||||
|
{Opt_quorum_slot_nr, "quorum_slot_nr=%s"},
|
||||||
{Opt_err, NULL}
|
{Opt_err, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,10 +102,15 @@ static void free_options(struct scoutfs_mount_options *opts)
|
|||||||
kfree(opts->metadev_path);
|
kfree(opts->metadev_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MIN_ORPHAN_SCAN_DELAY_MS 100UL
|
||||||
|
#define DEFAULT_ORPHAN_SCAN_DELAY_MS (10 * MSEC_PER_SEC)
|
||||||
|
#define MAX_ORPHAN_SCAN_DELAY_MS (60 * MSEC_PER_SEC)
|
||||||
|
|
||||||
static void init_default_options(struct scoutfs_mount_options *opts)
|
static void init_default_options(struct scoutfs_mount_options *opts)
|
||||||
{
|
{
|
||||||
memset(opts, 0, sizeof(*opts));
|
memset(opts, 0, sizeof(*opts));
|
||||||
opts->quorum_slot_nr = -1;
|
opts->quorum_slot_nr = -1;
|
||||||
|
opts->orphan_scan_delay_ms = DEFAULT_ORPHAN_SCAN_DELAY_MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -126,6 +134,30 @@ static int parse_options(struct super_block *sb, char *options, struct scoutfs_m
|
|||||||
token = match_token(p, tokens, args);
|
token = match_token(p, tokens, args);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
|
|
||||||
|
case Opt_metadev_path:
|
||||||
|
ret = parse_bdev_path(sb, &args[0], &opts->metadev_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Opt_orphan_scan_delay_ms:
|
||||||
|
if (opts->orphan_scan_delay_ms != -1) {
|
||||||
|
scoutfs_err(sb, "multiple orphan_scan_delay_ms options provided, only provide one.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = match_int(args, &nr);
|
||||||
|
if (ret < 0 ||
|
||||||
|
nr < MIN_ORPHAN_SCAN_DELAY_MS || nr > MAX_ORPHAN_SCAN_DELAY_MS) {
|
||||||
|
scoutfs_err(sb, "invalid orphan_scan_delay_ms option, must be between %lu and %lu",
|
||||||
|
MIN_ORPHAN_SCAN_DELAY_MS, MAX_ORPHAN_SCAN_DELAY_MS);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = -EINVAL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
opts->orphan_scan_delay_ms = nr;
|
||||||
|
break;
|
||||||
|
|
||||||
case Opt_quorum_slot_nr:
|
case Opt_quorum_slot_nr:
|
||||||
if (opts->quorum_slot_nr != -1) {
|
if (opts->quorum_slot_nr != -1) {
|
||||||
scoutfs_err(sb, "multiple quorum_slot_nr options provided, only provide one.");
|
scoutfs_err(sb, "multiple quorum_slot_nr options provided, only provide one.");
|
||||||
@@ -143,12 +175,6 @@ static int parse_options(struct super_block *sb, char *options, struct scoutfs_m
|
|||||||
opts->quorum_slot_nr = nr;
|
opts->quorum_slot_nr = nr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Opt_metadev_path:
|
|
||||||
ret = parse_bdev_path(sb, &args[0], &opts->metadev_path);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
scoutfs_err(sb, "Unknown or malformed option, \"%s\"", p);
|
scoutfs_err(sb, "Unknown or malformed option, \"%s\"", p);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -227,9 +253,10 @@ int scoutfs_options_show(struct seq_file *seq, struct dentry *root)
|
|||||||
|
|
||||||
scoutfs_options_read(sb, &opts);
|
scoutfs_options_read(sb, &opts);
|
||||||
|
|
||||||
|
seq_printf(seq, ",metadev_path=%s", opts.metadev_path);
|
||||||
|
seq_printf(seq, ",orphan_scan_delay_ms=%u", opts.orphan_scan_delay_ms);
|
||||||
if (opts.quorum_slot_nr >= 0)
|
if (opts.quorum_slot_nr >= 0)
|
||||||
seq_printf(seq, ",quorum_slot_nr=%d", opts.quorum_slot_nr);
|
seq_printf(seq, ",quorum_slot_nr=%d", opts.quorum_slot_nr);
|
||||||
seq_printf(seq, ",metadev_path=%s", opts.metadev_path);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -245,6 +272,47 @@ static ssize_t metadev_path_show(struct kobject *kobj, struct kobj_attribute *at
|
|||||||
}
|
}
|
||||||
SCOUTFS_ATTR_RO(metadev_path);
|
SCOUTFS_ATTR_RO(metadev_path);
|
||||||
|
|
||||||
|
static ssize_t orphan_scan_delay_ms_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj);
|
||||||
|
struct scoutfs_mount_options opts;
|
||||||
|
|
||||||
|
scoutfs_options_read(sb, &opts);
|
||||||
|
|
||||||
|
return snprintf(buf, PAGE_SIZE, "%u", opts.orphan_scan_delay_ms);
|
||||||
|
}
|
||||||
|
static ssize_t orphan_scan_delay_ms_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj);
|
||||||
|
DECLARE_OPTIONS_INFO(sb, optinf);
|
||||||
|
char nullterm[20]; /* more than enough for octal -U32_MAX */
|
||||||
|
long val;
|
||||||
|
int len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
len = min(count, sizeof(nullterm) - 1);
|
||||||
|
memcpy(nullterm, buf, len);
|
||||||
|
nullterm[len] = '\0';
|
||||||
|
|
||||||
|
ret = kstrtol(nullterm, 0, &val);
|
||||||
|
if (ret < 0 || val < MIN_ORPHAN_SCAN_DELAY_MS || val > MAX_ORPHAN_SCAN_DELAY_MS) {
|
||||||
|
scoutfs_err(sb, "invalid orphan_scan_delay_ms value written to options sysfs file, must be between %lu and %lu",
|
||||||
|
MIN_ORPHAN_SCAN_DELAY_MS, MAX_ORPHAN_SCAN_DELAY_MS);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_seqlock(&optinf->seqlock);
|
||||||
|
optinf->opts.orphan_scan_delay_ms = val;
|
||||||
|
write_sequnlock(&optinf->seqlock);
|
||||||
|
|
||||||
|
scoutfs_inode_schedule_orphan_dwork(sb);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
SCOUTFS_ATTR_RW(orphan_scan_delay_ms);
|
||||||
|
|
||||||
static ssize_t quorum_slot_nr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
static ssize_t quorum_slot_nr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj);
|
struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj);
|
||||||
@@ -258,6 +326,7 @@ SCOUTFS_ATTR_RO(quorum_slot_nr);
|
|||||||
|
|
||||||
static struct attribute *options_attrs[] = {
|
static struct attribute *options_attrs[] = {
|
||||||
SCOUTFS_ATTR_PTR(metadev_path),
|
SCOUTFS_ATTR_PTR(metadev_path),
|
||||||
|
SCOUTFS_ATTR_PTR(orphan_scan_delay_ms),
|
||||||
SCOUTFS_ATTR_PTR(quorum_slot_nr),
|
SCOUTFS_ATTR_PTR(quorum_slot_nr),
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
struct scoutfs_mount_options {
|
struct scoutfs_mount_options {
|
||||||
int quorum_slot_nr;
|
|
||||||
char *metadev_path;
|
char *metadev_path;
|
||||||
|
unsigned int orphan_scan_delay_ms;
|
||||||
|
int quorum_slot_nr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void scoutfs_options_read(struct super_block *sb, struct scoutfs_mount_options *opts);
|
void scoutfs_options_read(struct super_block *sb, struct scoutfs_mount_options *opts);
|
||||||
|
|||||||
@@ -21,6 +21,21 @@ contains the filesystem's metadata.
|
|||||||
.sp
|
.sp
|
||||||
This option is required.
|
This option is required.
|
||||||
.TP
|
.TP
|
||||||
|
.B orphan_scan_delay_ms=<number>
|
||||||
|
This option sets the average expected delay, in milliseconds, between
|
||||||
|
each mount's scan of the global orphaned inode list. Jitter is added to
|
||||||
|
avoid contention so each individual delay between scans is a random
|
||||||
|
value up to 20% less than or greater than this average expected delay.
|
||||||
|
.sp
|
||||||
|
The minimum value for this option is 100ms which is very short and is
|
||||||
|
only reasonable for testing or experiments. The default is 10000ms (10
|
||||||
|
seconds) and the maximum is 60000ms (1 minute).
|
||||||
|
.sp
|
||||||
|
This option can be changed in an active mount by writing to its file in
|
||||||
|
the options directory in the mount's sysfs directory. Writing a new
|
||||||
|
value will cause the next pending orphan scan to be rescheduled
|
||||||
|
with the newly written delay time.
|
||||||
|
.TP
|
||||||
.B quorum_slot_nr=<number>
|
.B quorum_slot_nr=<number>
|
||||||
The quorum_slot_nr option assigns a quorum member slot to the mount.
|
The quorum_slot_nr option assigns a quorum member slot to the mount.
|
||||||
The mount will use the slot assignment to claim exclusive ownership of
|
The mount will use the slot assignment to claim exclusive ownership of
|
||||||
|
|||||||
Reference in New Issue
Block a user