From: Nigel Kukard <nkukard@lbsd.net>
To: linux-hotplug@vger.kernel.org
Subject: Re: udev 145, when are events fully processed?
Date: Fri, 07 Aug 2009 14:48:17 +0000 [thread overview]
Message-ID: <4A7C3EB1.7030808@lbsd.net> (raw)
In-Reply-To: <4A749D9E.3020709@lbsd.net>
[-- Attachment #1: Type: text/plain, Size: 2777 bytes --]
> On 8/7/09, Nigel Kukard <nkukard@lbsd.net> wrote:
>
>>>> Trying to figure something out here, using the following I'm seeing a
>>>> delay in the creation of block devices in /dev ...
>>>>
>>>> # trigger the sorted events
>>>> echo -e '\000\000\000\000'> /proc/sys/kernel/hotplug
>>>>
>>>> rm -fr /dev/.udev> /dev/null 2>&1
>>>> mkdir -p /dev/.udev> /dev/null 2>&1
>>>> /sbin/udevd
>>>>
>>>> # Not entirely sure what this is for
>>>> /sbin/udevadm control --env=STARTUP=1
>>>> /sbin/udevadm trigger
>>>>
>>>> /sbin/udevadm settle
>>>>
>>> settle should have waited until all events have been processed
>>>
>> Does this mean fully processed or just received? I asked on
>> #udev/irc.freenode.net and was told that settle only waits until udev
>> had received them.
>>
>
> It does wait until events are "fully processed". The problem is that
> this will only apply to the events generated directly by udevadm
> trigger. USB devices may turn up late to the party for various
> reasons.
>
> Lurking on LKML it sounds like it _might_ be possible to fix the USB
> issue. AFAIK no-one is working to support this for userspace though.
>
>
>> The only reason it worked before was because of the speed improvements
>> made recently.
>>
>
> Yup.
>
>
>>>> # Nor sure what this does
>>>> /sbin/udevadm control --env=STARTUP=
>>>>
>>>>
>>>> I think my problem is, while all the events have been sent to udevd
>>>> there is a delay if I do a "fsck LABEL=root" straight on say the next
>>>> line, a "ls" shows that none of the block devices exist until a second
>>>> or two later. A sleep 5 before my "ls" works around this and the block
>>>> devices show up.
>>>>
>>>> Any ideas how I can determine once all udev events have finished
>>>> processing so I can continue boot?
>>>>
>>> check would look like:
>>> /sbin/udevadm settle --timeout=0 || echo "Still not all udev events
>>> processed"
>>>
>>> waiting should be:
>>> /sbin/udevadm settle
>>>
>> Same result on both.
>>
>> I went further and wrote a small C app to wait for the udev event, this
>> works 100%. I run the C app in the background before I run trigger &
>> settle, then do a "wait" until it returns.
>>
>> -N
>>
>
> I think everybody else just loops waiting for the device node to
> appear. So technically you may have a more advanced solution :-).
>
> Usually you also want a timeout in case something goes wrong.
> Depending on the system you can e.g. drop to an emergency shell or
> just print an error message.
>
I have a nice C proggie I'll including in bootutils, unless you guys are
interested in including it in udev?. Attached for anyone interested,
with timeout support. It can wait for a device or labeled device to come
up :)
-N
[-- Attachment #2: udev-wait-for-device.c --]
[-- Type: text/plain, Size: 5896 bytes --]
/*
* udev-wait-for-device.c - Wait for device to appear
* Copyright (C) 2009, Nigel Kukard <nkukard@lbsd.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* --
*
* Portions of code from searches on the Internet:
* - Copyright (C) 2009 Andy Walls <awa...@radix.net>
*
*/
#define VERSION "0.0.2"
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <getopt.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <libudev.h>
/* Exit handling in a sane way */
static int udev_exit;
static void sig_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM)
udev_exit = 1;
}
/* Print out our usage */
void printUsage(char **argv) {
printf("Usage: %s <options>\n",argv[0]);
printf("\n");
printf("Options:\n");
printf(" -l, --label=<LABEL> Wait for device with this label\n");
printf(" -d, --device=<DEVICE> Wait for device with this name\n");
printf(" -t, --timeout=<SECONDS> Timeout in seconds to wait [5].\n");
printf(" -h, --help Display this page\n");
printf(" -h Display this page\n\n");
printf("Return codes: 0 - found, 1 - not found/timeout");
printf("\n");
}
/* Main function */
int main(int argc, char *argv[])
{
struct udev *udev;
const char *s;
struct udev_list_entry *udev_list_entry;
int rc = 127;
struct sigaction act;
struct udev_monitor *udev_monitor = NULL;
fd_set readfds;
int prop = 1;
char *deviceName;
char *deviceLabel;
int timeout = 5;
/* Our long options */
struct option long_options[] = {
{"label",1,0,'l'},
{"device",1,0,'d'},
{"timeout",1,0,'t'},
{"help",0,0,'h'},
{0,0,0,0}
};
// printf("UDEV-WAIT-FOR v%s - Copyright (c) 2009, Nigel Kukard\n\n",VERSION);
/* Go straight to help if no params provided */
if (argc == 1) {
printUsage(argv);
exit(2);
}
/* Loop with options */
while (1) {
int option_index = 0;
char c;
/* Process */
c = getopt_long(argc,argv,"l:d:",long_options,&option_index);
if (c == -1)
break;
/* Check... */
switch (c) {
case 'l':
deviceLabel = optarg;
break;
case 'd':
deviceName = optarg;
break;
case 't':
timeout = atoi(optarg);
break;
case 'h':
printUsage(argv);
return 0;
default:
printUsage(argv);
return 1;
}
}
/* We shouldn't have anything left over */
if (optind < argc) {
while (optind < argc)
fprintf(stderr,"%s: Invalid option -- %s\n",argv[0],argv[optind++]);
exit(2);
}
/* Initialize udev */
udev = udev_new();
if (udev == NULL) {
fprintf(stderr, "ERROR: udev_new() failed\n");
exit(3);
}
/* set signal handlers */
memset(&act, 0x00, sizeof(struct sigaction));
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
/* Monitor from UDEV netlink */
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (udev_monitor == NULL) {
fprintf(stderr, "ERROR: Unable to create netlink socket\n");
rc = 3;
goto out;
}
/* Filter block devices */
if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0)
{
fprintf(stderr, "ERROR: Unable to apply filter\n");
rc = 3;
goto out;
}
/* Enable receiving of events */
if (udev_monitor_enable_receiving(udev_monitor) < 0) {
fprintf(stderr, "ERROR: Unable to subscribe to udev events\n");
rc = 3;
goto out;
}
/* Loop */
while (!udev_exit) {
int fdcount;
struct timeval tv;
/* Setup timeouts */
tv.tv_sec = timeout;
tv.tv_usec = 0;
/* Setup select fds */
FD_ZERO(&readfds);
FD_SET(udev_monitor_get_fd(udev_monitor), &readfds);
/* Fire up select */
fdcount = select(udev_monitor_get_fd(udev_monitor)+1, &readfds, NULL, NULL, &tv);
/* Look for timeout */
if (fdcount == 0) {
udev_exit = 1;
rc = 1;
continue;
/* Look for interrupt */
} else if (fdcount < 0) {
if (errno != EINTR)
fprintf(stderr, "ERROR Receiving uevent message: %m\n");
continue;
}
/* Check for set FD */
if (FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) {
struct udev_device *device;
struct udev_list_entry *list_entry;
/* Grab device */
device = udev_monitor_receive_device(udev_monitor);
if (device == NULL)
continue;
/* Loop with properties */
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
const char *propname = udev_list_entry_get_name(list_entry);
const char *propval = udev_list_entry_get_value(list_entry);
int found = 0;
if (deviceLabel)
if (!strcmp(propname,"ID_FS_LABEL") && !strcmp(propval,deviceLabel))
found = 1;
if (deviceName)
if (!strcmp(propname,"DEVNAME") && !strcmp(propval,deviceName))
found = 1;
if (found) {
rc = 0;
udev_exit = 1;
break;
}
}
udev_device_unref(device);
}
}
out:
udev_monitor_unref(udev_monitor);
udev_unref(udev);
exit(rc);
}
/* vim: ts=4 */
next prev parent reply other threads:[~2009-08-07 14:48 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-01 19:55 udev 145, when are events fully processed? Nigel Kukard
2009-08-07 12:26 ` Harald Hoyer
2009-08-07 12:56 ` Nigel Kukard
2009-08-07 14:15 ` Alan Jenkins
2009-08-07 14:48 ` Nigel Kukard [this message]
2009-08-07 15:34 ` Kay Sievers
2009-08-07 16:00 ` Alan Jenkins
2009-08-07 16:10 ` Nigel Kukard
2009-08-07 16:24 ` Kay Sievers
2009-08-07 16:40 ` Nigel Kukard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A7C3EB1.7030808@lbsd.net \
--to=nkukard@lbsd.net \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).