aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/core.c
diff options
context:
space:
mode:
authorMiroslav Benes <mbenes@suse.cz>2017-11-22 05:29:21 -0500
committerJiri Kosina <jkosina@suse.cz>2017-12-07 07:21:35 -0500
commitc99a2be790b07752d8cc694434d3450afd4c5a00 (patch)
tree086f38cd5bae5145e4677c552a8776990f12c2fb /kernel/livepatch/core.c
parent43347d56c8d9dd732cee2f8efd384ad21dd1f6c4 (diff)
livepatch: force transition to finish
If a task sleeps in a set of patched functions uninterruptedly, it could block the whole transition indefinitely. Thus it may be useful to clear its TIF_PATCH_PENDING to allow the process to finish. Admin can do that now by writing to force sysfs attribute in livepatch sysfs directory. TIF_PATCH_PENDING is then cleared for all tasks and the transition can finish successfully. Important note! Administrator should not use this feature without a clearance from a patch distributor. It must be checked that by doing so the consistency model guarantees are not violated. Removal (rmmod) of patch modules is permanently disabled when the feature is used. It cannot be guaranteed there is no task sleeping in such module. Signed-off-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r--kernel/livepatch/core.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 88766bd91803..1c3c9b27c916 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -455,6 +455,7 @@ EXPORT_SYMBOL_GPL(klp_enable_patch);
455 * /sys/kernel/livepatch/<patch>/enabled 455 * /sys/kernel/livepatch/<patch>/enabled
456 * /sys/kernel/livepatch/<patch>/transition 456 * /sys/kernel/livepatch/<patch>/transition
457 * /sys/kernel/livepatch/<patch>/signal 457 * /sys/kernel/livepatch/<patch>/signal
458 * /sys/kernel/livepatch/<patch>/force
458 * /sys/kernel/livepatch/<patch>/<object> 459 * /sys/kernel/livepatch/<patch>/<object>
459 * /sys/kernel/livepatch/<patch>/<object>/<function,sympos> 460 * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
460 */ 461 */
@@ -556,13 +557,42 @@ static ssize_t signal_store(struct kobject *kobj, struct kobj_attribute *attr,
556 return count; 557 return count;
557} 558}
558 559
560static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
561 const char *buf, size_t count)
562{
563 struct klp_patch *patch;
564 int ret;
565 bool val;
566
567 patch = container_of(kobj, struct klp_patch, kobj);
568
569 /*
570 * klp_mutex lock is not grabbed here intentionally. It is not really
571 * needed. The race window is harmless and grabbing the lock would only
572 * hold the action back.
573 */
574 if (patch != klp_transition_patch)
575 return -EINVAL;
576
577 ret = kstrtobool(buf, &val);
578 if (ret)
579 return ret;
580
581 if (val)
582 klp_force_transition();
583
584 return count;
585}
586
559static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled); 587static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
560static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition); 588static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
561static struct kobj_attribute signal_kobj_attr = __ATTR_WO(signal); 589static struct kobj_attribute signal_kobj_attr = __ATTR_WO(signal);
590static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
562static struct attribute *klp_patch_attrs[] = { 591static struct attribute *klp_patch_attrs[] = {
563 &enabled_kobj_attr.attr, 592 &enabled_kobj_attr.attr,
564 &transition_kobj_attr.attr, 593 &transition_kobj_attr.attr,
565 &signal_kobj_attr.attr, 594 &signal_kobj_attr.attr,
595 &force_kobj_attr.attr,
566 NULL 596 NULL
567}; 597};
568 598