Merge lp:~vicamo/systemd/systemd into lp:ubuntu/vivid/systemd

Proposed by You-Sheng Yang
Status: Work in progress
Proposed branch: lp:~vicamo/systemd/systemd
Merge into: lp:ubuntu/vivid/systemd
Diff against target: 486 lines (+409/-7)
7 files modified
.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions (+116/-0)
.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules (+141/-0)
.pc/applied-patches (+1/-0)
debian/extra/rule_generator.functions (+1/-1)
debian/extra/write_net_rules (+16/-6)
debian/patches/Avoid-duplicated-udev-match-rules.patch (+133/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~vicamo/systemd/systemd
Reviewer Review Type Date Requested Status
Martin Pitt Disapprove
Review via email: mp+253919@code.launchpad.net

Description of the change

Please see https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1435687

This patch tries to reuse device names that is already written in tmp rules and has exactly the same match expr with the one that is going to be written out.

Per Didier Roche's comment, I'm not going to request for review until it's destiny has been decided in upstream Debian bug. And maybe until then, we can use PredictableNetworkInterfaceNames feature from systemd directly and do not even need this at all. Just for a backup for now.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

Structurally, please don't use a debian/patches/*.patch against files in debian/, just apply them inline. But I don't think we should do something like this at all. I'll follow up in the bug report, where we can discuss the solution. Thanks!

review: Disapprove

Unmerged revisions

75. By You-Sheng Yang

* Add Avoid-duplicated-udev-match-rules.patch to avoid duplicated
  udev match entries for the same network interface on devices with
  read-only rootfs. (LP: #1435687)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch'
2=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/.timestamp'
3=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch/debian'
4=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra'
5=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions'
6--- .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions 1970-01-01 00:00:00 +0000
7+++ .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions 2015-03-24 07:42:49 +0000
8@@ -0,0 +1,116 @@
9+# functions used by the udev rule generator
10+
11+# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
12+
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU General Public License as published by
15+# the Free Software Foundation, either version 2 of the License, or
16+# (at your option) any later version.
17+
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU General Public License for more details.
22+
23+# You should have received a copy of the GNU General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+
26+PATH='/sbin:/bin'
27+#
28+
29+PATH='/sbin:/bin'
30+
31+# Read a single line from file $1 in the $DEVPATH directory.
32+# The function must not return an error even if the file does not exist.
33+sysread() {
34+ local file="$1"
35+ [ -e "/sys$DEVPATH/$file" ] || return 0
36+ local value
37+ read value < "/sys$DEVPATH/$file" || return 0
38+ echo "$value"
39+}
40+
41+sysreadlink() {
42+ local file="$1"
43+ [ -e "/sys$DEVPATH/$file" ] || return 0
44+ readlink -f /sys$DEVPATH/$file 2> /dev/null || true
45+}
46+
47+# Return true if a directory is writeable.
48+writeable() {
49+ if ln -s test-link $1/.is-writeable 2> /dev/null; then
50+ rm -f $1/.is-writeable
51+ return 0
52+ else
53+ return 1
54+ fi
55+}
56+
57+# Create a lock file for the current rules file.
58+lock_rules_file() {
59+ RUNDIR=/run/udev
60+ [ -e "$RUNDIR" ] || return 0
61+
62+ RULES_LOCK="$RUNDIR/.lock-${RULES_FILE##*/}"
63+
64+ retry=30
65+ while ! mkdir $RULES_LOCK 2> /dev/null; do
66+ if [ $retry -eq 0 ]; then
67+ echo "Cannot lock $RULES_FILE!" >&2
68+ exit 2
69+ fi
70+ sleep 1
71+ retry=$(($retry - 1))
72+ done
73+}
74+
75+unlock_rules_file() {
76+ [ "$RULES_LOCK" ] || return 0
77+ rmdir $RULES_LOCK || true
78+}
79+
80+# Choose the real rules file if it is writeable or a temporary file if not.
81+# Both files should be checked later when looking for existing rules.
82+choose_rules_file() {
83+ RUNDIR=/run/udev
84+ local tmp_rules_file="$RUNDIR/tmp-rules--${RULES_FILE##*/}"
85+ [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1
86+
87+ if writeable ${RULES_FILE%/*}; then
88+ RO_RULES_FILE='/dev/null'
89+ else
90+ RO_RULES_FILE=$RULES_FILE
91+ RULES_FILE=$tmp_rules_file
92+ fi
93+}
94+
95+# Return the name of the first free device.
96+raw_find_next_available() {
97+ local links="$1"
98+
99+ local basename=${links%%[ 0-9]*}
100+ local max=-1
101+ for name in $links; do
102+ local num=${name#$basename}
103+ [ "$num" ] || num=0
104+ [ $num -gt $max ] && max=$num
105+ done
106+
107+ local max=$(($max + 1))
108+ # "name0" actually is just "name"
109+ [ $max -eq 0 ] && return
110+ echo "$max"
111+}
112+
113+# Find all rules matching a key (with action) and a pattern.
114+find_all_rules() {
115+ local key="$1"
116+ local linkre="$2"
117+ local match="$3"
118+
119+ local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
120+ echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
121+ $RO_RULES_FILE \
122+ $([ -e $RULES_FILE ] && echo $RULES_FILE) \
123+ 2>/dev/null)
124+}
125
126=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules'
127--- .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules 1970-01-01 00:00:00 +0000
128+++ .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules 2015-03-24 07:42:49 +0000
129@@ -0,0 +1,141 @@
130+#!/bin/sh -e
131+
132+# This script is run to create persistent network device naming rules
133+# based on properties of the device.
134+# If the interface needs to be renamed, INTERFACE_NEW=<name> will be printed
135+# on stdout to allow udev to IMPORT it.
136+
137+# variables used to communicate:
138+# MATCHADDR MAC address used for the match
139+# MATCHID bus_id used for the match
140+# MATCHDEVID dev_id used for the match
141+# MATCHDRV driver name used for the match
142+# MATCHIFTYPE interface type match
143+# COMMENT comment to add to the generated rule
144+# INTERFACE_NAME requested name supplied by external tool
145+# INTERFACE_NEW new interface name returned by rule writer
146+
147+# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
148+# Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
149+#
150+# This program is free software: you can redistribute it and/or modify
151+# it under the terms of the GNU General Public License as published by
152+# the Free Software Foundation, either version 2 of the License, or
153+# (at your option) any later version.
154+#
155+# This program is distributed in the hope that it will be useful,
156+# but WITHOUT ANY WARRANTY; without even the implied warranty of
157+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
158+# GNU General Public License for more details.
159+#
160+# You should have received a copy of the GNU General Public License
161+# along with this program. If not, see <http://www.gnu.org/licenses/>.
162+
163+# debug, if UDEV_LOG=<debug>
164+if [ -n "$UDEV_LOG" ]; then
165+ if [ "$UDEV_LOG" -ge 7 ]; then
166+ set -x
167+ fi
168+fi
169+
170+RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
171+
172+. /lib/udev/rule_generator.functions
173+
174+interface_name_taken() {
175+ local value="$(find_all_rules 'NAME=' $INTERFACE)"
176+ if [ "$value" ]; then
177+ return 0
178+ else
179+ return 1
180+ fi
181+}
182+
183+find_next_available() {
184+ raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
185+}
186+
187+write_rule() {
188+ local match="$1"
189+ local name="$2"
190+ local comment="$3"
191+
192+ {
193+ if [ "$PRINT_HEADER" ]; then
194+ PRINT_HEADER=
195+ echo "# This file was automatically generated by the $0"
196+ echo "# program, run by the persistent-net-generator.rules rules file."
197+ echo "#"
198+ echo "# You can modify it, as long as you keep each rule on a single"
199+ echo "# line, and change only the value of the NAME= key."
200+ fi
201+
202+ echo ""
203+ [ "$comment" ] && echo "# $comment"
204+ echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\""
205+ } >> $RULES_FILE
206+}
207+
208+if [ -z "$INTERFACE" ]; then
209+ echo "missing \$INTERFACE" >&2
210+ exit 1
211+fi
212+
213+# Prevent concurrent processes from modifying the file at the same time.
214+lock_rules_file
215+
216+# Check if the rules file is writeable.
217+choose_rules_file
218+
219+# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
220+if [ "$MATCHADDR" ]; then
221+ match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\""
222+fi
223+
224+if [ "$MATCHDRV" ]; then
225+ match="$match, DRIVERS==\"$MATCHDRV\""
226+fi
227+
228+if [ "$MATCHDEVID" ]; then
229+ match="$match, ATTR{dev_id}==\"$MATCHDEVID\""
230+fi
231+
232+if [ "$MATCHID" ]; then
233+ match="$match, KERNELS==\"$MATCHID\""
234+fi
235+
236+if [ "$MATCHIFTYPE" ]; then
237+ match="$match, ATTR{type}==\"$MATCHIFTYPE\""
238+fi
239+
240+if [ -z "$match" ]; then
241+ echo "missing valid match" >&2
242+ unlock_rules_file
243+ exit 1
244+fi
245+
246+basename=${INTERFACE%%[0-9]*}
247+match="$match, KERNEL==\"$basename*\""
248+
249+if [ "$INTERFACE_NAME" ]; then
250+ # external tools may request a custom name
251+ COMMENT="$COMMENT (custom name provided by external tool)"
252+ if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
253+ INTERFACE=$INTERFACE_NAME;
254+ echo "INTERFACE_NEW=$INTERFACE"
255+ fi
256+else
257+ # if a rule using the current name already exists, find a new name
258+ if interface_name_taken; then
259+ INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
260+ # prevent INTERFACE from being "eth" instead of "eth0"
261+ [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
262+ echo "INTERFACE_NEW=$INTERFACE"
263+ fi
264+fi
265+
266+write_rule "$match" "$INTERFACE" "$COMMENT"
267+
268+unlock_rules_file
269+
270+exit 0
271
272=== modified file '.pc/applied-patches'
273--- .pc/applied-patches 2014-04-27 13:21:11 +0000
274+++ .pc/applied-patches 2015-03-24 07:42:49 +0000
275@@ -64,3 +64,4 @@
276 Fix-a-race-condition-at-boot-with-serio-devices.patch
277 Create-disk-by-partlabel-links-for-mmcblk-partitions.patch
278 Support-system-image-read-only-etc.patch
279+Avoid-duplicated-udev-match-rules.patch
280
281=== modified file 'debian/extra/rule_generator.functions'
282--- debian/extra/rule_generator.functions 2013-11-06 14:01:26 +0000
283+++ debian/extra/rule_generator.functions 2015-03-24 07:42:49 +0000
284@@ -108,7 +108,7 @@
285 local linkre="$2"
286 local match="$3"
287
288- local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
289+ local search='.*'"$key"'"('"$linkre"')".*'
290 echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
291 $RO_RULES_FILE \
292 $([ -e $RULES_FILE ] && echo $RULES_FILE) \
293
294=== modified file 'debian/extra/write_net_rules'
295--- debian/extra/write_net_rules 2014-04-26 17:29:00 +0000
296+++ debian/extra/write_net_rules 2015-03-24 07:42:49 +0000
297@@ -43,7 +43,7 @@
298 . /lib/udev/rule_generator.functions
299
300 interface_name_taken() {
301- local value="$(find_all_rules 'NAME=' $INTERFACE)"
302+ local value="$(find_all_rules '[[:space:],]NAME=' $INTERFACE)"
303 if [ "$value" ]; then
304 return 0
305 else
306@@ -52,7 +52,7 @@
307 }
308
309 find_next_available() {
310- raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
311+ raw_find_next_available "$(find_all_rules '[[:space:],]NAME=' "$1")"
312 }
313
314 write_rule() {
315@@ -127,10 +127,20 @@
316 else
317 # if a rule using the current name already exists, find a new name
318 if interface_name_taken; then
319- INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
320- # prevent INTERFACE from being "eth" instead of "eth0"
321- [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
322- echo "INTERFACE_NEW=$INTERFACE"
323+ match_exp="$(echo "$match" | sed -e s/{/\\\\{/g -e s/}/\\\\}/g -e s/*/\\\\*/g -e s/?/\\\\?/g)"
324+ INTERFACE_NAME="$(find_all_rules 'SUBSYSTEM=="net", ACTION=="add"'"${match_exp}"', NAME=' "$basename[0-9]*")"
325+ if [ -z "$INTERFACE_NAME" ]; then
326+ INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
327+ # prevent INTERFACE from being "eth" instead of "eth0"
328+ [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
329+ echo "INTERFACE_NEW=$INTERFACE"
330+ elif [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
331+ INTERFACE=$INTERFACE_NAME
332+ echo "INTERFACE_NEW=$INTERFACE"
333+ else
334+ unlock_rules_file
335+ exit 0
336+ fi
337 fi
338 fi
339
340
341=== added file 'debian/patches/Avoid-duplicated-udev-match-rules.patch'
342--- debian/patches/Avoid-duplicated-udev-match-rules.patch 1970-01-01 00:00:00 +0000
343+++ debian/patches/Avoid-duplicated-udev-match-rules.patch 2015-03-24 07:42:49 +0000
344@@ -0,0 +1,133 @@
345+From ca74f1efff06983160fe28bc3f931de73438de0a Mon Sep 17 00:00:00 2001
346+From: You-Sheng Yang <vicamo@gmail.com>
347+Date: Wed, 18 Mar 2015 11:33:32 +0800
348+Subject: [PATCH] Avoid duplicated udev match rules
349+
350+On devices with read-only rootfs, e.g. mobile phones, nic device number
351+(wlan<N>) may increase every time disabled and re-enabled. To be more
352+precisely, this happens only on devices when disabling a nic removes the
353+corresponding driver.
354+
355+"/lib/udev/rules.d/75-persistent-net-generator.rules" checks whether
356+NAME attribute has been assigned to wlan<N> device: if yes, skip all the
357+followed steps, or, call to "/lib/udev/write_net_rules" to generate a
358+persistent device name rule file. That persistent file should be created
359+under "/etc/udev/rules.d" and named "70-persistent-net.rules", so it
360+guarantees NAME attribute should be assigned if available before being
361+read. However, when rootfs was previously mounted as read-only, a file
362+"/run/udev/tmp-rules--70-persistent-net.rules" is created instead. This
363+temporary file is supposed to be moved back into "/etc/udev/rules.d" by
364+a systemd service udev-finish right after the system finishes start-up
365+chaos. Again, if rootfs is still mounted as read-only, this move will
366+certainly fail. One last important thing, /run/udev is _NOT_ included in
367+udev rules inclusion paths, so any rules written here will not be taken
368+into account when processing uevents.
369+
370+So, when wlan0 is probed for the first time on a device with read-only
371+rootfs, udev creates "/run/udev/tmp-rules--70-persistent-net.rules" and
372+inserts one rule for it. When wlan0 is disabled and re-enabled, since
373+"/run/udev/tmp-rules--70-persistent-net.rules" is not taken into
374+account, its NAME attribute will not be set, and udev recognize it as a
375+new nic and tries to write another rule for it again. However, in this
376+time, "wlan0" has been taken in the previously written temporary rules
377+file, so "wlan1" is chosen instead, and an exactly the same matching
378+rule (except for NAME= part) is appended to
379+"/run/udev/tmp-rules--70-persistent-net.rules". When the device is
380+again disabled and re-enabled, "wlan2" will be assigned. And so on ....
381+
382+This patch add an additional step to search if current match rule had
383+been previously written and reuse that interface name if available.
384+
385+Signed-off-by: You-Sheng Yang <vicamo@gmail.com>
386+
387+diff --git a/debian/extra/rule_generator.functions b/debian/extra/rule_generator.functions
388+index 925193e..a676ff7 100644
389+--- a/debian/extra/rule_generator.functions
390++++ b/debian/extra/rule_generator.functions
391+@@ -100,14 +100,14 @@ raw_find_next_available() {
392+ }
393+
394+ # Find all rules matching a key (with action) and a pattern.
395+ find_all_rules() {
396+ local key="$1"
397+ local linkre="$2"
398+ local match="$3"
399+
400+- local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
401++ local search='.*'"$key"'"('"$linkre"')".*'
402+ echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
403+ $RO_RULES_FILE \
404+ $([ -e $RULES_FILE ] && echo $RULES_FILE) \
405+ 2>/dev/null)
406+ }
407+diff --git a/debian/extra/write_net_rules b/debian/extra/write_net_rules
408+index 4379792..b05ed43 100644
409+--- a/debian/extra/write_net_rules
410++++ b/debian/extra/write_net_rules
411+@@ -38,26 +38,26 @@ if [ -n "$UDEV_LOG" ]; then
412+ fi
413+ fi
414+
415+ RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
416+
417+ . /lib/udev/rule_generator.functions
418+
419+ interface_name_taken() {
420+- local value="$(find_all_rules 'NAME=' $INTERFACE)"
421++ local value="$(find_all_rules '[[:space:],]NAME=' $INTERFACE)"
422+ if [ "$value" ]; then
423+ return 0
424+ else
425+ return 1
426+ fi
427+ }
428+
429+ find_next_available() {
430+- raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
431++ raw_find_next_available "$(find_all_rules '[[:space:],]NAME=' "$1")"
432+ }
433+
434+ write_rule() {
435+ local match="$1"
436+ local name="$2"
437+ local comment="$3"
438+
439+ {
440+@@ -122,20 +122,30 @@ if [ "$INTERFACE_NAME" ]; then
441+ COMMENT="$COMMENT (custom name provided by external tool)"
442+ if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
443+ INTERFACE=$INTERFACE_NAME;
444+ echo "INTERFACE_NEW=$INTERFACE"
445+ fi
446+ else
447+ # if a rule using the current name already exists, find a new name
448+ if interface_name_taken; then
449+- INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
450+- # prevent INTERFACE from being "eth" instead of "eth0"
451+- [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
452+- echo "INTERFACE_NEW=$INTERFACE"
453++ match_exp="$(echo "$match" | sed -e s/{/\\\\{/g -e s/}/\\\\}/g -e s/*/\\\\*/g -e s/?/\\\\?/g)"
454++ INTERFACE_NAME="$(find_all_rules 'SUBSYSTEM=="net", ACTION=="add"'"${match_exp}"', NAME=' "$basename[0-9]*")"
455++ if [ -z "$INTERFACE_NAME" ]; then
456++ INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
457++ # prevent INTERFACE from being "eth" instead of "eth0"
458++ [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
459++ echo "INTERFACE_NEW=$INTERFACE"
460++ elif [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
461++ INTERFACE=$INTERFACE_NAME
462++ echo "INTERFACE_NEW=$INTERFACE"
463++ else
464++ unlock_rules_file
465++ exit 0
466++ fi
467+ fi
468+ fi
469+
470+ write_rule "$match" "$INTERFACE" "$COMMENT"
471+
472+ unlock_rules_file
473+
474+ exit 0
475+--
476+2.1.4
477+
478
479=== modified file 'debian/patches/series'
480--- debian/patches/series 2014-04-27 13:21:11 +0000
481+++ debian/patches/series 2015-03-24 07:42:49 +0000
482@@ -64,3 +64,4 @@
483 Fix-a-race-condition-at-boot-with-serio-devices.patch
484 Create-disk-by-partlabel-links-for-mmcblk-partitions.patch
485 Support-system-image-read-only-etc.patch
486+Avoid-duplicated-udev-match-rules.patch

Subscribers

People subscribed via source and target branches