udev-cache related changes
v2 cover udev-cache related changes
This is v2 of the changes submitted by Ben Shelton on August 4. I've reworked the patches quite a bit, larger changes include:
- All non-udev-cache-related patches have been omitted. I'll submit those separately.
- Use find to build tar filelist. This eliminates the need for GNU- and busybox-specific tar options.
- No new settings have been added to udev-cache.default in order to preserve compatibility with older overrides of udev-cache.default. Note, this means a lot of new settings are duplicated between initscripts.
- System config is now generated immediately before the tarball is generated, and is manipulated at the file level instead of the shell variable level.
- Internal/corporate commit message fields stripped.
- Spurious whitespace changes should all be fixed.
There is one requested fix I'm pushing back on: Copying both $CMP_FILE_LIST and /dev to tmpfs in a single operation to minimize race conditions. For a variety of reasons, I abandoned trying to make this work in a single command. Instead it's done in two: grabbing the system configuration (i.e reading /proc files and udev rules) is done first, then /dev is archived as an uncompressed tarball. Notably, using tar instead of cp means that I can use find -xdev and find -type to eliminate a lot of other complexity. I think this approach will wind up being faster than the straight-up copy approach, although I have not made any attempt to confirm that.
The following changes since commit 47d1fc9f5c38f3d092937c47bd4c2f45adaa7fe6:
qemu: fix Darwin cross-compilation (2014-08-18 20:43:24 +0100)
are available in the git repository at:
git://github.com/rtollert/openembedded-core dev/rtollert/udev-cache-7
https://github.com/rtollert/openembedded-core/tree/dev/rtollert/udev-cache-7
Richard Tollerton (12):
udev-cache: Update cache tarball atomically
udev-cache: Compress the cache
udev-cache: choose a more descriptive cache filename
busybox: enable tar -m
udev-cache: strip timestamps on extract
udev-cache: omit sockets and filesystems mounted under /dev
udev-cache: Don't ignore error messages from cache extract
udev-cache: parametrize sysconf file paths
udev-cache: get system config immediately before cache
udev-cache: invalidate on rules.d changes
udev-cache: Update cache asynchronously
udev-cache: refactor; improve verbosity and error handling
meta/recipes-core/busybox/busybox/defconfig | 2 +- meta/recipes-core/udev/udev/init | 53 ++++++++++++-------------- meta/recipes-core/udev/udev/udev-cache | 42 ++++++++++++++++++-- meta/recipes-core/udev/udev/udev-cache.default | 2 +- 4 files changed, 64 insertions(+), 35 deletions(-)
Signature · 1 line
2.0.4
PATCH v2 1/12 udev-cache: Update cache tarball atomically
Overwriting the tarball in-place could cause a partial write, if the system stops at an inopportune time. This is mitigated by first writing to a temporary file, then moving that file on top of the final location.
--- meta/recipes-core/udev/udev/udev-cache | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
meta/recipes-core/udev/udev/udev-cache +3 -1
@@ -16,6 +16,7 @@ export TZ=/etc/localtime [ -d /sys/class ] || exit 1 [ -f /etc/default/rcS ] && . /etc/default/rcS +DEVCACHE_TMP="/dev/shm/udev-cache-tmp.tar" [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache if [ "$ROOTFS_READ_ONLY" = "yes" ]; then
@@ -25,7 +26,8 @@ fi if [ "$DEVCACHE" != "" -a -e /dev/shm/udev.cache ]; then echo "Populating dev cache" - (cd /; tar cf "$DEVCACHE" dev) + (cd /; tar cf "${DEVCACHE_TMP}" dev) + mv -f "${DEVCACHE_TMP}" "$DEVCACHE" mv /dev/shm/udev.cache /etc/udev/cache.data fi
Signature · 1 line
2.0.4
PATCH v2 2/12 udev-cache: Compress the cache
In reply to Richard Tollerton$DEVCACHE is observed to be 100k uncompressed; compressing it reduces its size to ~5k. But compress it outside of tar so that archival operation takes as little time as possible, to minimize the risk of devices being created/removed during execution.
--- meta/recipes-core/udev/udev/udev-cache | 3 ++- meta/recipes-core/udev/udev/udev-cache.default | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
meta/recipes-core/udev/udev/udev-cache +2 -1
@@ -27,7 +27,8 @@ fi if [ "$DEVCACHE" != "" -a -e /dev/shm/udev.cache ]; then echo "Populating dev cache" (cd /; tar cf "${DEVCACHE_TMP}" dev) - mv -f "${DEVCACHE_TMP}" "$DEVCACHE" + gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" + rm -f "${DEVCACHE_TMP}" mv /dev/shm/udev.cache /etc/udev/cache.data fi
meta/recipes-core/udev/udev/udev-cache.default +1 -1
@@ -1,5 +1,5 @@ # Default for /etc/init.d/udev # Comment this out to disable device cache -DEVCACHE="/etc/dev.tar" +DEVCACHE="/etc/dev.tar.gz" PROBE_PLATFORM_BUS="yes"
Signature · 1 line
2.0.4
PATCH v2 3/12 udev-cache: choose a more descriptive cache filename
In reply to Richard Tollerton"/etc/dev.tar.gz" doesn't adequately imply that udev-cache maintains it. Instead, call it "/etc/udev-cache.tar.gz".
--- meta/recipes-core/udev/udev/udev-cache.default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
meta/recipes-core/udev/udev/udev-cache.default +1 -1
@@ -1,5 +1,5 @@ # Default for /etc/init.d/udev # Comment this out to disable device cache -DEVCACHE="/etc/dev.tar.gz" +DEVCACHE="/etc/udev-cache.tar.gz" PROBE_PLATFORM_BUS="yes"
Signature · 1 line
2.0.4
PATCH v2 4/12 busybox: enable `tar -m`
In reply to Richard TollertonCONFIG_FEATURE_TAR_NOPRESERVE_TIME=y is needed for the commit "udev-cache: strip timestamps on extract". Enabling this flag increases the size of busybox by 0 bytes on x86.
--- meta/recipes-core/busybox/busybox/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
meta/recipes-core/busybox/busybox/defconfig +1 -1
@@ -159,7 +159,7 @@ CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set # CONFIG_FEATURE_TAR_TO_COMMAND is not set # CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set # CONFIG_UNCOMPRESS is not set # CONFIG_UNLZMA is not set
Signature · 1 line
2.0.4
PATCH v2 5/12 udev-cache: strip timestamps on extract
In reply to Richard TollertonUnder normal udev operation, device nodes are obviously timestamped based on the system time at current boot. However, when using udev-cache, they are timestamped from a previous boot.
The existence of machines lacking RTCs makes this more than a cosmetic
issue: if the current time is set further on in the boot, so that the system time is still 1970 by the time the cache is extracted, tar will print a timestamp warning for every extracted file (potentially hundreds of them).
To fix, use -m on extract.
If using busybox tar, this commit requiresCONFIG_FEATURE_TAR_NOPRESERVE_TIME=y.
--- meta/recipes-core/udev/udev/init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
meta/recipes-core/udev/udev/init +1 -1
@@ -69,7 +69,7 @@ case "$1" in readfiles /etc/udev/cache.data OLDDATA="$READDATA" if [ "$OLDDATA" = "$NEWDATA" ]; then - (cd /; tar xf $DEVCACHE > /dev/null 2>&1) + (cd /; tar xmf $DEVCACHE > /dev/null 2>&1) not_first_boot=1 [ "$VERBOSE" != "no" ] && echo "udev: using cache file $DEVCACHE" [ -e /dev/shm/udev.cache ] && rm -f /dev/shm/udev.cache
Signature · 1 line
2.0.4
PATCH v2 6/12 udev-cache: omit sockets and filesystems mounted under /dev
In reply to Richard TollertonArchiving sockets causes tar to report an error and return a nonzero exit status. Archiving a mounted filesystem is harmless, but may greatly bloat the size of the cache tarball, and wastes time on boot.
To fix these issues, use find to only include the files we want, which are the file types that udev will create (block/char devices and symlinks) that are on the same filesystem as /dev.
While we're at it, remove a subshell by archiving /dev as an absolute path. However, tar will complain about stripping the leading slash on stderr. To inhibit this, cut out the leading slash.
An alternative solution is to use tar --exclude, but that is modestly more brittle, since we'd need to explicitly list every socket and filesystem to exclude. Note that tar --one-file-system is GNU-specific, and tar implementations generally have nothing equivalent to find -type.
If using busybox find, this change requires CONFIG_FEATURE_FIND_TYPE=y and CONFIG_FEATURE_FIND_XDEV=y. If using busybox tar, this change requires CONFIG_FEATURE_TAR_FROM=y.
--- meta/recipes-core/udev/udev/udev-cache | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
meta/recipes-core/udev/udev/udev-cache +2 -1
@@ -26,7 +26,8 @@ fi if [ "$DEVCACHE" != "" -a -e /dev/shm/udev.cache ]; then echo "Populating dev cache" - (cd /; tar cf "${DEVCACHE_TMP}" dev) + find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ + | xargs tar cf "${DEVCACHE_TMP}" -T- gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" rm -f "${DEVCACHE_TMP}" mv /dev/shm/udev.cache /etc/udev/cache.data
Signature · 1 line
2.0.4
PATCH v2 7/12 udev-cache: Don't ignore error messages from cache extract
In reply to Richard TollertonPrevious changes should obviate all known spurious errors coming out of tar. Since real extraction failures can and will occur, stop redirecting stdout/stderr to /dev/null.
Take this opportunity to also remove an unnecessary subshell.
--- meta/recipes-core/udev/udev/init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
meta/recipes-core/udev/udev/init +1 -1
@@ -69,7 +69,7 @@ case "$1" in readfiles /etc/udev/cache.data OLDDATA="$READDATA" if [ "$OLDDATA" = "$NEWDATA" ]; then - (cd /; tar xmf $DEVCACHE > /dev/null 2>&1) + tar xmf $DEVCACHE -C / -m not_first_boot=1 [ "$VERBOSE" != "no" ] && echo "udev: using cache file $DEVCACHE" [ -e /dev/shm/udev.cache ] && rm -f /dev/shm/udev.cache
Signature · 1 line
2.0.4
PATCH v2 8/12 udev-cache: parametrize sysconf file paths
In reply to Richard TollertonThe udev-cache facility uses files that represent system states, to ensure that the cache tarball is valid to apply. These paths were hardcoded in several places; collect them into SYSCONF_CACHED and SYSCONF_TMP.
--- meta/recipes-core/udev/udev/init | 10 ++++++---- meta/recipes-core/udev/udev/udev-cache | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-)
meta/recipes-core/udev/udev/init +6 -4
@@ -14,6 +14,8 @@ export TZ=/etc/localtime [ -d /sys/class ] || exit 1 [ -r /proc/mounts ] || exit 1 [ -x @UDEVD@ ] || exit 1 +SYSCONF_CACHED="/etc/udev/cache.data" +SYSCONF_TMP="/dev/shm/udev.cache" [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache [ -f /etc/udev/udev.conf ] && . /etc/udev/udev.conf [ -f /etc/default/rcS ] && . /etc/default/rcS
@@ -66,13 +68,13 @@ case "$1" in if [ -e $DEVCACHE ]; then readfiles $CMP_FILE_LIST NEWDATA="$READDATA" - readfiles /etc/udev/cache.data + readfiles "$SYSCONF_CACHED" OLDDATA="$READDATA" if [ "$OLDDATA" = "$NEWDATA" ]; then tar xmf $DEVCACHE -C / -m not_first_boot=1 [ "$VERBOSE" != "no" ] && echo "udev: using cache file $DEVCACHE" - [ -e /dev/shm/udev.cache ] && rm -f /dev/shm/udev.cache + [ -e $SYSCONF_TMP ] && rm -f "$SYSCONF_TMP" else # Output detailed reason why the cached /dev is not used if [ "$VERBOSE" != "no" ]; then
@@ -81,14 +83,14 @@ case "$1" in echo "udev: olddata: $OLDDATA" echo "udev: newdata: $NEWDATA" fi - echo "$NEWDATA" > /dev/shm/udev.cache + echo "$NEWDATA" > "$SYSCONF_TMP" fi else if [ "$ROOTFS_READ_ONLY" != "yes" ]; then # If rootfs is not read-only, it's possible that a new udev cache would be generated; # otherwise, we do not bother to read files. readfiles $CMP_FILE_LIST - echo "$READDATA" > /dev/shm/udev.cache + echo "$READDATA" > "$SYSCONF_TMP" fi fi fi
meta/recipes-core/udev/udev/udev-cache +4 -2
@@ -17,6 +17,8 @@ export TZ=/etc/localtime [ -f /etc/default/rcS ] && . /etc/default/rcS DEVCACHE_TMP="/dev/shm/udev-cache-tmp.tar" +SYSCONF_CACHED="/etc/udev/cache.data" +SYSCONF_TMP="/dev/shm/udev.cache" [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache if [ "$ROOTFS_READ_ONLY" = "yes" ]; then
@@ -24,13 +26,13 @@ if [ "$ROOTFS_READ_ONLY" = "yes" ]; then exit 0 fi -if [ "$DEVCACHE" != "" -a -e /dev/shm/udev.cache ]; then +if [ "$DEVCACHE" != "" -a -e "$SYSCONF_TMP" ]; then echo "Populating dev cache" find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ | xargs tar cf "${DEVCACHE_TMP}" -T- gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" rm -f "${DEVCACHE_TMP}" - mv /dev/shm/udev.cache /etc/udev/cache.data + mv "$SYSCONF_TMP" "$SYSCONF_CACHED" fi exit 0
Signature · 1 line
2.0.4
PATCH v2 9/12 udev-cache: get system config immediately before cache
In reply to Richard TollertonThe system device configuration -- /proc/devices, /proc/cmdline, etc. -- and the contents of /dev must be stored as simultaneously as possible. Otherwise, hotplug events could be processed between the time we get the system config and the time we archive /dev, and the udev cache may be incorrect.
To solve this, update the cached system configuration inside the udev-cache initscript, not the udev initscript. Also, run it before archiving /dev, because it should execute nearly instantaneously.
We still need to compute the system configuration inside the udev initscript, to detect if it changed, so refactor it into a new function sysconf_cmd(). This also allows administrators to modify it for machine-specific requirements.
Evaluating the system configuration requires a shell function readfiles() defined in the udev initscript. The only salient differences between readfiles() and just using cat directly are a) readfiles() skips files without error if they don't exist, which is necessary because /proc/atags is in CMP_FILE_LIST but does not exist on all targets; and b) input lines are concatenated into an output shell variable with newlines stripped. (a) can be eliminated by not including /proc/atags in CMP_FILE_LIST if it doesn't exist. (b) is O(n^2) anyway, and makes $NEWDATA, $OLDDATA etc. very hard to read, and we don't need to strip newlines anyway. So make sysconf_cmd() use cat and remove readfiles().
Instead of storing system configuration in shell variables ($NEWDATA, $OLDDATA), store them directly in files: redirect to $SYSCONF_TMP instead of storing in $NEWDATA; read from $SYSCONF_CACHED directly instead of reading it into $OLDDATA. This turns comparing $NEWDATA vs. $OLDDATA into a call to cmp. However, busybox lacks cmp -q, so instead, redirect cmp's output to /dev/null.
$OLDDATA and $NEWDATA go away. This obviates the most of error message printed when the udev cache can't be used, but it probably wasn't of much help, because $OLDDATA and $NEWDATA are so large that they would have scrolled off the screen anyway. Beyond that, this error is so important that it should probably be printed regardless of the setting of VERBOSE. So leave the "udev: cache not used" log message and remove everything else.
Because the udev-cache initscript evaluates the system configuration itself, it makes no sense to signal it to run by storing the system configuration in a file. Instead, signal udev-cache execution by touching a file, $DEVCACHE_REGEN.
--- meta/recipes-core/udev/udev/init | 44 +++++++++++++--------------------- meta/recipes-core/udev/udev/udev-cache | 17 +++++++++++-- 2 files changed, 31 insertions(+), 30 deletions(-)
meta/recipes-core/udev/udev/init +16 -28
@@ -16,21 +16,20 @@ export TZ=/etc/localtime [ -x @UDEVD@ ] || exit 1 SYSCONF_CACHED="/etc/udev/cache.data" SYSCONF_TMP="/dev/shm/udev.cache" +DEVCACHE_REGEN="/dev/shm/udev-regen" # create to request cache regen + +# List of files whose contents will be included in cached system state. +CMP_FILE_LIST="/proc/version /proc/cmdline /proc/devices" +[ -f /proc/atags ] && CMP_FILE_LIST="$CMP_FILE_LIST /proc/atags" + +# Command to compute system configuration. +sysconf_cmd () { + cat -- $CMP_FILE_LIST +} [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache [ -f /etc/udev/udev.conf ] && . /etc/udev/udev.conf [ -f /etc/default/rcS ] && . /etc/default/rcS -readfiles () { - READDATA="" - for filename in $@; do - if [ -r $filename ]; then - while read line; do - READDATA="$READDATA$line" - done < $filename - fi - done -} - kill_udevd () { pid=`pidof -x udevd` [ -n "$pid" ] && kill $pid
@@ -62,35 +61,24 @@ case "$1" in mkdir -p /var/volatile/tmp # Cache handling. - # A list of files which are used as a criteria to judge whether the udev cache could be reused. - CMP_FILE_LIST="/proc/version /proc/cmdline /proc/devices /proc/atags" if [ "$DEVCACHE" != "" ]; then if [ -e $DEVCACHE ]; then - readfiles $CMP_FILE_LIST - NEWDATA="$READDATA" - readfiles "$SYSCONF_CACHED" - OLDDATA="$READDATA" - if [ "$OLDDATA" = "$NEWDATA" ]; then + sysconf_cmd > $SYSCONF_TMP + if cmp $SYSCONF_CACHED $SYSCONF_TMP >/dev/null; then tar xmf $DEVCACHE -C / -m not_first_boot=1 [ "$VERBOSE" != "no" ] && echo "udev: using cache file $DEVCACHE" - [ -e $SYSCONF_TMP ] && rm -f "$SYSCONF_TMP" + [ -e "$DEVCACHE_REGEN" ] && rm -f "$DEVCACHE_REGEN" else # Output detailed reason why the cached /dev is not used - if [ "$VERBOSE" != "no" ]; then - echo "udev: udev cache not used" - echo "udev: we use $CMP_FILE_LIST as criteria to judge whether the cache /dev could be resued" - echo "udev: olddata: $OLDDATA" - echo "udev: newdata: $NEWDATA" - fi - echo "$NEWDATA" > "$SYSCONF_TMP" + echo "udev: cache not used" + touch "$DEVCACHE_REGEN" fi else if [ "$ROOTFS_READ_ONLY" != "yes" ]; then # If rootfs is not read-only, it's possible that a new udev cache would be generated; # otherwise, we do not bother to read files. - readfiles $CMP_FILE_LIST - echo "$READDATA" > "$SYSCONF_TMP" + touch "$DEVCACHE_REGEN" fi fi fi
meta/recipes-core/udev/udev/udev-cache +15 -2
@@ -19,6 +19,16 @@ export TZ=/etc/localtime DEVCACHE_TMP="/dev/shm/udev-cache-tmp.tar" SYSCONF_CACHED="/etc/udev/cache.data" SYSCONF_TMP="/dev/shm/udev.cache" +DEVCACHE_REGEN="/dev/shm/udev-regen" # create to request cache regen + +# List of files whose contents will be included in cached system state. +CMP_FILE_LIST="/proc/version /proc/cmdline /proc/devices" +[ -f /proc/atags ] && CMP_FILE_LIST="$CMP_FILE_LIST /proc/atags" + +# Command to compute system configuration. +sysconf_cmd () { + cat -- $CMP_FILE_LIST +} [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache if [ "$ROOTFS_READ_ONLY" = "yes" ]; then
@@ -26,13 +36,16 @@ if [ "$ROOTFS_READ_ONLY" = "yes" ]; then exit 0 fi -if [ "$DEVCACHE" != "" -a -e "$SYSCONF_TMP" ]; then +if [ "$DEVCACHE" != "" -a -e "$DEVCACHE_REGEN" ]; then echo "Populating dev cache" + # Run sysconf_cmd before `tar`, not after, so that as little time as + # possible elapses between creating $SYSCONF_CACHED and $DEVCACHE. + sysconf_cmd > "$SYSCONF_CACHED" find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ | xargs tar cf "${DEVCACHE_TMP}" -T- gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" rm -f "${DEVCACHE_TMP}" - mv "$SYSCONF_TMP" "$SYSCONF_CACHED" + rm -f "$DEVCACHE_REGEN" fi exit 0
Signature · 1 line
2.0.4
Re: [PATCH v2 09/12] udev-cache: get system config immediately before cache
Quoted 15 lines · Richard Tollerton
The system device configuration --
/proc/devices,/proc/cmdline, etc. -- and the contents of /dev must be stored as simultaneously as possible. Otherwise, hotplug events could be processed between the time we get the system config and the time we archive /dev, and the udev cache may be incorrect.To solve this, update the cached system configuration inside the udev-cache initscript, not the udev initscript. Also, run it before archiving /dev, because it should execute nearly instantaneously.
We still need to compute the system configuration inside the udev initscript, to detect if it changed, so refactor it into a new function
sysconf_cmd(). This also allows administrators to modify it for machine-specific requirements.
Quoted 11 lines
Evaluating the system configuration requires a shell function
readfiles()defined in the udev initscript. The only salient differences betweenreadfiles()and just usingcatdirectly are a)readfiles()skips files without error if they don't exist, which is necessary because/proc/atagsis inCMP_FILE_LISTbut does not exist on all targets; and b) input lines are concatenated into an output shell variable with newlines stripped. (a) can be eliminated by not including/proc/atagsinCMP_FILE_LISTif it doesn't exist. (b) is O(n^2) anyway, and makes $NEWDATA, $OLDDATA etc. very hard to read, and we don't need to strip newlines anyway. So makesysconf_cmd()usecatand removereadfiles().
The reason this was done was actually c) avoid having to execute cat as a new process.
Quoted 6 lines
Instead of storing system configuration in shell variables ($NEWDATA, $OLDDATA), store them directly in files: redirect to $SYSCONF_TMP instead of storing in $NEWDATA; read from $SYSCONF_CACHED directly instead of reading it into $OLDDATA. This turns comparing $NEWDATA vs. $OLDDATA into a call to
cmp. However, busybox lackscmp -q, so instead, redirect cmp's output to/dev/null.
The above reason c) is also why we don't use cmp. It turned out to be faster to read into a variable than fork/exec cmp.
Cheers,
Richard
Re: [PATCH v2 09/12] udev-cache: get system config immediately before cache
Quoted 2 lines · Richard Purdie
The above reason c) is also why we don't use cmp. It turned out to be faster to read into a variable than fork/exec cmp.
You appear to be wrong: cat+cmp is 27-41% faster than readfiles. In fact, testing cat alone (without cmp) shows that cat to tmpfs file is 2x-3x as fast as readfiles.
These figures reproduce on both a Xilinx Zynq Cortex-A9 and my Xeon dev machine; the former running busybox sh, the latter running bash.
See below for test script.
---
#!/bin/busybox sh
files="/proc/version /proc/cmdline /proc/devices"
runs=100
readfiles () {
READDATA=""
for filename in $@; do
if [ -r $filename ]; then
while read line; do
READDATA="$READDATA$line"
done < $filename
fi
done
}
dotest_cat_inner () {
cat $@
}dotest_cat () {
cat $@ > /tmp/a.txt
cat $@ > /tmp/b.txt
cmp /tmp/a.txt /tmp/b.txt
}dotest_readfiles_inner () {
readfiles $@
echo "$READDATA"
}
dotest_readfiles () {
readfiles $@
NEWDATA="$READDATA"
readfiles $@
OLDDATA="$OLDDATA"
[ "$OLDDATA" = "$NEWDATA" ]
}timetest () {
cmd=$1
i=$2
shift 2
while [ "$i" -gt 0 ]; do
$cmd $@ >/dev/null
i=$(( i-1 ))
done
}case $1 in
cat) timetest dotest_cat $runs $files ;;
readfiles) timetest dotest_readfiles $runs $files ;; inner_cat) timetest dotest_cat_inner $runs $files ;; inner_readfiles) timetest dotest_readfiles_inner $runs $files ;; *)
printf 'cat:\n'
time $0 cat
printf '\nreadfiles:\n'
time $0 readfiles
printf '\ncat_inner:\n'
time $0 inner_cat
printf '\nreadfiles_inner:\n'
time $0 inner_readfiles
;;
esac
Quoted 4 lines
Cheers,
Richard
Signature · 1 line
Richard Tollerton <[email protected]>
PATCH v2 10/12 udev-cache: invalidate on rules.d changes
In reply to Richard TollertonPresently, the cache is not regenerated if udev rules are modified, which may cause the cache to preserve an old configuration. To fix, include the size, mtime, and filename of all udev rules in the system configuration.
This change requires stat. If busybox supplies stat, CONFIG_FEATURE_STAT_FORMAT must be enabled.
--- meta/recipes-core/udev/udev/init | 5 +++++ meta/recipes-core/udev/udev/udev-cache | 5 +++++ 2 files changed, 10 insertions(+)
meta/recipes-core/udev/udev/init +5 -0
@@ -22,9 +22,14 @@ DEVCACHE_REGEN="/dev/shm/udev-regen" # create to request cache regen CMP_FILE_LIST="/proc/version /proc/cmdline /proc/devices" [ -f /proc/atags ] && CMP_FILE_LIST="$CMP_FILE_LIST /proc/atags" +# List of files whose metadata (size/mtime/name) will be included in cached +# system state. +META_FILE_LIST="lib/udev/rules.d/* etc/udev/rules.d/*" + # Command to compute system configuration. sysconf_cmd () { cat -- $CMP_FILE_LIST + stat -L -c '%s %Y %n' -- $META_FILE_LIST | awk -F/ '{print $1 " " $NF;}' } [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache [ -f /etc/udev/udev.conf ] && . /etc/udev/udev.conf
meta/recipes-core/udev/udev/udev-cache +5 -0
@@ -25,9 +25,14 @@ DEVCACHE_REGEN="/dev/shm/udev-regen" # create to request cache regen CMP_FILE_LIST="/proc/version /proc/cmdline /proc/devices" [ -f /proc/atags ] && CMP_FILE_LIST="$CMP_FILE_LIST /proc/atags" +# List of files whose metadata (size/mtime/name) will be included in cached +# system state. +META_FILE_LIST="lib/udev/rules.d/* etc/udev/rules.d/*" + # Command to compute system configuration. sysconf_cmd () { cat -- $CMP_FILE_LIST + stat -L -c '%s %Y %n' -- $META_FILE_LIST | awk -F/ '{print $1 " " $NF;}' } [ -f /etc/default/udev-cache ] && . /etc/default/udev-cache
Signature · 1 line
2.0.4
PATCH v2 11/12 udev-cache: Update cache asynchronously
In reply to Richard TollertonDon't hold up the boot while the cache is being updated.
--- meta/recipes-core/udev/udev/udev-cache | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
meta/recipes-core/udev/udev/udev-cache +11 -8
@@ -43,14 +43,17 @@ fi if [ "$DEVCACHE" != "" -a -e "$DEVCACHE_REGEN" ]; then echo "Populating dev cache" - # Run sysconf_cmd before `tar`, not after, so that as little time as - # possible elapses between creating $SYSCONF_CACHED and $DEVCACHE. - sysconf_cmd > "$SYSCONF_CACHED" - find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ - | xargs tar cf "${DEVCACHE_TMP}" -T- - gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" - rm -f "${DEVCACHE_TMP}" - rm -f "$DEVCACHE_REGEN" + ( + # Run sysconf_cmd before `tar`, not after, so that as little + # time as possible elapses between creating $SYSCONF_CACHED and + # $DEVCACHE. + sysconf_cmd > "$SYSCONF_CACHED" + find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ + | xargs tar cf "${DEVCACHE_TMP}" -T- + gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" + rm -f "${DEVCACHE_TMP}" + rm -f "$DEVCACHE_REGEN" + ) & fi exit 0
Signature · 1 line
2.0.4
PATCH v2 12/12 udev-cache: refactor; improve verbosity and error handling
In reply to Richard TollertonMost of /etc/init.d/udev-cache is in a conditional block which can be replaced by a [ ... ] || exit 0 to reduce nesting. This also provides an opportunity to improve handling of VERBOSE a bit.
Previously, errors encountered during find, tar, etc. were ignored, which could mask some problems, or cause invalid cache files to get created. To solve: abort the update process (and report an error) if any command in the process fails; and write the system configuration to $SYSCONF_TMP first -- only update $SYSCONF_CACHED when we are certain that the cache tarball was successfully created.
--- meta/recipes-core/udev/udev/udev-cache | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-)
meta/recipes-core/udev/udev/udev-cache +20 -13
@@ -41,19 +41,26 @@ if [ "$ROOTFS_READ_ONLY" = "yes" ]; then exit 0 fi -if [ "$DEVCACHE" != "" -a -e "$DEVCACHE_REGEN" ]; then - echo "Populating dev cache" - ( - # Run sysconf_cmd before `tar`, not after, so that as little - # time as possible elapses between creating $SYSCONF_CACHED and - # $DEVCACHE. - sysconf_cmd > "$SYSCONF_CACHED" - find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ - | xargs tar cf "${DEVCACHE_TMP}" -T- - gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" - rm -f "${DEVCACHE_TMP}" - rm -f "$DEVCACHE_REGEN" - ) & +[ "$DEVCACHE" != "" ] || exit 0 +[ "${VERBOSE}" == "no" ] || echo -n "udev-cache: checking for ${DEVCACHE_REGEN}... " +if ! [ -e "$DEVCACHE_REGEN" ]; then + [ "${VERBOSE}" == "no" ] || echo "not found." + exit 0 fi +[ "${VERBOSE}" == "no" ] || echo "found; building cache." + +( + # Run sysconf_cmd before `tar`, not after, so that as little time as + # possible elapses between creating $SYSCONF_CACHED and $DEVCACHE. + if ! { sysconf_cmd > "$SYSCONF_TMP" \ + && find /dev -xdev \( -type b -o -type c -o -type l \) | cut -c 2- \ + | xargs tar cf "${DEVCACHE_TMP}" -T- \ + && gzip < "${DEVCACHE_TMP}" > "$DEVCACHE" \ + && mv "$SYSCONF_TMP" "$SYSCONF_CACHED" \ + && rm -f "$DEVCACHE_REGEN" "${DEVCACHE_TMP}"; } + then + echo "udev-cache: update failed!" + fi +) & exit 0
Signature · 1 line
2.0.4