diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index a89058b39884..7a8db78a91d2 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -1100,7 +1100,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1100 | struct configfs_subsystem *subsys; | 1100 | struct configfs_subsystem *subsys; |
1101 | struct configfs_dirent *sd; | 1101 | struct configfs_dirent *sd; |
1102 | struct config_item_type *type; | 1102 | struct config_item_type *type; |
1103 | struct module *owner = NULL; | 1103 | struct module *subsys_owner = NULL, *new_item_owner = NULL; |
1104 | char *name; | 1104 | char *name; |
1105 | 1105 | ||
1106 | if (dentry->d_parent == configfs_sb->s_root) { | 1106 | if (dentry->d_parent == configfs_sb->s_root) { |
@@ -1137,10 +1137,25 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1137 | goto out_put; | 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 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); | 1155 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); |
1141 | if (!name) { | 1156 | if (!name) { |
1142 | ret = -ENOMEM; | 1157 | ret = -ENOMEM; |
1143 | goto out_put; | 1158 | goto out_subsys_put; |
1144 | } | 1159 | } |
1145 | 1160 | ||
1146 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); | 1161 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); |
@@ -1172,7 +1187,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1172 | * If ret != 0, then link_obj() was never called. | 1187 | * If ret != 0, then link_obj() was never called. |
1173 | * There are no extra references to clean up. | 1188 | * There are no extra references to clean up. |
1174 | */ | 1189 | */ |
1175 | goto out_put; | 1190 | goto out_subsys_put; |
1176 | } | 1191 | } |
1177 | 1192 | ||
1178 | /* | 1193 | /* |
@@ -1186,8 +1201,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1186 | goto out_unlink; | 1201 | goto out_unlink; |
1187 | } | 1202 | } |
1188 | 1203 | ||
1189 | owner = type->ct_owner; | 1204 | new_item_owner = type->ct_owner; |
1190 | if (!try_module_get(owner)) { | 1205 | if (!try_module_get(new_item_owner)) { |
1191 | ret = -EINVAL; | 1206 | ret = -EINVAL; |
1192 | goto out_unlink; | 1207 | goto out_unlink; |
1193 | } | 1208 | } |
@@ -1236,9 +1251,13 @@ out_unlink: | |||
1236 | mutex_unlock(&subsys->su_mutex); | 1251 | mutex_unlock(&subsys->su_mutex); |
1237 | 1252 | ||
1238 | if (module_got) | 1253 | if (module_got) |
1239 | module_put(owner); | 1254 | module_put(new_item_owner); |
1240 | } | 1255 | } |
1241 | 1256 | ||
1257 | out_subsys_put: | ||
1258 | if (ret) | ||
1259 | module_put(subsys_owner); | ||
1260 | |||
1242 | out_put: | 1261 | out_put: |
1243 | /* | 1262 | /* |
1244 | * link_obj()/link_group() took a reference from child->parent, | 1263 | * link_obj()/link_group() took a reference from child->parent, |
@@ -1257,7 +1276,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1257 | struct config_item *item; | 1276 | struct config_item *item; |
1258 | struct configfs_subsystem *subsys; | 1277 | struct configfs_subsystem *subsys; |
1259 | struct configfs_dirent *sd; | 1278 | struct configfs_dirent *sd; |
1260 | struct module *owner = NULL; | 1279 | struct module *subsys_owner = NULL, *dead_item_owner = NULL; |
1261 | int ret; | 1280 | int ret; |
1262 | 1281 | ||
1263 | if (dentry->d_parent == configfs_sb->s_root) | 1282 | if (dentry->d_parent == configfs_sb->s_root) |
@@ -1284,6 +1303,10 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1284 | return -EINVAL; | 1303 | return -EINVAL; |
1285 | } | 1304 | } |
1286 | 1305 | ||
1306 | /* configfs_mkdir() shouldn't have allowed this */ | ||
1307 | BUG_ON(!subsys->su_group.cg_item.ci_type); | ||
1308 | subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; | ||
1309 | |||
1287 | /* | 1310 | /* |
1288 | * Ensure that no racing symlink() will make detach_prep() fail while | 1311 | * Ensure that no racing symlink() will make detach_prep() fail while |
1289 | * the new link is temporarily attached | 1312 | * the new link is temporarily attached |
@@ -1321,7 +1344,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1321 | config_item_put(parent_item); | 1344 | config_item_put(parent_item); |
1322 | 1345 | ||
1323 | if (item->ci_type) | 1346 | if (item->ci_type) |
1324 | owner = item->ci_type->ct_owner; | 1347 | dead_item_owner = item->ci_type->ct_owner; |
1325 | 1348 | ||
1326 | if (sd->s_type & CONFIGFS_USET_DIR) { | 1349 | if (sd->s_type & CONFIGFS_USET_DIR) { |
1327 | configfs_detach_group(item); | 1350 | configfs_detach_group(item); |
@@ -1343,7 +1366,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1343 | /* Drop our reference from above */ | 1366 | /* Drop our reference from above */ |
1344 | config_item_put(item); | 1367 | config_item_put(item); |
1345 | 1368 | ||
1346 | module_put(owner); | 1369 | module_put(dead_item_owner); |
1370 | module_put(subsys_owner); | ||
1347 | 1371 | ||
1348 | return 0; | 1372 | return 0; |
1349 | } | 1373 | } |