From 9ed34f8892c0c8f485311967adc2ec7fd7ce0819 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 18 Dec 2017 11:29:02 -0800 Subject: [PATCH] scoutfs: add triggers Signed-off-by: Zach Brown --- kmod/src/Makefile | 2 +- kmod/src/super.c | 3 ++ kmod/src/super.h | 2 + kmod/src/triggers.c | 118 ++++++++++++++++++++++++++++++++++++++++++++ kmod/src/triggers.h | 17 +++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 kmod/src/triggers.c create mode 100644 kmod/src/triggers.h diff --git a/kmod/src/Makefile b/kmod/src/Makefile index ed9bdcbe..ad177eb2 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -9,7 +9,7 @@ scoutfs-y += alloc.o bio.o btree.o client.o compact.o counters.o data.o dir.o \ dlmglue.o file.o kvec.o inode.o ioctl.o item.o key.o lock.o \ manifest.o msg.o options.o per_task.o seg.o server.o \ scoutfs_trace.o sock.o sort_priv.o stackglue.o super.o trans.o \ - xattr.o + triggers.o xattr.o # # The raw types aren't available in userspace headers. Make sure all diff --git a/kmod/src/super.c b/kmod/src/super.c index b4f14aa6..6c12f59b 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -28,6 +28,7 @@ #include "xattr.h" #include "msg.h" #include "counters.h" +#include "triggers.h" #include "trans.h" #include "item.h" #include "manifest.h" @@ -125,6 +126,7 @@ static void scoutfs_put_super(struct super_block *sb) scoutfs_seg_destroy(sb); scoutfs_lock_destroy(sb); + scoutfs_destroy_triggers(sb); debugfs_remove(sbi->debug_root); scoutfs_destroy_counters(sb); if (sbi->kset) @@ -324,6 +326,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) ret = scoutfs_setup_counters(sb) ?: scoutfs_read_supers(sb, &SCOUTFS_SB(sb)->super) ?: scoutfs_debugfs_setup(sb) ?: + scoutfs_setup_triggers(sb) ?: scoutfs_seg_setup(sb) ?: scoutfs_item_setup(sb) ?: scoutfs_inode_setup(sb) ?: diff --git a/kmod/src/super.h b/kmod/src/super.h index e09ac9d5..0955d722 100644 --- a/kmod/src/super.h +++ b/kmod/src/super.h @@ -8,6 +8,7 @@ #include "options.h" struct scoutfs_counters; +struct scoutfs_triggers; struct item_cache; struct manifest; struct segment_cache; @@ -61,6 +62,7 @@ struct scoutfs_sb_info { struct kset *kset; struct scoutfs_counters *counters; + struct scoutfs_triggers *triggers; struct mount_options opts; diff --git a/kmod/src/triggers.c b/kmod/src/triggers.c new file mode 100644 index 00000000..64f83941 --- /dev/null +++ b/kmod/src/triggers.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017 Versity Software, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include +#include +#include + +#include "super.h" +#include "triggers.h" + +/* + * We have debugfs files we can write to which arm triggers which + * atomically fire once for testing or debugging. + */ + +/* + * The atomic cachelines are kept hot and shared by being read by fast + * paths. They're very rarely modified by debugfs writes which arm them + * and then the next read will atomically clear and return true. + */ +struct scoutfs_triggers { + struct dentry *dir; + atomic_t atomics[SCOUTFS_TRIGGER_NR]; +}; + +#define DECLARE_TRIGGERS(sb, name) \ + struct scoutfs_triggers *name = SCOUTFS_SB(sb)->triggers + +static char *names[] = { + [SCOUTFS_TRIGGER_SOMETHING] = "something", +}; + +bool scoutfs_trigger_test_and_clear(struct super_block *sb, unsigned int t) +{ + DECLARE_TRIGGERS(sb, triggers); + atomic_t *atom; + int old; + int mem; + + BUG_ON(t >= SCOUTFS_TRIGGER_NR); + atom = &triggers->atomics[t]; + + mem = atomic_read(atom); + if (likely(!mem)) + return 0; + + do { + old = mem; + mem = atomic_cmpxchg(atom, old, 0); + } while (mem && mem != old); + + return !!mem; +} + +int scoutfs_setup_triggers(struct super_block *sb) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct scoutfs_triggers *triggers; + int ret; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(names) != SCOUTFS_TRIGGER_NR); + + for (i = 0; i < ARRAY_SIZE(names); i++) { + if (WARN_ON(!names[i])) + return -EINVAL; + } + + triggers = kzalloc(sizeof(struct scoutfs_triggers), GFP_KERNEL); + if (!triggers) + return -ENOMEM; + + sbi->triggers = triggers; + + triggers->dir = debugfs_create_dir("trigger", sbi->debug_root); + if (!triggers->dir) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(triggers->atomics); i++) { + if (!debugfs_create_atomic_t(names[i], 0644, triggers->dir, + &triggers->atomics[i])) { + ret = -ENOMEM; + goto out; + } + } + + ret = 0; +out: + if (ret) + scoutfs_destroy_triggers(sb); + return ret; +} + +void scoutfs_destroy_triggers(struct super_block *sb) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct scoutfs_triggers *triggers = sbi->triggers; + + if (triggers) { + if (triggers->dir) + debugfs_remove_recursive(triggers->dir); + kfree(triggers); + sbi->triggers = NULL; + } +} diff --git a/kmod/src/triggers.h b/kmod/src/triggers.h new file mode 100644 index 00000000..48920844 --- /dev/null +++ b/kmod/src/triggers.h @@ -0,0 +1,17 @@ +#ifndef _SCOUTFS_TRIGGERS_H_ +#define _SCOUTFS_TRIGGERS_H_ + +enum { + SCOUTFS_TRIGGER_SOMETHING, + SCOUTFS_TRIGGER_NR, +}; + +bool scoutfs_trigger_test_and_clear(struct super_block *sb, unsigned int t); + +#define scoutfs_trigger(sb, which) \ + scoutfs_trigger_test_and_clear(sb, SCOUTFS_TRIGGER_##which) + +int scoutfs_setup_triggers(struct super_block *sb); +void scoutfs_destroy_triggers(struct super_block *sb); + +#endif