diff --git a/kmod/src/client.c b/kmod/src/client.c index 4799fcc5..0f1006d0 100644 --- a/kmod/src/client.c +++ b/kmod/src/client.c @@ -477,12 +477,15 @@ static void scoutfs_client_connect_worker(struct work_struct *work) struct super_block *sb = client->sb; struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct scoutfs_super_block *super = &sbi->super; - struct mount_options *opts = &sbi->opts; - const bool am_quorum = opts->quorum_slot_nr >= 0; + struct scoutfs_mount_options opts; struct scoutfs_net_greeting greet; struct sockaddr_in sin; + bool am_quorum; int ret; + scoutfs_options_read(sb, &opts); + am_quorum = opts.quorum_slot_nr >= 0; + /* can unmount once server farewell handling removes our item */ if (client->sending_farewell && lookup_mounted_client_item(sb, sbi->rid) == 0) { diff --git a/kmod/src/fence.c b/kmod/src/fence.c index 7f989e74..ff617634 100644 --- a/kmod/src/fence.c +++ b/kmod/src/fence.c @@ -395,12 +395,13 @@ int scoutfs_fence_wait_fenced(struct super_block *sb, long timeout_jiffies) int scoutfs_fence_setup(struct super_block *sb) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct mount_options *opts = &sbi->opts; + struct scoutfs_mount_options opts; struct fence_info *fi; int ret; /* can only fence if we can be elected by quorum */ - if (opts->quorum_slot_nr == -1) { + scoutfs_options_read(sb, &opts); + if (opts.quorum_slot_nr == -1) { ret = 0; goto out; } diff --git a/kmod/src/options.c b/kmod/src/options.c index 74c9819c..4a5e9c2c 100644 --- a/kmod/src/options.c +++ b/kmod/src/options.c @@ -27,21 +27,26 @@ #include "options.h" #include "super.h" +enum { + Opt_quorum_slot_nr, + Opt_metadev_path, + Opt_err, +}; + static const match_table_t tokens = { {Opt_quorum_slot_nr, "quorum_slot_nr=%s"}, {Opt_metadev_path, "metadev_path=%s"}, {Opt_err, NULL} }; -struct options_sb_info { - struct dentry *debugfs_dir; +struct options_info { + seqlock_t seqlock; + struct scoutfs_mount_options opts; + struct scoutfs_sysfs_attrs sysfs_attrs; }; -u32 scoutfs_option_u32(struct super_block *sb, int token) -{ - WARN_ON_ONCE(1); - return 0; -} +#define DECLARE_OPTIONS_INFO(sb, name) \ + struct options_info *name = SCOUTFS_SB(sb)->options_info static int parse_bdev_path(struct super_block *sb, substring_t *substr, char **bdev_path_ret) @@ -89,8 +94,24 @@ out: return ret; } -int scoutfs_parse_options(struct super_block *sb, char *options, - struct mount_options *parsed) +static void free_options(struct scoutfs_mount_options *opts) +{ + kfree(opts->metadev_path); +} + +static void init_default_options(struct scoutfs_mount_options *opts) +{ + memset(opts, 0, sizeof(*opts)); + opts->quorum_slot_nr = -1; +} + +/* + * Parse the option string into our options struct. This can allocate + * memory in the struct. The caller is responsible for always calling + * free_options() when the struct is destroyed, including when we return + * an error. + */ +static int parse_options(struct super_block *sb, char *options, struct scoutfs_mount_options *opts) { substring_t args[MAX_OPT_ARGS]; int nr; @@ -98,49 +119,43 @@ int scoutfs_parse_options(struct super_block *sb, char *options, char *p; int ret; - /* Set defaults */ - memset(parsed, 0, sizeof(*parsed)); - parsed->quorum_slot_nr = -1; - while ((p = strsep(&options, ",")) != NULL) { if (!*p) continue; token = match_token(p, tokens, args); switch (token) { - case Opt_quorum_slot_nr: - if (parsed->quorum_slot_nr != -1) { + case Opt_quorum_slot_nr: + if (opts->quorum_slot_nr != -1) { scoutfs_err(sb, "multiple quorum_slot_nr options provided, only provide one."); return -EINVAL; } ret = match_int(args, &nr); - if (ret < 0 || nr < 0 || - nr >= SCOUTFS_QUORUM_MAX_SLOTS) { + if (ret < 0 || nr < 0 || nr >= SCOUTFS_QUORUM_MAX_SLOTS) { scoutfs_err(sb, "invalid quorum_slot_nr option, must be between 0 and %u", SCOUTFS_QUORUM_MAX_SLOTS - 1); if (ret == 0) ret = -EINVAL; return ret; } - parsed->quorum_slot_nr = nr; + opts->quorum_slot_nr = nr; break; - case Opt_metadev_path: - ret = parse_bdev_path(sb, &args[0], - &parsed->metadev_path); + case Opt_metadev_path: + ret = parse_bdev_path(sb, &args[0], &opts->metadev_path); if (ret < 0) return ret; break; + default: scoutfs_err(sb, "Unknown or malformed option, \"%s\"", p); return -EINVAL; - break; } } - if (!parsed->metadev_path) { + if (!opts->metadev_path) { scoutfs_err(sb, "Required mount option \"metadev_path\" not found"); return -EINVAL; } @@ -148,40 +163,138 @@ int scoutfs_parse_options(struct super_block *sb, char *options, return 0; } -int scoutfs_options_setup(struct super_block *sb) +void scoutfs_options_read(struct super_block *sb, struct scoutfs_mount_options *opts) +{ + DECLARE_OPTIONS_INFO(sb, optinf); + unsigned int seq; + + if (WARN_ON_ONCE(optinf == NULL)) { + /* trying to use options before early setup or after destroy */ + init_default_options(opts); + return; + } + + do { + seq = read_seqbegin(&optinf->seqlock); + memcpy(opts, &optinf->opts, sizeof(struct scoutfs_mount_options)); + } while (read_seqretry(&optinf->seqlock, seq)); +} + +/* + * Early setup that parses and stores the options so that the rest of + * setup can use them. Full options setup that relies on other + * components will be done later. + */ +int scoutfs_options_early_setup(struct super_block *sb, char *options) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct options_sb_info *osi; + struct scoutfs_mount_options opts; + struct options_info *optinf; int ret; - osi = kzalloc(sizeof(struct options_sb_info), GFP_KERNEL); - if (!osi) - return -ENOMEM; + init_default_options(&opts); - sbi->options = osi; + ret = parse_options(sb, options, &opts); + if (ret < 0) + goto out; - osi->debugfs_dir = debugfs_create_dir("options", sbi->debug_root); - if (!osi->debugfs_dir) { + optinf = kzalloc(sizeof(struct options_info), GFP_KERNEL); + if (!optinf) { ret = -ENOMEM; goto out; } + seqlock_init(&optinf->seqlock); + scoutfs_sysfs_init_attrs(sb, &optinf->sysfs_attrs); + + write_seqlock(&optinf->seqlock); + optinf->opts = opts; + write_sequnlock(&optinf->seqlock); + + sbi->options_info = optinf; ret = 0; out: - if (ret) + if (ret < 0) + free_options(&opts); + + return ret; +} + +int scoutfs_options_show(struct seq_file *seq, struct dentry *root) +{ + struct super_block *sb = root->d_sb; + struct scoutfs_mount_options opts; + + scoutfs_options_read(sb, &opts); + + if (opts.quorum_slot_nr >= 0) + seq_printf(seq, ",quorum_slot_nr=%d", opts.quorum_slot_nr); + seq_printf(seq, ",metadev_path=%s", opts.metadev_path); + + return 0; +} + +static ssize_t metadev_path_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, "%s", opts.metadev_path); +} +SCOUTFS_ATTR_RO(metadev_path); + +static ssize_t quorum_server_nr_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, "%d\n", opts.quorum_slot_nr); +} +SCOUTFS_ATTR_RO(quorum_server_nr); + +static struct attribute *options_attrs[] = { + SCOUTFS_ATTR_PTR(metadev_path), + SCOUTFS_ATTR_PTR(quorum_server_nr), + NULL, +}; + +int scoutfs_options_setup(struct super_block *sb) +{ + DECLARE_OPTIONS_INFO(sb, optinf); + int ret; + + ret = scoutfs_sysfs_create_attrs(sb, &optinf->sysfs_attrs, options_attrs, "mount_options"); + if (ret < 0) scoutfs_options_destroy(sb); return ret; } +/* + * We remove the sysfs files early in unmount so that they can't try to call other subsystems + * as they're being destroyed. + */ +void scoutfs_options_stop(struct super_block *sb) +{ + DECLARE_OPTIONS_INFO(sb, optinf); + + if (optinf) + scoutfs_sysfs_destroy_attrs(sb, &optinf->sysfs_attrs); +} + void scoutfs_options_destroy(struct super_block *sb) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct options_sb_info *osi = sbi->options; + DECLARE_OPTIONS_INFO(sb, optinf); - if (osi) { - if (osi->debugfs_dir) - debugfs_remove_recursive(osi->debugfs_dir); - kfree(osi); - sbi->options = NULL; + scoutfs_options_stop(sb); + + if (optinf) { + free_options(&optinf->opts); + kfree(optinf); + sbi->options_info = NULL; } } diff --git a/kmod/src/options.h b/kmod/src/options.h index d948b5b7..993f3894 100644 --- a/kmod/src/options.h +++ b/kmod/src/options.h @@ -5,23 +5,17 @@ #include #include "format.h" -enum scoutfs_mount_options { - Opt_quorum_slot_nr, - Opt_metadev_path, - Opt_err, -}; - -struct mount_options { +struct scoutfs_mount_options { int quorum_slot_nr; char *metadev_path; }; -int scoutfs_parse_options(struct super_block *sb, char *options, - struct mount_options *parsed); +void scoutfs_options_read(struct super_block *sb, struct scoutfs_mount_options *opts); +int scoutfs_options_show(struct seq_file *seq, struct dentry *root); + +int scoutfs_options_early_setup(struct super_block *sb, char *options); int scoutfs_options_setup(struct super_block *sb); +void scoutfs_options_stop(struct super_block *sb); void scoutfs_options_destroy(struct super_block *sb); -u32 scoutfs_option_u32(struct super_block *sb, int token); -#define scoutfs_option_bool scoutfs_option_u32 - #endif /* _SCOUTFS_OPTIONS_H_ */ diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index f8b547d2..91f5b492 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -116,6 +116,7 @@ struct quorum_info { struct socket *sock; bool shutdown; + int our_quorum_slot_nr; unsigned long flags; int votes_needed; @@ -160,9 +161,7 @@ static ktime_t heartbeat_timeout(void) static int create_socket(struct super_block *sb) { DECLARE_QUORUM_INFO(sb, qinf); - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct mount_options *opts = &sbi->opts; - struct scoutfs_super_block *super = &sbi->super; + struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; struct socket *sock = NULL; struct sockaddr_in sin; int addrlen; @@ -176,7 +175,7 @@ static int create_socket(struct super_block *sb) sock->sk->sk_allocation = GFP_NOFS; - scoutfs_quorum_slot_sin(super, opts->quorum_slot_nr, &sin); + scoutfs_quorum_slot_sin(super, qinf->our_quorum_slot_nr, &sin); addrlen = sizeof(sin); ret = kernel_bind(sock, (struct sockaddr *)&sin, addrlen); @@ -207,7 +206,6 @@ static void send_msg_members(struct super_block *sb, int type, u64 term, int only) { DECLARE_QUORUM_INFO(sb, qinf); - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; ktime_t now; int i; @@ -216,7 +214,7 @@ static void send_msg_members(struct super_block *sb, int type, u64 term, .fsid = super->hdr.fsid, .term = cpu_to_le64(term), .type = type, - .from = opts->quorum_slot_nr, + .from = qinf->our_quorum_slot_nr, }; struct kvec kv = { .iov_base = &qmes, @@ -238,7 +236,7 @@ static void send_msg_members(struct super_block *sb, int type, u64 term, for (i = 0; i < SCOUTFS_QUORUM_MAX_SLOTS; i++) { if (!quorum_slot_present(super, i) || - (only >= 0 && i != only) || i == opts->quorum_slot_nr) + (only >= 0 && i != only) || i == qinf->our_quorum_slot_nr) continue; scoutfs_quorum_slot_sin(super, i, &sin); @@ -476,8 +474,8 @@ static int write_quorum_block(struct super_block *sb, u64 blkno, struct scoutfs_ */ static int update_quorum_block(struct super_block *sb, int event, u64 term, bool check_rid) { - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; - u64 blkno = SCOUTFS_QUORUM_BLKNO + opts->quorum_slot_nr; + DECLARE_QUORUM_INFO(sb, qinf); + u64 blkno = SCOUTFS_QUORUM_BLKNO + qinf->our_quorum_slot_nr; struct scoutfs_quorum_block blk; int ret; @@ -622,7 +620,6 @@ static void scoutfs_quorum_worker(struct work_struct *work) { struct quorum_info *qinf = container_of(work, struct quorum_info, work); struct super_block *sb = qinf->sb; - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; struct sockaddr_in unused; struct quorum_host_msg msg; struct quorum_status qst; @@ -724,7 +721,7 @@ static void scoutfs_quorum_worker(struct work_struct *work) qst.term++; qst.vote_for = -1; qst.vote_bits = 0; - set_bit(opts->quorum_slot_nr, &qst.vote_bits); + set_bit(qinf->our_quorum_slot_nr, &qst.vote_bits); send_msg_others(sb, SCOUTFS_QUORUM_MSG_REQUEST_VOTE, qst.term); qst.timeout = election_timeout(); @@ -954,7 +951,6 @@ static ssize_t status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { DECLARE_QUORUM_INFO_KOBJ(kobj, qinf); - struct mount_options *opts = &SCOUTFS_SB(qinf->sb)->opts; struct quorum_status qst; struct last_msg last; struct timespec64 ts; @@ -971,7 +967,7 @@ static ssize_t status_show(struct kobject *kobj, struct kobj_attribute *attr, ret = 0; snprintf_ret(buf, size, &ret, "quorum_slot_nr %u\n", - opts->quorum_slot_nr); + qinf->our_quorum_slot_nr); snprintf_ret(buf, size, &ret, "term %llu\n", qst.term); snprintf_ret(buf, size, &ret, "role %d (%s)\n", @@ -1048,7 +1044,6 @@ static inline bool valid_ipv4_port(__be16 port) static int verify_quorum_slots(struct super_block *sb) { struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; char slots[(SCOUTFS_QUORUM_MAX_SLOTS * 3) + 1]; DECLARE_QUORUM_INFO(sb, qinf); struct sockaddr_in other; @@ -1099,7 +1094,7 @@ static int verify_quorum_slots(struct super_block *sb) return -EINVAL; } - if (!quorum_slot_present(super, opts->quorum_slot_nr)) { + if (!quorum_slot_present(super, qinf->our_quorum_slot_nr)) { char *str = slots; *str = '\0'; for (i = 0; i < SCOUTFS_QUORUM_MAX_SLOTS; i++) { @@ -1114,7 +1109,7 @@ static int verify_quorum_slots(struct super_block *sb) } } scoutfs_err(sb, "quorum_slot_nr=%u option references unused slot, must be one of the following configured slots:%s", - opts->quorum_slot_nr, slots); + qinf->our_quorum_slot_nr, slots); return -EINVAL; } @@ -1137,11 +1132,12 @@ static int verify_quorum_slots(struct super_block *sb) int scoutfs_quorum_setup(struct super_block *sb) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct mount_options *opts = &sbi->opts; + struct scoutfs_mount_options opts; struct quorum_info *qinf; int ret; - if (opts->quorum_slot_nr < 0) + scoutfs_options_read(sb, &opts); + if (opts.quorum_slot_nr < 0) return 0; qinf = kzalloc(sizeof(struct quorum_info), GFP_KERNEL); @@ -1153,6 +1149,8 @@ int scoutfs_quorum_setup(struct super_block *sb) spin_lock_init(&qinf->show_lock); INIT_WORK(&qinf->work, scoutfs_quorum_worker); scoutfs_sysfs_init_attrs(sb, &qinf->ssa); + /* static for the lifetime of the mount */ + qinf->our_quorum_slot_nr = opts.quorum_slot_nr; sbi->quorum_info = qinf; qinf->sb = sb; diff --git a/kmod/src/server.c b/kmod/src/server.c index 2b8221d7..2fcd316b 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -3842,8 +3842,8 @@ static void scoutfs_server_worker(struct work_struct *work) struct super_block *sb = server->sb; struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct scoutfs_super_block *super = &sbi->super; - struct mount_options *opts = &sbi->opts; struct scoutfs_net_connection *conn = NULL; + struct scoutfs_mount_options opts; DECLARE_WAIT_QUEUE_HEAD(waitq); struct sockaddr_in sin; bool alloc_init = false; @@ -3852,7 +3852,8 @@ static void scoutfs_server_worker(struct work_struct *work) trace_scoutfs_server_work_enter(sb, 0, 0); - scoutfs_quorum_slot_sin(super, opts->quorum_slot_nr, &sin); + scoutfs_options_read(sb, &opts); + scoutfs_quorum_slot_sin(super, opts.quorum_slot_nr, &sin); scoutfs_info(sb, "server starting at "SIN_FMT, SIN_ARG(&sin)); scoutfs_block_writer_init(sb, &server->wri); diff --git a/kmod/src/super.c b/kmod/src/super.c index 3302ad4f..5cac5148 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -132,44 +132,6 @@ out: return ret; } -static int scoutfs_show_options(struct seq_file *seq, struct dentry *root) -{ - struct super_block *sb = root->d_sb; - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; - - if (opts->quorum_slot_nr >= 0) - seq_printf(seq, ",quorum_slot_nr=%d", opts->quorum_slot_nr); - seq_printf(seq, ",metadev_path=%s", opts->metadev_path); - - return 0; -} - -static ssize_t metadev_path_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj); - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; - - return snprintf(buf, PAGE_SIZE, "%s", opts->metadev_path); -} -SCOUTFS_ATTR_RO(metadev_path); - -static ssize_t quorum_server_nr_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj); - struct mount_options *opts = &SCOUTFS_SB(sb)->opts; - - return snprintf(buf, PAGE_SIZE, "%d\n", opts->quorum_slot_nr); -} -SCOUTFS_ATTR_RO(quorum_server_nr); - -static struct attribute *mount_options_attrs[] = { - SCOUTFS_ATTR_PTR(metadev_path), - SCOUTFS_ATTR_PTR(quorum_server_nr), - NULL, -}; - static int scoutfs_sync_fs(struct super_block *sb, int wait) { trace_scoutfs_sync_fs(sb, wait); @@ -246,13 +208,11 @@ static void scoutfs_put_super(struct super_block *sb) scoutfs_destroy_triggers(sb); scoutfs_fence_destroy(sb); scoutfs_options_destroy(sb); - scoutfs_sysfs_destroy_attrs(sb, &sbi->mopts_ssa); debugfs_remove(sbi->debug_root); scoutfs_destroy_counters(sb); scoutfs_destroy_sysfs(sb); scoutfs_metadev_close(sb); - kfree(sbi->opts.metadev_path); kfree(sbi); sb->s_fs_info = NULL; @@ -282,7 +242,7 @@ static const struct super_operations scoutfs_super_ops = { .destroy_inode = scoutfs_destroy_inode, .sync_fs = scoutfs_sync_fs, .statfs = scoutfs_statfs, - .show_options = scoutfs_show_options, + .show_options = scoutfs_options_show, .put_super = scoutfs_put_super, .umount_begin = scoutfs_umount_begin, }; @@ -511,9 +471,9 @@ out: static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) { - struct scoutfs_sb_info *sbi; - struct mount_options opts; + struct scoutfs_mount_options opts; struct block_device *meta_bdev; + struct scoutfs_sb_info *sbi; struct inode *inode; int ret; @@ -541,13 +501,12 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) spin_lock_init(&sbi->next_ino_lock); spin_lock_init(&sbi->data_wait_root.lock); sbi->data_wait_root.root = RB_ROOT; - scoutfs_sysfs_init_attrs(sb, &sbi->mopts_ssa); - ret = scoutfs_parse_options(sb, data, &opts); - if (ret) - goto out; - - sbi->opts = opts; + /* parse options early for use during setup */ + ret = scoutfs_options_early_setup(sb, data); + if (ret < 0) + return ret; + scoutfs_options_read(sb, &opts); ret = sb_set_blocksize(sb, SCOUTFS_BLOCK_SM_SIZE); if (ret != SCOUTFS_BLOCK_SM_SIZE) { @@ -556,9 +515,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) goto out; } - meta_bdev = - blkdev_get_by_path(sbi->opts.metadev_path, - SCOUTFS_META_BDEV_MODE, sb); + meta_bdev = blkdev_get_by_path(opts.metadev_path, SCOUTFS_META_BDEV_MODE, sb); if (IS_ERR(meta_bdev)) { scoutfs_err(sb, "could not open metadev: error %ld", PTR_ERR(meta_bdev)); @@ -578,8 +535,6 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) scoutfs_setup_sysfs(sb) ?: scoutfs_setup_counters(sb) ?: scoutfs_options_setup(sb) ?: - scoutfs_sysfs_create_attrs(sb, &sbi->mopts_ssa, - mount_options_attrs, "mount_options") ?: scoutfs_setup_triggers(sb) ?: scoutfs_fence_setup(sb) ?: scoutfs_block_setup(sb) ?: @@ -652,6 +607,7 @@ static void scoutfs_kill_sb(struct super_block *sb) } if (SCOUTFS_HAS_SBI(sb)) { + scoutfs_options_stop(sb); scoutfs_inode_orphan_stop(sb); scoutfs_lock_unmount_begin(sb); } diff --git a/kmod/src/super.h b/kmod/src/super.h index 51c11722..3d3cd3d2 100644 --- a/kmod/src/super.h +++ b/kmod/src/super.h @@ -44,6 +44,7 @@ struct scoutfs_sb_info { spinlock_t next_ino_lock; + struct options_info *options_info; struct data_info *data_info; struct inode_sb_info *inode_sb_info; struct btree_info *btree_info; @@ -74,10 +75,6 @@ struct scoutfs_sb_info { struct scoutfs_counters *counters; struct scoutfs_triggers *triggers; - struct mount_options opts; - struct options_sb_info *options; - struct scoutfs_sysfs_attrs mopts_ssa; - struct dentry *debug_root; bool forced_unmount;