From 9e30cf74ce42de2d6672ec5150e764c581b855b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 12:16:01 +0100 Subject: [PATCH 1/8] core: add comment explaining ECOMM return value of unit_start() we explain all other return values, explain these ones too. --- src/core/unit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/unit.c b/src/core/unit.c index 185ec3f6a7a..4f89db02b65 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1730,6 +1730,7 @@ static bool unit_verify_deps(Unit *u) { * -EALREADY: Unit is already started. * -EAGAIN: An operation is already in progress. Retry later. * -ECANCELED: Too many requests for now. + * -ECOMM: Condition failed * -EPROTO: Assert failed * -EINVAL: Unit not loaded * -EOPNOTSUPP: Unit type not supported From 97a3f4ee052e1b8a0ff03accfa478e352891a84f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 12:21:27 +0100 Subject: [PATCH 2/8] core: rename unit_{start_limit|condition|assert}_test() to unit_test_xyz() Just some renaming, no change in behaviour. Background: I'd like to add more functions unit_test_xyz() that test various things, hence let's streamline the naming a bit. --- src/core/automount.c | 2 +- src/core/mount.c | 2 +- src/core/path.c | 2 +- src/core/service.c | 2 +- src/core/socket.c | 2 +- src/core/swap.c | 2 +- src/core/timer.c | 2 +- src/core/unit.c | 10 +++++----- src/core/unit.h | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/automount.c b/src/core/automount.c index 6a8373920ea..eff357bb3de 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -813,7 +813,7 @@ static int automount_start(Unit *u) { return -ENOENT; } - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/mount.c b/src/core/mount.c index 8da818beeee..a991bf8794d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1104,7 +1104,7 @@ static int mount_start(Unit *u) { assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED)); - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/path.c b/src/core/path.c index 831e49df29f..a7a7ec28aef 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -567,7 +567,7 @@ static int path_start(Unit *u) { return -ENOENT; } - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/service.c b/src/core/service.c index fc4e92389bb..bbe55322099 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2364,7 +2364,7 @@ static int service_start(Unit *u) { assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); /* Make sure we don't enter a busy loop of some kind. */ - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false); return r; diff --git a/src/core/socket.c b/src/core/socket.c index 3b60914c867..fd550290bea 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2487,7 +2487,7 @@ static int socket_start(Unit *u) { assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED)); - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/swap.c b/src/core/swap.c index 2d8463b8b18..b836fdd3046 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -871,7 +871,7 @@ static int swap_start(Unit *u) { if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING) return -EAGAIN; - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/timer.c b/src/core/timer.c index 0c1ca3ef233..736ffaa437a 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -607,7 +607,7 @@ static int timer_start(Unit *u) { return -ENOENT; } - r = unit_start_limit_test(u); + r = unit_test_start_limit(u); if (r < 0) { timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT); return r; diff --git a/src/core/unit.c b/src/core/unit.c index 4f89db02b65..9f75c976827 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1633,7 +1633,7 @@ static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to return triggered != 0; } -static bool unit_condition_test(Unit *u) { +static bool unit_test_condition(Unit *u) { assert(u); dual_timestamp_get(&u->condition_timestamp); @@ -1644,7 +1644,7 @@ static bool unit_condition_test(Unit *u) { return u->condition_result; } -static bool unit_assert_test(Unit *u) { +static bool unit_test_assert(Unit *u) { assert(u); dual_timestamp_get(&u->assert_timestamp); @@ -1667,7 +1667,7 @@ void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg REENABLE_WARNING; } -int unit_start_limit_test(Unit *u) { +int unit_test_start_limit(Unit *u) { const char *reason; assert(u); @@ -1764,14 +1764,14 @@ int unit_start(Unit *u) { * speed up activation in case there is some hold-off time, * but we don't want to recheck the condition in that case. */ if (state != UNIT_ACTIVATING && - !unit_condition_test(u)) { + !unit_test_condition(u)) { log_unit_debug(u, "Starting requested but condition failed. Not starting unit."); return -ECOMM; } /* If the asserts failed, fail the entire job */ if (state != UNIT_ACTIVATING && - !unit_assert_test(u)) { + !unit_test_assert(u)) { log_unit_notice(u, "Starting requested but asserts failed."); return -EPROTO; } diff --git a/src/core/unit.h b/src/core/unit.h index 90d5e6f49db..8c67676c8ae 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -778,7 +778,7 @@ static inline bool unit_supported(Unit *u) { void unit_warn_if_dir_nonempty(Unit *u, const char* where); int unit_fail_if_noncanonical(Unit *u, const char* where); -int unit_start_limit_test(Unit *u); +int unit_test_start_limit(Unit *u); void unit_unref_uid(Unit *u, bool destroy_now); int unit_ref_uid(Unit *u, uid_t uid, bool clean_ipc); From a4191c9fb5fc473f8e4d1d32fec08efd8a2217d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 12:29:08 +0100 Subject: [PATCH 3/8] core: unify code for checking whether unit to trigger is loaded --- src/core/automount.c | 9 +++------ src/core/path.c | 9 +++------ src/core/timer.c | 9 +++------ src/core/unit.c | 15 +++++++++++++++ src/core/unit.h | 2 ++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/core/automount.c b/src/core/automount.c index eff357bb3de..8ffdad18c70 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -796,7 +796,6 @@ fail: static int automount_start(Unit *u) { Automount *a = AUTOMOUNT(u); - Unit *trigger; int r; assert(a); @@ -807,11 +806,9 @@ static int automount_start(Unit *u) { return -EEXIST; } - trigger = UNIT_TRIGGER(u); - if (!trigger || trigger->load_state != UNIT_LOADED) { - log_unit_error(u, "Refusing to start, unit to trigger not loaded."); - return -ENOENT; - } + r = unit_test_trigger_loaded(u); + if (r < 0) + return r; r = unit_test_start_limit(u); if (r < 0) { diff --git a/src/core/path.c b/src/core/path.c index a7a7ec28aef..3fe14ef2bcf 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -555,17 +555,14 @@ static void path_mkdir(Path *p) { static int path_start(Unit *u) { Path *p = PATH(u); - Unit *trigger; int r; assert(p); assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED)); - trigger = UNIT_TRIGGER(u); - if (!trigger || trigger->load_state != UNIT_LOADED) { - log_unit_error(u, "Refusing to start, unit to trigger not loaded."); - return -ENOENT; - } + r = unit_test_trigger_loaded(u); + if (r < 0) + return r; r = unit_test_start_limit(u); if (r < 0) { diff --git a/src/core/timer.c b/src/core/timer.c index 736ffaa437a..d1e351c30dc 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -595,17 +595,14 @@ fail: static int timer_start(Unit *u) { Timer *t = TIMER(u); TimerValue *v; - Unit *trigger; int r; assert(t); assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED)); - trigger = UNIT_TRIGGER(u); - if (!trigger || trigger->load_state != UNIT_LOADED) { - log_unit_error(u, "Refusing to start, unit to trigger not loaded."); - return -ENOENT; - } + r = unit_test_trigger_loaded(u); + if (r < 0) + return r; r = unit_test_start_limit(u); if (r < 0) { diff --git a/src/core/unit.c b/src/core/unit.c index 9f75c976827..8a599a571c2 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1736,6 +1736,7 @@ static bool unit_verify_deps(Unit *u) { * -EOPNOTSUPP: Unit type not supported * -ENOLINK: The necessary dependencies are not fulfilled. * -ESTALE: This unit has been started before and can't be started a second time + * -ENOENT: This is a triggering unit and unit to trigger is not loaded */ int unit_start(Unit *u) { UnitActiveState state; @@ -5590,6 +5591,20 @@ int unit_success_action_exit_status(Unit *u) { return r; } +int unit_test_trigger_loaded(Unit *u) { + Unit *trigger; + + /* Tests whether the unit to trigger is loaded */ + + trigger = UNIT_TRIGGER(u); + if (!trigger) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Refusing to start, unit to trigger not loaded."); + if (trigger->load_state != UNIT_LOADED) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Refusing to start, unit %s to trigger not loaded.", u->id); + + return 0; +} + static const char* const collect_mode_table[_COLLECT_MODE_MAX] = { [COLLECT_INACTIVE] = "inactive", [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", diff --git a/src/core/unit.h b/src/core/unit.h index 8c67676c8ae..35b936771c9 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -830,6 +830,8 @@ int unit_exit_status(Unit *u); int unit_success_action_exit_status(Unit *u); int unit_failure_action_exit_status(Unit *u); +int unit_test_trigger_loaded(Unit *u); + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ From 5766aca8d2e52c9c27f5c0486cdaa049bb743371 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 12:36:03 +0100 Subject: [PATCH 4/8] core: modernize unit_start() a bit No change in behaviour, just a re-line-breaking of the various comments to our current coding style, and some use of SYNTHETIC_ERRNO(). --- src/core/unit.c | 48 +++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/core/unit.c b/src/core/unit.c index 8a599a571c2..d4060a7267e 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1744,10 +1744,9 @@ int unit_start(Unit *u) { assert(u); - /* If this is already started, then this will succeed. Note - * that this will even succeed if this unit is not startable - * by the user. This is relied on to detect when we need to - * wait for units and when waiting is finished. */ + /* If this is already started, then this will succeed. Note that this will even succeed if this unit + * is not startable by the user. This is relied on to detect when we need to wait for units and when + * waiting is finished. */ state = unit_active_state(u); if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; @@ -1760,35 +1759,28 @@ int unit_start(Unit *u) { if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_enter_timestamp)) return -ESTALE; - /* If the conditions failed, don't do anything at all. If we - * already are activating this call might still be useful to - * speed up activation in case there is some hold-off time, - * but we don't want to recheck the condition in that case. */ + /* If the conditions failed, don't do anything at all. If we already are activating this call might + * still be useful to speed up activation in case there is some hold-off time, but we don't want to + * recheck the condition in that case. */ if (state != UNIT_ACTIVATING && - !unit_test_condition(u)) { - log_unit_debug(u, "Starting requested but condition failed. Not starting unit."); - return -ECOMM; - } + !unit_test_condition(u)) + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(ECOMM), "Starting requested but condition failed. Not starting unit."); /* If the asserts failed, fail the entire job */ if (state != UNIT_ACTIVATING && - !unit_test_assert(u)) { - log_unit_notice(u, "Starting requested but asserts failed."); - return -EPROTO; - } + !unit_test_assert(u)) + return log_unit_notice_errno(u, SYNTHETIC_ERRNO(EPROTO), "Starting requested but asserts failed."); - /* Units of types that aren't supported cannot be - * started. Note that we do this test only after the condition - * checks, so that we rather return condition check errors - * (which are usually not considered a true failure) than "not - * supported" errors (which are considered a failure). + /* Units of types that aren't supported cannot be started. Note that we do this test only after the + * condition checks, so that we rather return condition check errors (which are usually not + * considered a true failure) than "not supported" errors (which are considered a failure). */ if (!unit_supported(u)) return -EOPNOTSUPP; - /* Let's make sure that the deps really are in order before we start this. Normally the job engine should have - * taken care of this already, but let's check this here again. After all, our dependencies might not be in - * effect anymore, due to a reload or due to a failed condition. */ + /* Let's make sure that the deps really are in order before we start this. Normally the job engine + * should have taken care of this already, but let's check this here again. After all, our + * dependencies might not be in effect anymore, due to a reload or due to a failed condition. */ if (!unit_verify_deps(u)) return -ENOLINK; @@ -1803,11 +1795,9 @@ int unit_start(Unit *u) { if (!UNIT_VTABLE(u)->start) return -EBADR; - /* We don't suppress calls to ->start() here when we are - * already starting, to allow this request to be used as a - * "hurry up" call, for example when the unit is in some "auto - * restart" state where it waits for a holdoff timer to elapse - * before it will start again. */ + /* We don't suppress calls to ->start() here when we are already starting, to allow this request to + * be used as a "hurry up" call, for example when the unit is in some "auto restart" state where it + * waits for a holdoff timer to elapse before it will start again. */ unit_add_to_dbus_queue(u); From 2de9b9793b91f492141f090dcc89445511e94bd4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 13:14:19 +0100 Subject: [PATCH 5/8] core: check start limit on condition checks too Let's add a safety precaution: if the start condition checks for a unit are tested too often and fail each time, let's rate limit this too. This should add extra safety in case people define .path, .timer or .automount units that trigger a service that as a conditoin that always fails. --- src/core/unit.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core/unit.c b/src/core/unit.c index d4060a7267e..96b520f3d1c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1729,7 +1729,7 @@ static bool unit_verify_deps(Unit *u) { * -EBADR: This unit type does not support starting. * -EALREADY: Unit is already started. * -EAGAIN: An operation is already in progress. Retry later. - * -ECANCELED: Too many requests for now. + * -ECANCELED: Start limit hit, too many requests for now * -ECOMM: Condition failed * -EPROTO: Assert failed * -EINVAL: Unit not loaded @@ -1741,6 +1741,7 @@ static bool unit_verify_deps(Unit *u) { int unit_start(Unit *u) { UnitActiveState state; Unit *following; + int r; assert(u); @@ -1763,8 +1764,25 @@ int unit_start(Unit *u) { * still be useful to speed up activation in case there is some hold-off time, but we don't want to * recheck the condition in that case. */ if (state != UNIT_ACTIVATING && - !unit_test_condition(u)) + !unit_test_condition(u)) { + + /* Let's also check the start limit here. Normally, the start limit is only checked by the + * .start() method of the unit type after it did some additional checks verifying everything + * is in order (so that those other checks can propagate errors properly). However, if a + * condition check doesn't hold we don't get that far but we should still ensure we are not + * called in a tight loop without a rate limit check enforced, hence do the check here. Note + * that ECOMM is generally not a reason for a job to fail, unlike most other errors here, + * hence the chance is big that any triggering unit for us will trigger us again. Note this + * condition check is a bit different from the condition check inside the per-unit .start() + * function, as this one will not change the unit's state in any way (and we shouldn't here, + * after all the condition failed). */ + + r = unit_test_start_limit(u); + if (r < 0) + return r; + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(ECOMM), "Starting requested but condition failed. Not starting unit."); + } /* If the asserts failed, fail the entire job */ if (state != UNIT_ACTIVATING && From 36c4dc089e21e731e7ff5519aa6c636dd55e30e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 13:20:54 +0100 Subject: [PATCH 6/8] core: change emergency_action() to return void The function so far always returned -ECANCELLED, which is ignored in all cases the function is invoked, except one: in unit_test_start_limit() where -ECANCELLED is returned when the start limit is hit, which is part of unit_start()'s protocol of return values. Since the emergency_action() logic should be relatively generic and is used in many places, let's drop the return value from it, since it's constant anyway, and in alll cases useless. Instead, let's return it in unit_test_start_limit(), where it's part of the protocol. No change in behaviour. --- src/core/emergency-action.c | 8 +++----- src/core/emergency-action.h | 6 +++--- src/core/unit.c | 12 +++++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index f98b0de7925..9731aef5c44 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -20,7 +20,7 @@ static void log_and_status(Manager *m, bool warn, const char *message, const cha "%s: %s", message, reason); } -int emergency_action( +void emergency_action( Manager *m, EmergencyAction action, EmergencyActionFlags options, @@ -33,11 +33,11 @@ int emergency_action( assert(action < _EMERGENCY_ACTION_MAX); if (action == EMERGENCY_ACTION_NONE) - return -ECANCELED; + return; if (FLAGS_SET(options, EMERGENCY_ACTION_IS_WATCHDOG) && !m->service_watchdogs) { log_warning("Watchdog disabled! Not acting on: %s", reason); - return -ECANCELED; + return; } bool warn = FLAGS_SET(options, EMERGENCY_ACTION_WARN); @@ -125,8 +125,6 @@ int emergency_action( default: assert_not_reached("Unknown emergency action"); } - - return -ECANCELED; } static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h index 6e6c69ddfcb..706c38a7d74 100644 --- a/src/core/emergency-action.h +++ b/src/core/emergency-action.h @@ -24,9 +24,9 @@ typedef enum EmergencyActionFlags { #include "macro.h" #include "manager.h" -int emergency_action(Manager *m, - EmergencyAction action, EmergencyActionFlags options, - const char *reboot_arg, int exit_status, const char *reason); +void emergency_action(Manager *m, + EmergencyAction action, EmergencyActionFlags options, + const char *reboot_arg, int exit_status, const char *reason); const char* emergency_action_to_string(EmergencyAction i) _const_; EmergencyAction emergency_action_from_string(const char *s) _pure_; diff --git a/src/core/unit.c b/src/core/unit.c index 96b520f3d1c..1ce7ceb3e1c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1682,9 +1682,11 @@ int unit_test_start_limit(Unit *u) { reason = strjoina("unit ", u->id, " failed"); - return emergency_action(u->manager, u->start_limit_action, - EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN, - u->reboot_arg, -1, reason); + emergency_action(u->manager, u->start_limit_action, + EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN, + u->reboot_arg, -1, reason); + + return -ECANCELED; } bool unit_shall_confirm_spawn(Unit *u) { @@ -2511,10 +2513,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag if (os != UNIT_FAILED && ns == UNIT_FAILED) { reason = strjoina("unit ", u->id, " failed"); - (void) emergency_action(m, u->failure_action, 0, u->reboot_arg, unit_failure_action_exit_status(u), reason); + emergency_action(m, u->failure_action, 0, u->reboot_arg, unit_failure_action_exit_status(u), reason); } else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && ns == UNIT_INACTIVE) { reason = strjoina("unit ", u->id, " succeeded"); - (void) emergency_action(m, u->success_action, 0, u->reboot_arg, unit_success_action_exit_status(u), reason); + emergency_action(m, u->success_action, 0, u->reboot_arg, unit_success_action_exit_status(u), reason); } } From 9adb695987dbf5a147d62e12b8f107223643f9ce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 13:28:59 +0100 Subject: [PATCH 7/8] core: split error list in comment for unit_start() in two --- src/core/unit.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/unit.c b/src/core/unit.c index 1ce7ceb3e1c..445cf6695c8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1727,12 +1727,14 @@ static bool unit_verify_deps(Unit *u) { return true; } -/* Errors: - * -EBADR: This unit type does not support starting. +/* Errors that aren't really errors: * -EALREADY: Unit is already started. - * -EAGAIN: An operation is already in progress. Retry later. - * -ECANCELED: Start limit hit, too many requests for now * -ECOMM: Condition failed + * -EAGAIN: An operation is already in progress. Retry later. + * + * Errors that are real errors: + * -EBADR: This unit type does not support starting. + * -ECANCELED: Start limit hit, too many requests for now * -EPROTO: Assert failed * -EINVAL: Unit not loaded * -EOPNOTSUPP: Unit type not supported From 0f6e58f63780a261e4723dec9e13a94f8e991f06 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 16:06:14 +0100 Subject: [PATCH 8/8] hwdb: fix trailing newline issue --- hwdb/60-sensor.hwdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hwdb/60-sensor.hwdb b/hwdb/60-sensor.hwdb index 8b1665a5359..26e51ce6651 100644 --- a/hwdb/60-sensor.hwdb +++ b/hwdb/60-sensor.hwdb @@ -70,7 +70,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-012* sensor:modalias:acpi:BMA250E*:dmi:*:svnAcer:pnIconiaW1-810:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 - + sensor:modalias:acpi:SMO8500:*:dmi:*Acer*:pnOneS1002* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1