X Tutup
Skip to content

Commit f8e07c5

Browse files
authored
Merge pull request systemd#22871 from yuwata/udev-worker-error-code
udev: append error code on failure
2 parents a6ea4dc + 10176f0 commit f8e07c5

File tree

4 files changed

+98
-24
lines changed

4 files changed

+98
-24
lines changed

src/libsystemd/sd-device/device-private.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ int device_add_property(sd_device *device, const char *key, const char *value) {
4747
return 0;
4848
}
4949

50+
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) {
51+
_cleanup_free_ char *value = NULL;
52+
va_list ap;
53+
int r;
54+
55+
assert(device);
56+
assert(key);
57+
58+
if (!format)
59+
return device_add_property(device, key, NULL);
60+
61+
va_start(ap, format);
62+
r = vasprintf(&value, format, ap);
63+
va_end(ap);
64+
65+
if (r < 0)
66+
return -ENOMEM;
67+
68+
return device_add_property(device, key, value);
69+
}
70+
5071
void device_set_devlink_priority(sd_device *device, int priority) {
5172
assert(device);
5273

src/libsystemd/sd-device/device-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
3636
int device_add_devlink(sd_device *device, const char *devlink);
3737
bool device_has_devlink(sd_device *device, const char *devlink);
3838
int device_add_property(sd_device *device, const char *property, const char *value);
39+
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
3940
int device_add_tag(sd_device *device, const char *tag, bool both);
4041
void device_remove_tag(sd_device *device, const char *tag);
4142
void device_cleanup_tags(sd_device *device);

src/udev/udevd.c

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "device-monitor-private.h"
3636
#include "device-private.h"
3737
#include "device-util.h"
38+
#include "errno-list.h"
3839
#include "event-util.h"
3940
#include "fd-util.h"
4041
#include "fileio.h"
@@ -157,11 +158,15 @@ typedef struct Worker {
157158

158159
/* passed from worker to main process */
159160
typedef enum EventResult {
160-
EVENT_RESULT_SUCCESS,
161-
EVENT_RESULT_FAILED,
162-
EVENT_RESULT_TRY_AGAIN, /* when the block device is locked by another process. */
161+
EVENT_RESULT_NERRNO_MIN = -ERRNO_MAX,
162+
EVENT_RESULT_NERRNO_MAX = -1,
163+
EVENT_RESULT_EXIT_STATUS_BASE = 0,
164+
EVENT_RESULT_EXIT_STATUS_MAX = 255,
165+
EVENT_RESULT_TRY_AGAIN = 256, /* when the block device is locked by another process. */
166+
EVENT_RESULT_SIGNAL_BASE = 257,
167+
EVENT_RESULT_SIGNAL_MAX = EVENT_RESULT_SIGNAL_BASE + _NSIG,
163168
_EVENT_RESULT_MAX,
164-
_EVENT_RESULT_INVALID = -EINVAL,
169+
_EVENT_RESULT_INVALID = -EINVAL,
165170
} EventResult;
166171

167172
static Event *event_free(Event *event) {
@@ -356,7 +361,7 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda
356361
return 1;
357362
}
358363

359-
static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
364+
static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, int result) {
360365
int r;
361366

362367
assert(dev);
@@ -365,13 +370,40 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
365370
if (!monitor)
366371
return;
367372

373+
if (result != 0) {
374+
(void) device_add_property(dev, "UDEV_WORKER_FAILED", "1");
375+
376+
switch (result) {
377+
case EVENT_RESULT_NERRNO_MIN ... EVENT_RESULT_NERRNO_MAX:
378+
(void) device_add_propertyf(dev, "UDEV_WORKER_ERRNO", "%i", -result);
379+
(void) device_add_propertyf(dev, "UDEV_WORKER_ERRNO_NAME", "%s", strna(errno_to_name(result)));
380+
break;
381+
382+
case EVENT_RESULT_EXIT_STATUS_BASE ... EVENT_RESULT_EXIT_STATUS_MAX:
383+
(void) device_add_propertyf(dev, "UDEV_WORKER_EXIT_STATUS", "%i", result - EVENT_RESULT_EXIT_STATUS_BASE);
384+
break;
385+
386+
case EVENT_RESULT_TRY_AGAIN:
387+
assert_not_reached();
388+
break;
389+
390+
case EVENT_RESULT_SIGNAL_BASE ... EVENT_RESULT_SIGNAL_MAX:
391+
(void) device_add_propertyf(dev, "UDEV_WORKER_SIGNAL", "%i", result - EVENT_RESULT_SIGNAL_BASE);
392+
(void) device_add_propertyf(dev, "UDEV_WORKER_SIGNAL_NAME", "%s", strna(signal_to_string(result - EVENT_RESULT_SIGNAL_BASE)));
393+
break;
394+
395+
default:
396+
log_device_warning(dev, "Unknown event result \"%i\", ignoring.", result);
397+
}
398+
}
399+
368400
r = device_monitor_send_device(monitor, NULL, dev);
369401
if (r < 0)
370402
log_device_warning_errno(dev, r,
371403
"Failed to broadcast event to libudev listeners, ignoring: %m");
372404
}
373405

374-
static int worker_send_result(Manager *manager, EventResult result) {
406+
static int worker_send_result(Manager *manager, int result) {
375407
assert(manager);
376408
assert(manager->worker_watch[WRITE_END] >= 0);
377409

@@ -536,6 +568,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
536568
*
537569
* The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING */
538570
r = worker_lock_block_device(dev, &fd_lock);
571+
if (r == -EAGAIN)
572+
return EVENT_RESULT_TRY_AGAIN;
539573
if (r < 0)
540574
return r;
541575

@@ -568,29 +602,25 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
568602

569603
static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
570604
Manager *manager = userdata;
571-
EventResult result;
572605
int r;
573606

574607
assert(dev);
575608
assert(manager);
576609

577610
r = worker_process_device(manager, dev);
578-
if (r == -EAGAIN) {
611+
if (r == EVENT_RESULT_TRY_AGAIN)
579612
/* if we couldn't acquire the flock(), then requeue the event */
580-
result = EVENT_RESULT_TRY_AGAIN;
581-
log_device_debug_errno(dev, r, "Block device is currently locked, requeueing the event.");
582-
} else if (r < 0) {
583-
result = EVENT_RESULT_FAILED;
584-
log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m");
585-
} else
586-
result = EVENT_RESULT_SUCCESS;
613+
log_device_debug(dev, "Block device is currently locked, requeueing the event.");
614+
else {
615+
if (r < 0)
616+
log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m");
587617

588-
if (result != EVENT_RESULT_TRY_AGAIN)
589618
/* send processed event back to libudev listeners */
590-
device_broadcast(monitor, dev);
619+
device_broadcast(monitor, dev, r);
620+
}
591621

592622
/* send udevd the result of the event execution */
593-
r = worker_send_result(manager, result);
623+
r = worker_send_result(manager, r);
594624
if (r < 0)
595625
log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m");
596626

@@ -1150,7 +1180,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
11501180
assert(manager);
11511181

11521182
for (;;) {
1153-
EventResult result;
1183+
int result;
11541184
struct iovec iovec = IOVEC_MAKE(&result, sizeof(result));
11551185
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
11561186
struct msghdr msghdr = {
@@ -1174,7 +1204,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
11741204

11751205
cmsg_close_all(&msghdr);
11761206

1177-
if (size != sizeof(EventResult)) {
1207+
if (size != sizeof(result)) {
11781208
log_warning("Ignoring worker message with invalid size %zi bytes", size);
11791209
continue;
11801210
}
@@ -1201,7 +1231,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
12011231
/* worker returned */
12021232
if (result == EVENT_RESULT_TRY_AGAIN &&
12031233
event_requeue(worker->event) < 0)
1204-
device_broadcast(manager->monitor, worker->event->dev);
1234+
device_broadcast(manager->monitor, worker->event->dev, -ETIMEDOUT);
12051235

12061236
/* When event_requeue() succeeds, worker->event is NULL, and event_free() handles NULL gracefully. */
12071237
event_free(worker->event);
@@ -1543,7 +1573,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
15431573
device_tag_index(worker->event->dev, NULL, false);
15441574

15451575
/* Forward kernel event to libudev listeners */
1546-
device_broadcast(manager->monitor, worker->event->dev);
1576+
device_broadcast(manager->monitor, worker->event->dev,
1577+
WIFEXITED(status) ? EVENT_RESULT_EXIT_STATUS_BASE + WEXITSTATUS(status):
1578+
WIFSIGNALED(status) ? EVENT_RESULT_SIGNAL_BASE + WTERMSIG(status) : 0);
15471579
}
15481580

15491581
worker_free(worker);

test/units/testsuite-17.03.sh

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
set -ex
44

55
test_rule="/run/udev/rules.d/49-test.rules"
6+
KILL_PID=
67

78
setup() {
89
mkdir -p "${test_rule%/*}"
@@ -22,18 +23,37 @@ EOF
2223
teardown() {
2324
set +e
2425

26+
if [[ -n "$KILL_PID" ]]; then
27+
kill "$KILL_PID"
28+
fi
29+
30+
rm -rf "$TMPDIR"
31+
2532
mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf
2633
rm -f "$test_rule"
2734
systemctl restart systemd-udevd.service
2835
}
2936

3037
run_test() {
38+
local since
39+
3140
since="$(date '+%F %T')"
3241

33-
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
42+
TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX)
43+
udevadm monitor --udev --property --subsystem-match=mem >"$TMPDIR"/monitor.txt &
44+
KILL_PID="$!"
3445

35-
for _ in {1..20}; do
46+
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --action add /dev/null
47+
48+
for _ in {1..40}; do
3649
if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then
50+
kill "$KILL_PID"
51+
KILL_PID=
52+
53+
cat "$TMPDIR"/monitor.txt
54+
grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt
55+
grep -q 'UDEV_WORKER_SIGNAL=6' "$TMPDIR"/monitor.txt
56+
grep -q 'UDEV_WORKER_SIGNAL_NAME=ABRT' "$TMPDIR"/monitor.txt
3757
return 0
3858
fi
3959
sleep .5

0 commit comments

Comments
 (0)
X Tutup