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

[PATCH] configfs: Pin configfs subsystems separately from new config_items.

configfs_mkdir() creates a new item by calling its parent's
->make_item/group() functions. Once that object is created,
configfs_mkdir() calls try_module_get() on the new item's module. If it
succeeds, the module owning the new item cannot be unloaded, and
configfs is safe to reference the item.

If the item and the subsystem it belongs to are part of the same module,
the subsystem is also pinned. This is the common case.

However, if the subsystem is made up of multiple modules, this may not
pin the subsystem. Thus, it would be possible to unload the toplevel
subsystem module while there is still a child item. Thus, we now
try_module_get() the subsystem's module. This only really affects
children of the toplevel subsystem group. Deeper children already have
their parents pinned.

Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>

authored by

Joel Becker and committed by
Mark Fasheh
70526b67 99cefda4

+33 -9
+33 -9
fs/configfs/dir.c
··· 1100 1100 struct configfs_subsystem *subsys; 1101 1101 struct configfs_dirent *sd; 1102 1102 struct config_item_type *type; 1103 - struct module *owner = NULL; 1103 + struct module *subsys_owner = NULL, *new_item_owner = NULL; 1104 1104 char *name; 1105 1105 1106 1106 if (dentry->d_parent == configfs_sb->s_root) { ··· 1137 1137 goto out_put; 1138 1138 } 1139 1139 1140 + /* 1141 + * The subsystem may belong to a different module than the item 1142 + * being created. We don't want to safely pin the new item but 1143 + * fail to pin the subsystem it sits under. 1144 + */ 1145 + if (!subsys->su_group.cg_item.ci_type) { 1146 + ret = -EINVAL; 1147 + goto out_put; 1148 + } 1149 + subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; 1150 + if (!try_module_get(subsys_owner)) { 1151 + ret = -EINVAL; 1152 + goto out_put; 1153 + } 1154 + 1140 1155 name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); 1141 1156 if (!name) { 1142 1157 ret = -ENOMEM; 1143 - goto out_put; 1158 + goto out_subsys_put; 1144 1159 } 1145 1160 1146 1161 snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); ··· 1187 1172 * If ret != 0, then link_obj() was never called. 1188 1173 * There are no extra references to clean up. 1189 1174 */ 1190 - goto out_put; 1175 + goto out_subsys_put; 1191 1176 } 1192 1177 1193 1178 /* ··· 1201 1186 goto out_unlink; 1202 1187 } 1203 1188 1204 - owner = type->ct_owner; 1205 - if (!try_module_get(owner)) { 1189 + new_item_owner = type->ct_owner; 1190 + if (!try_module_get(new_item_owner)) { 1206 1191 ret = -EINVAL; 1207 1192 goto out_unlink; 1208 1193 } ··· 1251 1236 mutex_unlock(&subsys->su_mutex); 1252 1237 1253 1238 if (module_got) 1254 - module_put(owner); 1239 + module_put(new_item_owner); 1255 1240 } 1241 + 1242 + out_subsys_put: 1243 + if (ret) 1244 + module_put(subsys_owner); 1256 1245 1257 1246 out_put: 1258 1247 /* ··· 1276 1257 struct config_item *item; 1277 1258 struct configfs_subsystem *subsys; 1278 1259 struct configfs_dirent *sd; 1279 - struct module *owner = NULL; 1260 + struct module *subsys_owner = NULL, *dead_item_owner = NULL; 1280 1261 int ret; 1281 1262 1282 1263 if (dentry->d_parent == configfs_sb->s_root) ··· 1302 1283 config_item_put(parent_item); 1303 1284 return -EINVAL; 1304 1285 } 1286 + 1287 + /* configfs_mkdir() shouldn't have allowed this */ 1288 + BUG_ON(!subsys->su_group.cg_item.ci_type); 1289 + subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; 1305 1290 1306 1291 /* 1307 1292 * Ensure that no racing symlink() will make detach_prep() fail while ··· 1344 1321 config_item_put(parent_item); 1345 1322 1346 1323 if (item->ci_type) 1347 - owner = item->ci_type->ct_owner; 1324 + dead_item_owner = item->ci_type->ct_owner; 1348 1325 1349 1326 if (sd->s_type & CONFIGFS_USET_DIR) { 1350 1327 configfs_detach_group(item); ··· 1366 1343 /* Drop our reference from above */ 1367 1344 config_item_put(item); 1368 1345 1369 - module_put(owner); 1346 + module_put(dead_item_owner); 1347 + module_put(subsys_owner); 1370 1348 1371 1349 return 0; 1372 1350 }