* Re: udev: Why non-blocking poll() with blocking recvmsg()?
2013-08-19 11:39 udev: Why non-blocking poll() with blocking recvmsg()? Tetsuo Handa
2013-08-19 12:15 ` Martin Pitt
2013-08-19 12:37 ` Tetsuo Handa
@ 2013-08-19 12:45 ` Kay Sievers
2013-08-19 13:24 ` Tetsuo Handa
2013-08-23 12:48 ` Tetsuo Handa
4 siblings, 0 replies; 6+ messages in thread
From: Kay Sievers @ 2013-08-19 12:45 UTC (permalink / raw)
To: linux-hotplug
On Mon, Aug 19, 2013 at 1:39 PM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> recvmsg() waits until something is queued if udev_monitor->sock is blocking,
Only on a blocking socket, which it isn't by default:
http://www.freedesktop.org/software/systemd/libudev/libudev-udev-monitor.html#udev-monitor-receive-device
> but poll() does not wait until something is queued even if udev_monitor->sock
> is blocking.
>
> I think that this inconsistency makes udev_monitor_receive_device()
> to immediately return NULL when an event where passes_filter() returns 0 was
> already queued but another event where passes_filter() returns 1 is not yet
> queued, making wait-for-root utility which is waiting for only "block" subsystem
> events fail.
>
> Why don't we unconditionally go to retry rather than poll(pfd, 1, 0) so that
> "blocking socket can wait for next event" and "non-blocking socket can return
> immediately"?
It's from a time where the socket was still blocking, but we still
used poll() in calling code. We didn't want to block the caller, hence
the poll() inside the library.
The poll() inside of libudev-monitor.c can probably just be removed
today. Or even the whole retry be removed, it might not be a useful
optimization at all.
Kay
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: udev: Why non-blocking poll() with blocking recvmsg()?
2013-08-19 11:39 udev: Why non-blocking poll() with blocking recvmsg()? Tetsuo Handa
` (2 preceding siblings ...)
2013-08-19 12:45 ` Kay Sievers
@ 2013-08-19 13:24 ` Tetsuo Handa
2013-08-23 12:48 ` Tetsuo Handa
4 siblings, 0 replies; 6+ messages in thread
From: Tetsuo Handa @ 2013-08-19 13:24 UTC (permalink / raw)
To: linux-hotplug
Hello Kay.
Kay Sievers wrote:
> > recvmsg() waits until something is queued if udev_monitor->sock is blocking,
>
> Only on a blocking socket, which it isn't by default:
I confirmed using strace utility that Ubuntu 12.04's wait-for-root
(source code shown below) calls recvmsg() using blocking mode.
# strace /usr/lib/initramfs-tools/bin/wait-for-root /dev/sdaX 5
> It's from a time where the socket was still blocking, but we still
> used poll() in calling code. We didn't want to block the caller, hence
> the poll() inside the library.
So, "poll() in udev_monitor_receive_device() does not wait" is a feature?
Then, wait-for-root is responsible for retrying the loop (line 91 to 104) when
udev_monitor_receive_device() returned NULL (without waiting for a "block"
subsystem event) caused by udev_monitor_receive_device() getting a non-"block"
subsystem event at recvmsg(), isn't it?
---------- wait-for-root.c start ----------
1:#include <libudev.h>
2:
3:#include <sys/types.h>
4:#include <sys/stat.h>
5:
6:#include <time.h>
7:#include <stdio.h>
8:#include <limits.h>
9:#include <signal.h>
10:#include <stdlib.h>
11:#include <string.h>
12:#include <unistd.h>
13:
14:
15:static int device_queued (struct udev *udev, const char *path);
16:static int matching_device (struct udev_device *device, const char *path);
17:
18:static void alarm_handler (int signum);
19:
20:
21:int
22:main (int argc,
23: char *argv[])
24:{
25: const char * devpath;
26: char path[PATH_MAX];
27: int timeout;
28: struct udev * udev;
29: struct udev_monitor *udev_monitor;
30: struct stat devstat;
31: struct udev_device * udev_device;
32: const char * type;
33:
34: if (argc != 3) {
35: fprintf (stderr, "Usage: %s DEVICE TIMEOUT\n", argv[0]);
36: exit (2);
37: }
38:
39: devpath = argv[1];
40: if (! strncmp (devpath, "UUID=", 5)) {
41: strcpy (path, "/dev/disk/by-uuid/");
42: strcat (path, devpath + 5);
43: } else if (! strncmp (devpath, "LABEL=", 6)) {
44: strcpy (path, "/dev/disk/by-label/");
45: strcat (path, devpath + 6);
46: } else {
47: strcpy (path, devpath);
48: }
49:
50: timeout = atoi (argv[2]);
51:
52: signal (SIGALRM, alarm_handler);
53: alarm (timeout);
54:
55: /* Connect to the udev monitor first; if we stat() first, the
56: * event might happen between the stat() and the time we actually
57: * get hooked up.
58: */
59: udev = udev_new ();
60: udev_monitor = udev_monitor_new_from_netlink (udev, "udev");
61:
62: udev_monitor_filter_add_match_subsystem_devtype (udev_monitor, "block", NULL);
63: udev_monitor_enable_receiving (udev_monitor);
64:
65: /* If the device is not being processed, check to see whether it
66: * exists already on the filesystem. If this is true, we don't need
67: * to wait for it can obtain the filesystem type by looking up the
68: * udevdb record by major/minor.
69: */
70: if ((! device_queued (udev, devpath))
71: && (stat (path, &devstat) = 0)
72: && S_ISBLK (devstat.st_mode))
73: {
74: udev_device = udev_device_new_from_devnum (udev, 'b', devstat.st_rdev);
75: if (udev_device) {
76: type = udev_device_get_property_value (udev_device, "ID_FS_TYPE");
77: if (type) {
78: printf ("%s\n", type);
79:
80: udev_device_unref (udev_device);
81: goto exit;
82: }
83:
84: udev_device_unref (udev_device);
85: }
86: }
87:
88: /* When the device doesn't exist yet, or is still being processed
89: * by udev, use the monitor socket to wait it to be done.
90: */
91: while ((udev_device = udev_monitor_receive_device (udev_monitor)) != NULL) {
92: if (matching_device (udev_device, devpath)) {
93: type = udev_device_get_property_value (udev_device, "ID_FS_TYPE");
94: if (type) {
95: printf ("%s\n", type);
96:
97: udev_device_unref (udev_device);
98: goto exit;
99: }
100:
101: }
102:
103: udev_device_unref (udev_device);
104: }
105:
106:exit:
107: udev_monitor_unref (udev_monitor);
108: udev_unref (udev);
109:
110: exit (0);
111:}
112:
113:
114:static int
115:device_queued (struct udev *udev,
116: const char * devpath)
117:{
118: struct udev_queue * udev_queue;
119: struct udev_list_entry *queue_entry;
120: int found = 0;
121:
122: udev_queue = udev_queue_new (udev);
123:
124: for (queue_entry = udev_queue_get_queued_list_entry (udev_queue);
125: queue_entry != NULL;
126: queue_entry = udev_list_entry_get_next (queue_entry)) {
127: const char * syspath;
128: struct udev_device *udev_device;
129:
130: syspath = udev_list_entry_get_name (queue_entry);
131: udev_device = udev_device_new_from_syspath (udev, syspath);
132: if (udev_device) {
133: if (matching_device (udev_device, devpath))
134: found = 1;
135:
136: udev_device_unref (udev_device);
137: }
138: }
139:
140: udev_queue_unref (udev_queue);
141:
142: return found;
143:}
144:
145:static int
146:matching_device (struct udev_device *device,
147: const char * path)
148:{
149: const char * devnode;
150: struct udev_list_entry *devlinks_entry;
151:
152: /* Match by name */
153: devnode = udev_device_get_devnode (device);
154: if (devnode && (! strcmp (path, devnode)))
155: return 1;
156:
157: /* Match by UUID */
158: if (! strncmp (path, "UUID=", 5)) {
159: const char *uuid;
160:
161: uuid = udev_device_get_property_value (device, "ID_FS_UUID");
162: if (uuid && (! strcmp (path + 5, uuid)))
163: return 1;
164: }
165:
166: /* Match by LABEL */
167: if (! strncmp (path, "LABEL=", 6)) {
168: const char *label;
169:
170: label = udev_device_get_property_value (device, "ID_FS_LABEL");
171: if (label && (! strcmp (path + 6, label)))
172: return 1;
173: }
174:
175: /* Match by symlink */
176: for (devlinks_entry = udev_device_get_devlinks_list_entry (device);
177: devlinks_entry != NULL;
178: devlinks_entry = udev_list_entry_get_next (devlinks_entry))
179: if (! strcmp (path, udev_list_entry_get_name (devlinks_entry)))
180: return 1;
181:
182: return 0;
183:}
184:
185:
186:static void
187:alarm_handler (int signum)
188:{
189: exit (1);
190:}
---------- wait-for-root.c end ----------
^ permalink raw reply [flat|nested] 6+ messages in thread