Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-deduplicate-netdev-name-allocation'

Jakub Kicinski says:

====================
net: deduplicate netdev name allocation

After recent fixes we have even more duplicated code in netdev name
allocation helpers. There are two complications in this code.
First, __dev_alloc_name() clobbers its output arg even if allocation
fails, forcing callers to do extra copies. Second as our experience in
commit 55a5ec9b7710 ("Revert "net: core: dev_get_valid_name is now the same as dev_alloc_name_ns"") and
commit 029b6d140550 ("Revert "net: core: maybe return -EEXIST in __dev_alloc_name"")
taught us, user space is very sensitive to the exact error codes.

Align the callers of __dev_alloc_name(), and remove some of its
complexity.

v1: https://lore.kernel.org/all/20231020011856.3244410-1-kuba@kernel.org/
====================

Link: https://lore.kernel.org/r/20231023152346.3639749-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+45 -75
+45 -75
net/core/dev.c
··· 1057 1057 * __dev_alloc_name - allocate a name for a device 1058 1058 * @net: network namespace to allocate the device name in 1059 1059 * @name: name format string 1060 - * @buf: scratch buffer and result name string 1060 + * @res: result name string 1061 1061 * 1062 1062 * Passed a format string - eg "lt%d" it will try and find a suitable 1063 1063 * id. It scans list of devices to build up a free map, then chooses ··· 1068 1068 * Returns the number of the unit assigned or a negative errno code. 1069 1069 */ 1070 1070 1071 - static int __dev_alloc_name(struct net *net, const char *name, char *buf) 1071 + static int __dev_alloc_name(struct net *net, const char *name, char *res) 1072 1072 { 1073 1073 int i = 0; 1074 1074 const char *p; 1075 1075 const int max_netdevices = 8*PAGE_SIZE; 1076 1076 unsigned long *inuse; 1077 1077 struct net_device *d; 1078 + char buf[IFNAMSIZ]; 1078 1079 1079 - if (!dev_valid_name(name)) 1080 + /* Verify the string as this thing may have come from the user. 1081 + * There must be one "%d" and no other "%" characters. 1082 + */ 1083 + p = strchr(name, '%'); 1084 + if (!p || p[1] != 'd' || strchr(p + 2, '%')) 1080 1085 return -EINVAL; 1081 1086 1082 - p = strchr(name, '%'); 1083 - if (p) { 1084 - /* 1085 - * Verify the string as this thing may have come from 1086 - * the user. There must be either one "%d" and no other "%" 1087 - * characters. 1088 - */ 1089 - if (p[1] != 'd' || strchr(p + 2, '%')) 1090 - return -EINVAL; 1087 + /* Use one page as a bit array of possible slots */ 1088 + inuse = bitmap_zalloc(max_netdevices, GFP_ATOMIC); 1089 + if (!inuse) 1090 + return -ENOMEM; 1091 1091 1092 - /* Use one page as a bit array of possible slots */ 1093 - inuse = bitmap_zalloc(max_netdevices, GFP_ATOMIC); 1094 - if (!inuse) 1095 - return -ENOMEM; 1092 + for_each_netdev(net, d) { 1093 + struct netdev_name_node *name_node; 1096 1094 1097 - for_each_netdev(net, d) { 1098 - struct netdev_name_node *name_node; 1099 - 1100 - netdev_for_each_altname(d, name_node) { 1101 - if (!sscanf(name_node->name, name, &i)) 1102 - continue; 1103 - if (i < 0 || i >= max_netdevices) 1104 - continue; 1105 - 1106 - /* avoid cases where sscanf is not exact inverse of printf */ 1107 - snprintf(buf, IFNAMSIZ, name, i); 1108 - if (!strncmp(buf, name_node->name, IFNAMSIZ)) 1109 - __set_bit(i, inuse); 1110 - } 1111 - if (!sscanf(d->name, name, &i)) 1095 + netdev_for_each_altname(d, name_node) { 1096 + if (!sscanf(name_node->name, name, &i)) 1112 1097 continue; 1113 1098 if (i < 0 || i >= max_netdevices) 1114 1099 continue; 1115 1100 1116 - /* avoid cases where sscanf is not exact inverse of printf */ 1101 + /* avoid cases where sscanf is not exact inverse of printf */ 1117 1102 snprintf(buf, IFNAMSIZ, name, i); 1118 - if (!strncmp(buf, d->name, IFNAMSIZ)) 1103 + if (!strncmp(buf, name_node->name, IFNAMSIZ)) 1119 1104 __set_bit(i, inuse); 1120 1105 } 1106 + if (!sscanf(d->name, name, &i)) 1107 + continue; 1108 + if (i < 0 || i >= max_netdevices) 1109 + continue; 1121 1110 1122 - i = find_first_zero_bit(inuse, max_netdevices); 1123 - bitmap_free(inuse); 1111 + /* avoid cases where sscanf is not exact inverse of printf */ 1112 + snprintf(buf, IFNAMSIZ, name, i); 1113 + if (!strncmp(buf, d->name, IFNAMSIZ)) 1114 + __set_bit(i, inuse); 1124 1115 } 1125 1116 1126 - snprintf(buf, IFNAMSIZ, name, i); 1127 - if (!netdev_name_in_use(net, buf)) 1128 - return i; 1117 + i = find_first_zero_bit(inuse, max_netdevices); 1118 + bitmap_free(inuse); 1119 + if (i == max_netdevices) 1120 + return -ENFILE; 1129 1121 1130 - /* It is possible to run out of possible slots 1131 - * when the name is long and there isn't enough space left 1132 - * for the digits, or if all bits are used. 1133 - */ 1134 - return -ENFILE; 1122 + snprintf(res, IFNAMSIZ, name, i); 1123 + return i; 1135 1124 } 1136 1125 1126 + /* Returns negative errno or allocated unit id (see __dev_alloc_name()) */ 1137 1127 static int dev_prep_valid_name(struct net *net, struct net_device *dev, 1138 - const char *want_name, char *out_name) 1128 + const char *want_name, char *out_name, 1129 + int dup_errno) 1139 1130 { 1140 - int ret; 1141 - 1142 1131 if (!dev_valid_name(want_name)) 1143 1132 return -EINVAL; 1144 1133 1145 - if (strchr(want_name, '%')) { 1146 - ret = __dev_alloc_name(net, want_name, out_name); 1147 - return ret < 0 ? ret : 0; 1148 - } else if (netdev_name_in_use(net, want_name)) { 1149 - return -EEXIST; 1150 - } else if (out_name != want_name) { 1134 + if (strchr(want_name, '%')) 1135 + return __dev_alloc_name(net, want_name, out_name); 1136 + 1137 + if (netdev_name_in_use(net, want_name)) 1138 + return -dup_errno; 1139 + if (out_name != want_name) 1151 1140 strscpy(out_name, want_name, IFNAMSIZ); 1152 - } 1153 - 1154 1141 return 0; 1155 - } 1156 - 1157 - static int dev_alloc_name_ns(struct net *net, 1158 - struct net_device *dev, 1159 - const char *name) 1160 - { 1161 - char buf[IFNAMSIZ]; 1162 - int ret; 1163 - 1164 - BUG_ON(!net); 1165 - ret = __dev_alloc_name(net, name, buf); 1166 - if (ret >= 0) 1167 - strscpy(dev->name, buf, IFNAMSIZ); 1168 - return ret; 1169 1142 } 1170 1143 1171 1144 /** ··· 1157 1184 1158 1185 int dev_alloc_name(struct net_device *dev, const char *name) 1159 1186 { 1160 - return dev_alloc_name_ns(dev_net(dev), dev, name); 1187 + return dev_prep_valid_name(dev_net(dev), dev, name, dev->name, ENFILE); 1161 1188 } 1162 1189 EXPORT_SYMBOL(dev_alloc_name); 1163 1190 1164 1191 static int dev_get_valid_name(struct net *net, struct net_device *dev, 1165 1192 const char *name) 1166 1193 { 1167 - char buf[IFNAMSIZ]; 1168 1194 int ret; 1169 1195 1170 - ret = dev_prep_valid_name(net, dev, name, buf); 1171 - if (ret >= 0) 1172 - strscpy(dev->name, buf, IFNAMSIZ); 1173 - return ret; 1196 + ret = dev_prep_valid_name(net, dev, name, dev->name, EEXIST); 1197 + return ret < 0 ? ret : 0; 1174 1198 } 1175 1199 1176 1200 /** ··· 11105 11135 /* We get here if we can't use the current device name */ 11106 11136 if (!pat) 11107 11137 goto out; 11108 - err = dev_prep_valid_name(net, dev, pat, new_name); 11138 + err = dev_prep_valid_name(net, dev, pat, new_name, EEXIST); 11109 11139 if (err < 0) 11110 11140 goto out; 11111 11141 }