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
=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch'
=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/.timestamp'
=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch/debian'
=== added directory '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra'
=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions'
--- .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions 1970-01-01 00:00:00 +0000
+++ .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/rule_generator.functions 2015-03-24 07:42:49 +0000
@@ -0,0 +1,116 @@
1# functions used by the udev rule generator
2
3# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
4
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 2 of the License, or
8# (at your option) any later version.
9
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18PATH='/sbin:/bin'
19#
20
21PATH='/sbin:/bin'
22
23# Read a single line from file $1 in the $DEVPATH directory.
24# The function must not return an error even if the file does not exist.
25sysread() {
26 local file="$1"
27 [ -e "/sys$DEVPATH/$file" ] || return 0
28 local value
29 read value < "/sys$DEVPATH/$file" || return 0
30 echo "$value"
31}
32
33sysreadlink() {
34 local file="$1"
35 [ -e "/sys$DEVPATH/$file" ] || return 0
36 readlink -f /sys$DEVPATH/$file 2> /dev/null || true
37}
38
39# Return true if a directory is writeable.
40writeable() {
41 if ln -s test-link $1/.is-writeable 2> /dev/null; then
42 rm -f $1/.is-writeable
43 return 0
44 else
45 return 1
46 fi
47}
48
49# Create a lock file for the current rules file.
50lock_rules_file() {
51 RUNDIR=/run/udev
52 [ -e "$RUNDIR" ] || return 0
53
54 RULES_LOCK="$RUNDIR/.lock-${RULES_FILE##*/}"
55
56 retry=30
57 while ! mkdir $RULES_LOCK 2> /dev/null; do
58 if [ $retry -eq 0 ]; then
59 echo "Cannot lock $RULES_FILE!" >&2
60 exit 2
61 fi
62 sleep 1
63 retry=$(($retry - 1))
64 done
65}
66
67unlock_rules_file() {
68 [ "$RULES_LOCK" ] || return 0
69 rmdir $RULES_LOCK || true
70}
71
72# Choose the real rules file if it is writeable or a temporary file if not.
73# Both files should be checked later when looking for existing rules.
74choose_rules_file() {
75 RUNDIR=/run/udev
76 local tmp_rules_file="$RUNDIR/tmp-rules--${RULES_FILE##*/}"
77 [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1
78
79 if writeable ${RULES_FILE%/*}; then
80 RO_RULES_FILE='/dev/null'
81 else
82 RO_RULES_FILE=$RULES_FILE
83 RULES_FILE=$tmp_rules_file
84 fi
85}
86
87# Return the name of the first free device.
88raw_find_next_available() {
89 local links="$1"
90
91 local basename=${links%%[ 0-9]*}
92 local max=-1
93 for name in $links; do
94 local num=${name#$basename}
95 [ "$num" ] || num=0
96 [ $num -gt $max ] && max=$num
97 done
98
99 local max=$(($max + 1))
100 # "name0" actually is just "name"
101 [ $max -eq 0 ] && return
102 echo "$max"
103}
104
105# Find all rules matching a key (with action) and a pattern.
106find_all_rules() {
107 local key="$1"
108 local linkre="$2"
109 local match="$3"
110
111 local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
112 echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
113 $RO_RULES_FILE \
114 $([ -e $RULES_FILE ] && echo $RULES_FILE) \
115 2>/dev/null)
116}
0117
=== added file '.pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules'
--- .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules 1970-01-01 00:00:00 +0000
+++ .pc/Avoid-duplicated-udev-match-rules.patch/debian/extra/write_net_rules 2015-03-24 07:42:49 +0000
@@ -0,0 +1,141 @@
1#!/bin/sh -e
2
3# This script is run to create persistent network device naming rules
4# based on properties of the device.
5# If the interface needs to be renamed, INTERFACE_NEW=<name> will be printed
6# on stdout to allow udev to IMPORT it.
7
8# variables used to communicate:
9# MATCHADDR MAC address used for the match
10# MATCHID bus_id used for the match
11# MATCHDEVID dev_id used for the match
12# MATCHDRV driver name used for the match
13# MATCHIFTYPE interface type match
14# COMMENT comment to add to the generated rule
15# INTERFACE_NAME requested name supplied by external tool
16# INTERFACE_NEW new interface name returned by rule writer
17
18# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
19# Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
20#
21# This program is free software: you can redistribute it and/or modify
22# it under the terms of the GNU General Public License as published by
23# the Free Software Foundation, either version 2 of the License, or
24# (at your option) any later version.
25#
26# This program is distributed in the hope that it will be useful,
27# but WITHOUT ANY WARRANTY; without even the implied warranty of
28# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29# GNU General Public License for more details.
30#
31# You should have received a copy of the GNU General Public License
32# along with this program. If not, see <http://www.gnu.org/licenses/>.
33
34# debug, if UDEV_LOG=<debug>
35if [ -n "$UDEV_LOG" ]; then
36 if [ "$UDEV_LOG" -ge 7 ]; then
37 set -x
38 fi
39fi
40
41RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
42
43. /lib/udev/rule_generator.functions
44
45interface_name_taken() {
46 local value="$(find_all_rules 'NAME=' $INTERFACE)"
47 if [ "$value" ]; then
48 return 0
49 else
50 return 1
51 fi
52}
53
54find_next_available() {
55 raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
56}
57
58write_rule() {
59 local match="$1"
60 local name="$2"
61 local comment="$3"
62
63 {
64 if [ "$PRINT_HEADER" ]; then
65 PRINT_HEADER=
66 echo "# This file was automatically generated by the $0"
67 echo "# program, run by the persistent-net-generator.rules rules file."
68 echo "#"
69 echo "# You can modify it, as long as you keep each rule on a single"
70 echo "# line, and change only the value of the NAME= key."
71 fi
72
73 echo ""
74 [ "$comment" ] && echo "# $comment"
75 echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\""
76 } >> $RULES_FILE
77}
78
79if [ -z "$INTERFACE" ]; then
80 echo "missing \$INTERFACE" >&2
81 exit 1
82fi
83
84# Prevent concurrent processes from modifying the file at the same time.
85lock_rules_file
86
87# Check if the rules file is writeable.
88choose_rules_file
89
90# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
91if [ "$MATCHADDR" ]; then
92 match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\""
93fi
94
95if [ "$MATCHDRV" ]; then
96 match="$match, DRIVERS==\"$MATCHDRV\""
97fi
98
99if [ "$MATCHDEVID" ]; then
100 match="$match, ATTR{dev_id}==\"$MATCHDEVID\""
101fi
102
103if [ "$MATCHID" ]; then
104 match="$match, KERNELS==\"$MATCHID\""
105fi
106
107if [ "$MATCHIFTYPE" ]; then
108 match="$match, ATTR{type}==\"$MATCHIFTYPE\""
109fi
110
111if [ -z "$match" ]; then
112 echo "missing valid match" >&2
113 unlock_rules_file
114 exit 1
115fi
116
117basename=${INTERFACE%%[0-9]*}
118match="$match, KERNEL==\"$basename*\""
119
120if [ "$INTERFACE_NAME" ]; then
121 # external tools may request a custom name
122 COMMENT="$COMMENT (custom name provided by external tool)"
123 if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
124 INTERFACE=$INTERFACE_NAME;
125 echo "INTERFACE_NEW=$INTERFACE"
126 fi
127else
128 # if a rule using the current name already exists, find a new name
129 if interface_name_taken; then
130 INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
131 # prevent INTERFACE from being "eth" instead of "eth0"
132 [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
133 echo "INTERFACE_NEW=$INTERFACE"
134 fi
135fi
136
137write_rule "$match" "$INTERFACE" "$COMMENT"
138
139unlock_rules_file
140
141exit 0
0142
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2014-04-27 13:21:11 +0000
+++ .pc/applied-patches 2015-03-24 07:42:49 +0000
@@ -64,3 +64,4 @@
64Fix-a-race-condition-at-boot-with-serio-devices.patch64Fix-a-race-condition-at-boot-with-serio-devices.patch
65Create-disk-by-partlabel-links-for-mmcblk-partitions.patch65Create-disk-by-partlabel-links-for-mmcblk-partitions.patch
66Support-system-image-read-only-etc.patch66Support-system-image-read-only-etc.patch
67Avoid-duplicated-udev-match-rules.patch
6768
=== modified file 'debian/extra/rule_generator.functions'
--- debian/extra/rule_generator.functions 2013-11-06 14:01:26 +0000
+++ debian/extra/rule_generator.functions 2015-03-24 07:42:49 +0000
@@ -108,7 +108,7 @@
108 local linkre="$2"108 local linkre="$2"
109 local match="$3"109 local match="$3"
110110
111 local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'111 local search='.*'"$key"'"('"$linkre"')".*'
112 echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \112 echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
113 $RO_RULES_FILE \113 $RO_RULES_FILE \
114 $([ -e $RULES_FILE ] && echo $RULES_FILE) \114 $([ -e $RULES_FILE ] && echo $RULES_FILE) \
115115
=== modified file 'debian/extra/write_net_rules'
--- debian/extra/write_net_rules 2014-04-26 17:29:00 +0000
+++ debian/extra/write_net_rules 2015-03-24 07:42:49 +0000
@@ -43,7 +43,7 @@
43. /lib/udev/rule_generator.functions43. /lib/udev/rule_generator.functions
4444
45interface_name_taken() {45interface_name_taken() {
46 local value="$(find_all_rules 'NAME=' $INTERFACE)"46 local value="$(find_all_rules '[[:space:],]NAME=' $INTERFACE)"
47 if [ "$value" ]; then47 if [ "$value" ]; then
48 return 048 return 0
49 else49 else
@@ -52,7 +52,7 @@
52}52}
5353
54find_next_available() {54find_next_available() {
55 raw_find_next_available "$(find_all_rules 'NAME=' "$1")"55 raw_find_next_available "$(find_all_rules '[[:space:],]NAME=' "$1")"
56}56}
5757
58write_rule() {58write_rule() {
@@ -127,10 +127,20 @@
127else127else
128 # if a rule using the current name already exists, find a new name128 # if a rule using the current name already exists, find a new name
129 if interface_name_taken; then129 if interface_name_taken; then
130 INTERFACE="$basename$(find_next_available "$basename[0-9]*")"130 match_exp="$(echo "$match" | sed -e s/{/\\\\{/g -e s/}/\\\\}/g -e s/*/\\\\*/g -e s/?/\\\\?/g)"
131 # prevent INTERFACE from being "eth" instead of "eth0"131 INTERFACE_NAME="$(find_all_rules 'SUBSYSTEM=="net", ACTION=="add"'"${match_exp}"', NAME=' "$basename[0-9]*")"
132 [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0132 if [ -z "$INTERFACE_NAME" ]; then
133 echo "INTERFACE_NEW=$INTERFACE"133 INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
134 # prevent INTERFACE from being "eth" instead of "eth0"
135 [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
136 echo "INTERFACE_NEW=$INTERFACE"
137 elif [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
138 INTERFACE=$INTERFACE_NAME
139 echo "INTERFACE_NEW=$INTERFACE"
140 else
141 unlock_rules_file
142 exit 0
143 fi
134 fi144 fi
135fi145fi
136146
137147
=== added file 'debian/patches/Avoid-duplicated-udev-match-rules.patch'
--- debian/patches/Avoid-duplicated-udev-match-rules.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/Avoid-duplicated-udev-match-rules.patch 2015-03-24 07:42:49 +0000
@@ -0,0 +1,133 @@
1From ca74f1efff06983160fe28bc3f931de73438de0a Mon Sep 17 00:00:00 2001
2From: You-Sheng Yang <vicamo@gmail.com>
3Date: Wed, 18 Mar 2015 11:33:32 +0800
4Subject: [PATCH] Avoid duplicated udev match rules
5
6On devices with read-only rootfs, e.g. mobile phones, nic device number
7(wlan<N>) may increase every time disabled and re-enabled. To be more
8precisely, this happens only on devices when disabling a nic removes the
9corresponding driver.
10
11"/lib/udev/rules.d/75-persistent-net-generator.rules" checks whether
12NAME attribute has been assigned to wlan<N> device: if yes, skip all the
13followed steps, or, call to "/lib/udev/write_net_rules" to generate a
14persistent device name rule file. That persistent file should be created
15under "/etc/udev/rules.d" and named "70-persistent-net.rules", so it
16guarantees NAME attribute should be assigned if available before being
17read. However, when rootfs was previously mounted as read-only, a file
18"/run/udev/tmp-rules--70-persistent-net.rules" is created instead. This
19temporary file is supposed to be moved back into "/etc/udev/rules.d" by
20a systemd service udev-finish right after the system finishes start-up
21chaos. Again, if rootfs is still mounted as read-only, this move will
22certainly fail. One last important thing, /run/udev is _NOT_ included in
23udev rules inclusion paths, so any rules written here will not be taken
24into account when processing uevents.
25
26So, when wlan0 is probed for the first time on a device with read-only
27rootfs, udev creates "/run/udev/tmp-rules--70-persistent-net.rules" and
28inserts one rule for it. When wlan0 is disabled and re-enabled, since
29"/run/udev/tmp-rules--70-persistent-net.rules" is not taken into
30account, its NAME attribute will not be set, and udev recognize it as a
31new nic and tries to write another rule for it again. However, in this
32time, "wlan0" has been taken in the previously written temporary rules
33file, so "wlan1" is chosen instead, and an exactly the same matching
34rule (except for NAME= part) is appended to
35"/run/udev/tmp-rules--70-persistent-net.rules". When the device is
36again disabled and re-enabled, "wlan2" will be assigned. And so on ....
37
38This patch add an additional step to search if current match rule had
39been previously written and reuse that interface name if available.
40
41Signed-off-by: You-Sheng Yang <vicamo@gmail.com>
42
43diff --git a/debian/extra/rule_generator.functions b/debian/extra/rule_generator.functions
44index 925193e..a676ff7 100644
45--- a/debian/extra/rule_generator.functions
46+++ b/debian/extra/rule_generator.functions
47@@ -100,14 +100,14 @@ raw_find_next_available() {
48 }
49
50 # Find all rules matching a key (with action) and a pattern.
51 find_all_rules() {
52 local key="$1"
53 local linkre="$2"
54 local match="$3"
55
56- local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
57+ local search='.*'"$key"'"('"$linkre"')".*'
58 echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
59 $RO_RULES_FILE \
60 $([ -e $RULES_FILE ] && echo $RULES_FILE) \
61 2>/dev/null)
62 }
63diff --git a/debian/extra/write_net_rules b/debian/extra/write_net_rules
64index 4379792..b05ed43 100644
65--- a/debian/extra/write_net_rules
66+++ b/debian/extra/write_net_rules
67@@ -38,26 +38,26 @@ if [ -n "$UDEV_LOG" ]; then
68 fi
69 fi
70
71 RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
72
73 . /lib/udev/rule_generator.functions
74
75 interface_name_taken() {
76- local value="$(find_all_rules 'NAME=' $INTERFACE)"
77+ local value="$(find_all_rules '[[:space:],]NAME=' $INTERFACE)"
78 if [ "$value" ]; then
79 return 0
80 else
81 return 1
82 fi
83 }
84
85 find_next_available() {
86- raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
87+ raw_find_next_available "$(find_all_rules '[[:space:],]NAME=' "$1")"
88 }
89
90 write_rule() {
91 local match="$1"
92 local name="$2"
93 local comment="$3"
94
95 {
96@@ -122,20 +122,30 @@ if [ "$INTERFACE_NAME" ]; then
97 COMMENT="$COMMENT (custom name provided by external tool)"
98 if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
99 INTERFACE=$INTERFACE_NAME;
100 echo "INTERFACE_NEW=$INTERFACE"
101 fi
102 else
103 # if a rule using the current name already exists, find a new name
104 if interface_name_taken; then
105- INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
106- # prevent INTERFACE from being "eth" instead of "eth0"
107- [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
108- echo "INTERFACE_NEW=$INTERFACE"
109+ match_exp="$(echo "$match" | sed -e s/{/\\\\{/g -e s/}/\\\\}/g -e s/*/\\\\*/g -e s/?/\\\\?/g)"
110+ INTERFACE_NAME="$(find_all_rules 'SUBSYSTEM=="net", ACTION=="add"'"${match_exp}"', NAME=' "$basename[0-9]*")"
111+ if [ -z "$INTERFACE_NAME" ]; then
112+ INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
113+ # prevent INTERFACE from being "eth" instead of "eth0"
114+ [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
115+ echo "INTERFACE_NEW=$INTERFACE"
116+ elif [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
117+ INTERFACE=$INTERFACE_NAME
118+ echo "INTERFACE_NEW=$INTERFACE"
119+ else
120+ unlock_rules_file
121+ exit 0
122+ fi
123 fi
124 fi
125
126 write_rule "$match" "$INTERFACE" "$COMMENT"
127
128 unlock_rules_file
129
130 exit 0
131--
1322.1.4
133
0134
=== modified file 'debian/patches/series'
--- debian/patches/series 2014-04-27 13:21:11 +0000
+++ debian/patches/series 2015-03-24 07:42:49 +0000
@@ -64,3 +64,4 @@
64Fix-a-race-condition-at-boot-with-serio-devices.patch64Fix-a-race-condition-at-boot-with-serio-devices.patch
65Create-disk-by-partlabel-links-for-mmcblk-partitions.patch65Create-disk-by-partlabel-links-for-mmcblk-partitions.patch
66Support-system-image-read-only-etc.patch66Support-system-image-read-only-etc.patch
67Avoid-duplicated-udev-match-rules.patch

Subscribers

People subscribed via source and target branches