rfkill: Delay writes until exit (#5768) #5815

Merged
merged 2 commits into from Sep 4, 2017

Conversation

Projects
None yet
2 participants
Contributor

benzea commented Apr 26, 2017

On thinkpads there are two rfkill devices for bluetooth. The first is an
ACPI switch which powers down the USB dongle and the second one is the
USB dongle itself. So when userspace decides to enable rfkill on all
devices systemd would randomly save the soft block state of the USB
dongle. This later causes issue when re-enabling the devie as
systemd-rfkill would put the USB dongle into soft block state right
after the ACPI rfkill switch is unblocked by userspace.

The simple way to avoid this is to not store rfkill changes for devices
that disappear shortly after. That way only the "main" ACPI switch will
get stored and systemd-rfkill will not end up blocking the device right
after it is being added back again.

Looks really good, just some comments

src/rfkill/rfkill.c
+ int state;
+} write_queue_item;
+
+static LIST_HEAD(write_queue_item, write_queue);
@poettering

poettering Aug 31, 2017

Owner

no, unnecessary global variables please. Doesn't matter much, but I think it would be nicer to avoid this, and just make it a local varibale of main() or so, which is passed through as pointer... dunno.

src/rfkill/rfkill.c
+
+static LIST_HEAD(write_queue_item, write_queue);
+
+
@poettering

poettering Aug 31, 2017

Owner

spurious double newline,

- return r;
-
- r = determine_state_file(udev, event, device, &state_file);
+ r = determine_state_file(udev, event, &state_file);
@poettering

poettering Aug 31, 2017

Owner

maybe split out this little rearrangement in a separete commit in this PR? (doesn't matter though, it's fine this way, too)

src/rfkill/rfkill.c
+ struct write_queue_item *item, *tmp;
+
+ LIST_FOREACH_SAFE(queue, item, tmp, write_queue) {
+ if ((state_file && strcmp(item->file, state_file) == 0) || idx == item->rfkill_idx) {
@poettering

poettering Aug 31, 2017

Owner

nitpick: we prefer streq() over strcmp() == 0 in systemd sources, see CODING_STYLE.

src/rfkill/rfkill.c
+ log_debug("Canceled previous save state of '%s' to %s.", one_zero(item->state), item->file);
+ LIST_REMOVE(queue, write_queue, item);
+ free(item->file);
+ mfree(item);
@poettering

poettering Aug 31, 2017

Owner

no need to use mfree() if you don't care about its return value... the whole reason mfree() exists, is so that you can write:

p = mfree(p);

and that frees p and also assigns NULL to it...

src/rfkill/rfkill.c
+ }
+}
+
+
@poettering

poettering Aug 31, 2017

Owner

nitpick: spurious double newline

src/rfkill/rfkill.c
+ r = write_string_file(item->file, one_zero(item->state), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0) {
+ result = r;
+ log_error_errno(r, "Failed to write state file %s: %m", item->file);
@poettering

poettering Aug 31, 2017

Owner

if you continue the loop on error, then the error message should be downgraded to warning i figure...

src/rfkill/rfkill.c
+ log_error_errno(r, "Failed to write state file %s: %m", item->file);
+ }
+
+ log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
@poettering

poettering Aug 31, 2017

Owner

this log line should probably only be shown, if the if block above doesn't apply.. i.e. you probably want an else line there

src/rfkill/rfkill.c
+ log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
+ LIST_REMOVE(queue, write_queue, item);
+ free(item->file);
+ mfree(item);
@poettering

poettering Aug 31, 2017

Owner

mfree() → free() if you don't care for the return value

Owner

poettering commented Aug 31, 2017

And I am very sorry for not looking into this any earlier! Somehow it escaped me for too long. Sorry!

rfkill: Lookup device in determine_state_file
None of the callers actually need the device itself. So it makes sense
to do the lookup inside determine_state_file instead.
Contributor

benzea commented Aug 31, 2017

Whoops, should have tested before pushing and not after (passed the list head in the wrong manner at first). I think I have addressed everything you mentioned.

Thanks for the review. I actually kind of forgot to ping you myself.

looks excellent, just two more nits

src/rfkill/rfkill.c
+ log_debug("Canceled previous save state of '%s' to %s.", one_zero(item->state), item->file);
+ LIST_REMOVE(queue, *write_queue, item);
+ free(item->file);
+ free(item);
@poettering

poettering Aug 31, 2017

Owner

sorry I missed this on the first review, but I think we should probably have a destructor of some kind for this, i.e. write_queue_item_unlink() or so, that does the three steps above... after all, we have the very same three lines further down again, and we can share that then, and make it more readable

src/rfkill/rfkill.c
+ error_logged = true;
+ } else {
+ log_warning_errno(r, "Failed to write state file %s: %m", item->file);
+ }
@poettering

poettering Aug 31, 2017

Owner

nitpick: no {} around single-line if blocks

src/rfkill/rfkill.c
+ }
+ } else {
+ log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
+ }
rfkill: Delay writes until exit (#5768)
On thinkpads there are two rfkill devices for bluetooth. The first is an
ACPI switch which powers down the USB dongle and the second one is the
USB dongle itself. So when userspace decides to enable rfkill on all
devices systemd would randomly save the soft block state of the USB
dongle. This later causes issue when re-enabling the devie as
systemd-rfkill would put the USB dongle into soft block state right
after the ACPI rfkill switch is unblocked by userspace.

The simple way to avoid this is to not store rfkill changes for devices
that disappear shortly after. That way only the "main" ACPI switch will
get stored and systemd-rfkill will not end up blocking the device right
after it is being added back again.

@poettering poettering merged commit d398cf4 into systemd:master Sep 4, 2017

1 of 4 checks passed

xenial-amd64 autopkgtest finished (failure)
Details
xenial-i386 autopkgtest finished (failure)
Details
xenial-s390x autopkgtest finished (failure)
Details
semaphoreci The build passed on Semaphore.
Details
Contributor

benzea commented Sep 5, 2017

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment