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

Merge tag 'configfs-for-5.4' of git://git.infradead.org/users/hch/configfs

Pull configfs updates from Christoph Hellwig:

- fix a symlink deadlock (Al Viro)

- various cleanups (Al Viro, me)

* tag 'configfs-for-5.4' of git://git.infradead.org/users/hch/configfs:
configfs: calculate the symlink target only once
configfs: make configfs_create() return inode
configfs: factor dirent removal into helpers
configfs: fix a deadlock in configfs_symlink()

+172 -256
+5 -16
fs/configfs/configfs_internal.h
··· 34 34 int s_dependent_count; 35 35 struct list_head s_sibling; 36 36 struct list_head s_children; 37 - struct list_head s_links; 37 + int s_links; 38 38 void * s_element; 39 39 int s_type; 40 40 umode_t s_mode; ··· 66 66 extern int configfs_is_root(struct config_item *item); 67 67 68 68 extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, struct super_block *); 69 - extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct inode *)); 69 + extern struct inode *configfs_create(struct dentry *, umode_t mode); 70 70 71 71 extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); 72 72 extern int configfs_create_bin_file(struct config_item *, ··· 84 84 extern struct dentry *configfs_pin_fs(void); 85 85 extern void configfs_release_fs(void); 86 86 87 - extern struct rw_semaphore configfs_rename_sem; 88 87 extern const struct file_operations configfs_dir_operations; 89 88 extern const struct file_operations configfs_file_operations; 90 89 extern const struct file_operations configfs_bin_file_operations; ··· 96 97 const char *symname); 97 98 extern int configfs_unlink(struct inode *dir, struct dentry *dentry); 98 99 99 - struct configfs_symlink { 100 - struct list_head sl_list; 101 - struct config_item *sl_target; 102 - }; 103 - 104 - extern int configfs_create_link(struct configfs_symlink *sl, 105 - struct dentry *parent, 106 - struct dentry *dentry); 100 + int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, 101 + struct dentry *dentry, char *body); 107 102 108 103 static inline struct config_item * to_item(struct dentry * dentry) 109 104 { ··· 125 132 spin_lock(&dentry->d_lock); 126 133 if (!d_unhashed(dentry)) { 127 134 struct configfs_dirent * sd = dentry->d_fsdata; 128 - if (sd->s_type & CONFIGFS_ITEM_LINK) { 129 - struct configfs_symlink * sl = sd->s_element; 130 - item = config_item_get(sl->sl_target); 131 - } else 132 - item = config_item_get(sd->s_element); 135 + item = config_item_get(sd->s_element); 133 136 } 134 137 spin_unlock(&dentry->d_lock); 135 138
+65 -108
fs/configfs/dir.c
··· 22 22 #include <linux/configfs.h> 23 23 #include "configfs_internal.h" 24 24 25 - DECLARE_RWSEM(configfs_rename_sem); 26 25 /* 27 26 * Protects mutations of configfs_dirent linkage together with proper i_mutex 28 27 * Also protects mutations of symlinks linkage to target configfs_dirent ··· 190 191 return ERR_PTR(-ENOMEM); 191 192 192 193 atomic_set(&sd->s_count, 1); 193 - INIT_LIST_HEAD(&sd->s_links); 194 194 INIT_LIST_HEAD(&sd->s_children); 195 195 sd->s_element = element; 196 196 sd->s_type = type; ··· 251 253 return 0; 252 254 } 253 255 254 - static void init_dir(struct inode * inode) 256 + static void configfs_remove_dirent(struct dentry *dentry) 255 257 { 256 - inode->i_op = &configfs_dir_inode_operations; 257 - inode->i_fop = &configfs_dir_operations; 258 + struct configfs_dirent *sd = dentry->d_fsdata; 258 259 259 - /* directory inodes start off with i_nlink == 2 (for "." entry) */ 260 - inc_nlink(inode); 261 - } 262 - 263 - static void configfs_init_file(struct inode * inode) 264 - { 265 - inode->i_size = PAGE_SIZE; 266 - inode->i_fop = &configfs_file_operations; 267 - } 268 - 269 - static void configfs_init_bin_file(struct inode *inode) 270 - { 271 - inode->i_size = 0; 272 - inode->i_fop = &configfs_bin_file_operations; 273 - } 274 - 275 - static void init_symlink(struct inode * inode) 276 - { 277 - inode->i_op = &configfs_symlink_inode_operations; 260 + if (!sd) 261 + return; 262 + spin_lock(&configfs_dirent_lock); 263 + list_del_init(&sd->s_sibling); 264 + spin_unlock(&configfs_dirent_lock); 265 + configfs_put(sd); 278 266 } 279 267 280 268 /** ··· 278 294 int error; 279 295 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; 280 296 struct dentry *p = dentry->d_parent; 297 + struct inode *inode; 281 298 282 299 BUG_ON(!item); 283 300 ··· 293 308 return error; 294 309 295 310 configfs_set_dir_dirent_depth(p->d_fsdata, dentry->d_fsdata); 296 - error = configfs_create(dentry, mode, init_dir); 297 - if (!error) { 298 - inc_nlink(d_inode(p)); 299 - item->ci_dentry = dentry; 300 - } else { 301 - struct configfs_dirent *sd = dentry->d_fsdata; 302 - if (sd) { 303 - spin_lock(&configfs_dirent_lock); 304 - list_del_init(&sd->s_sibling); 305 - spin_unlock(&configfs_dirent_lock); 306 - configfs_put(sd); 307 - } 308 - } 309 - return error; 311 + inode = configfs_create(dentry, mode); 312 + if (IS_ERR(inode)) 313 + goto out_remove; 314 + 315 + inode->i_op = &configfs_dir_inode_operations; 316 + inode->i_fop = &configfs_dir_operations; 317 + /* directory inodes start off with i_nlink == 2 (for "." entry) */ 318 + inc_nlink(inode); 319 + d_instantiate(dentry, inode); 320 + /* already hashed */ 321 + dget(dentry); /* pin directory dentries in core */ 322 + inc_nlink(d_inode(p)); 323 + item->ci_dentry = dentry; 324 + return 0; 325 + 326 + out_remove: 327 + configfs_remove_dirent(dentry); 328 + return PTR_ERR(inode); 310 329 } 311 330 312 331 /* ··· 351 362 return ret; 352 363 } 353 364 354 - int configfs_create_link(struct configfs_symlink *sl, 355 - struct dentry *parent, 356 - struct dentry *dentry) 365 + int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, 366 + struct dentry *dentry, char *body) 357 367 { 358 368 int err = 0; 359 369 umode_t mode = S_IFLNK | S_IRWXUGO; 360 370 struct configfs_dirent *p = parent->d_fsdata; 371 + struct inode *inode; 361 372 362 - err = configfs_make_dirent(p, dentry, sl, mode, 363 - CONFIGFS_ITEM_LINK, p->s_frag); 364 - if (!err) { 365 - err = configfs_create(dentry, mode, init_symlink); 366 - if (err) { 367 - struct configfs_dirent *sd = dentry->d_fsdata; 368 - if (sd) { 369 - spin_lock(&configfs_dirent_lock); 370 - list_del_init(&sd->s_sibling); 371 - spin_unlock(&configfs_dirent_lock); 372 - configfs_put(sd); 373 - } 374 - } 375 - } 376 - return err; 373 + err = configfs_make_dirent(p, dentry, target, mode, CONFIGFS_ITEM_LINK, 374 + p->s_frag); 375 + if (err) 376 + return err; 377 + 378 + inode = configfs_create(dentry, mode); 379 + if (IS_ERR(inode)) 380 + goto out_remove; 381 + 382 + inode->i_link = body; 383 + inode->i_op = &configfs_symlink_inode_operations; 384 + d_instantiate(dentry, inode); 385 + dget(dentry); /* pin link dentries in core */ 386 + return 0; 387 + 388 + out_remove: 389 + configfs_remove_dirent(dentry); 390 + return PTR_ERR(inode); 377 391 } 378 392 379 393 static void remove_dir(struct dentry * d) 380 394 { 381 395 struct dentry * parent = dget(d->d_parent); 382 - struct configfs_dirent * sd; 383 396 384 - sd = d->d_fsdata; 385 - spin_lock(&configfs_dirent_lock); 386 - list_del_init(&sd->s_sibling); 387 - spin_unlock(&configfs_dirent_lock); 388 - configfs_put(sd); 397 + configfs_remove_dirent(d); 398 + 389 399 if (d_really_is_positive(d)) 390 400 simple_rmdir(d_inode(parent),d); 391 401 ··· 425 437 static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry) 426 438 { 427 439 struct configfs_attribute * attr = sd->s_element; 428 - int error; 440 + struct inode *inode; 429 441 430 442 spin_lock(&configfs_dirent_lock); 431 443 dentry->d_fsdata = configfs_get(sd); 432 444 sd->s_dentry = dentry; 433 445 spin_unlock(&configfs_dirent_lock); 434 446 435 - error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, 436 - (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) ? 437 - configfs_init_bin_file : 438 - configfs_init_file); 439 - if (error) 447 + inode = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG); 448 + if (IS_ERR(inode)) { 440 449 configfs_put(sd); 441 - return error; 450 + return PTR_ERR(inode); 451 + } 452 + if (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) { 453 + inode->i_size = 0; 454 + inode->i_fop = &configfs_bin_file_operations; 455 + } else { 456 + inode->i_size = PAGE_SIZE; 457 + inode->i_fop = &configfs_file_operations; 458 + } 459 + d_add(dentry, inode); 460 + return 0; 442 461 } 443 462 444 463 static struct dentry * configfs_lookup(struct inode *dir, ··· 515 520 parent_sd->s_type |= CONFIGFS_USET_DROPPING; 516 521 517 522 ret = -EBUSY; 518 - if (!list_empty(&parent_sd->s_links)) 523 + if (parent_sd->s_links) 519 524 goto out; 520 525 521 526 ret = 0; ··· 1572 1577 .lookup = configfs_lookup, 1573 1578 .setattr = configfs_setattr, 1574 1579 }; 1575 - 1576 - #if 0 1577 - int configfs_rename_dir(struct config_item * item, const char *new_name) 1578 - { 1579 - int error = 0; 1580 - struct dentry * new_dentry, * parent; 1581 - 1582 - if (!strcmp(config_item_name(item), new_name)) 1583 - return -EINVAL; 1584 - 1585 - if (!item->parent) 1586 - return -EINVAL; 1587 - 1588 - down_write(&configfs_rename_sem); 1589 - parent = item->parent->dentry; 1590 - 1591 - inode_lock(d_inode(parent)); 1592 - 1593 - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); 1594 - if (!IS_ERR(new_dentry)) { 1595 - if (d_really_is_negative(new_dentry)) { 1596 - error = config_item_set_name(item, "%s", new_name); 1597 - if (!error) { 1598 - d_add(new_dentry, NULL); 1599 - d_move(item->dentry, new_dentry); 1600 - } 1601 - else 1602 - d_delete(new_dentry); 1603 - } else 1604 - error = -EEXIST; 1605 - dput(new_dentry); 1606 - } 1607 - inode_unlock(d_inode(parent)); 1608 - up_write(&configfs_rename_sem); 1609 - 1610 - return error; 1611 - } 1612 - #endif 1613 1580 1614 1581 static int configfs_dir_open(struct inode *inode, struct file *file) 1615 1582 {
+5 -19
fs/configfs/inode.c
··· 164 164 165 165 #endif /* CONFIG_LOCKDEP */ 166 166 167 - int configfs_create(struct dentry * dentry, umode_t mode, void (*init)(struct inode *)) 167 + struct inode *configfs_create(struct dentry *dentry, umode_t mode) 168 168 { 169 - int error = 0; 170 169 struct inode *inode = NULL; 171 170 struct configfs_dirent *sd; 172 171 struct inode *p_inode; 173 172 174 173 if (!dentry) 175 - return -ENOENT; 174 + return ERR_PTR(-ENOENT); 176 175 177 176 if (d_really_is_positive(dentry)) 178 - return -EEXIST; 177 + return ERR_PTR(-EEXIST); 179 178 180 179 sd = dentry->d_fsdata; 181 180 inode = configfs_new_inode(mode, sd, dentry->d_sb); 182 181 if (!inode) 183 - return -ENOMEM; 182 + return ERR_PTR(-ENOMEM); 184 183 185 184 p_inode = d_inode(dentry->d_parent); 186 185 p_inode->i_mtime = p_inode->i_ctime = current_time(p_inode); 187 186 configfs_set_inode_lock_class(sd, inode); 188 - 189 - init(inode); 190 - if (S_ISDIR(mode) || S_ISLNK(mode)) { 191 - /* 192 - * ->symlink(), ->mkdir(), configfs_register_subsystem() or 193 - * create_default_group() - already hashed. 194 - */ 195 - d_instantiate(dentry, inode); 196 - dget(dentry); /* pin link and directory dentries in core */ 197 - } else { 198 - /* ->lookup() */ 199 - d_add(dentry, inode); 200 - } 201 - return error; 187 + return inode; 202 188 } 203 189 204 190 /*
+9
fs/configfs/mount.c
··· 28 28 struct kmem_cache *configfs_dir_cachep; 29 29 static int configfs_mnt_count = 0; 30 30 31 + 32 + static void configfs_free_inode(struct inode *inode) 33 + { 34 + if (S_ISLNK(inode->i_mode)) 35 + kfree(inode->i_link); 36 + free_inode_nonrcu(inode); 37 + } 38 + 31 39 static const struct super_operations configfs_ops = { 32 40 .statfs = simple_statfs, 33 41 .drop_inode = generic_delete_inode, 42 + .free_inode = configfs_free_inode, 34 43 }; 35 44 36 45 static struct config_group configfs_root_group = {
+88 -113
fs/configfs/symlink.c
··· 55 55 } 56 56 } 57 57 58 + static int configfs_get_target_path(struct config_item *item, 59 + struct config_item *target, char *path) 60 + { 61 + int depth, size; 62 + char *s; 63 + 64 + depth = item_depth(item); 65 + size = item_path_length(target) + depth * 3 - 1; 66 + if (size > PATH_MAX) 67 + return -ENAMETOOLONG; 68 + 69 + pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); 70 + 71 + for (s = path; depth--; s += 3) 72 + strcpy(s,"../"); 73 + 74 + fill_item_path(target, path, size); 75 + pr_debug("%s: path = '%s'\n", __func__, path); 76 + return 0; 77 + } 78 + 58 79 static int create_link(struct config_item *parent_item, 59 80 struct config_item *item, 60 81 struct dentry *dentry) 61 82 { 62 83 struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; 63 - struct configfs_symlink *sl; 84 + char *body; 64 85 int ret; 65 86 66 - ret = -ENOENT; 67 87 if (!configfs_dirent_is_ready(target_sd)) 68 - goto out; 69 - ret = -ENOMEM; 70 - sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); 71 - if (sl) { 72 - spin_lock(&configfs_dirent_lock); 73 - if (target_sd->s_type & CONFIGFS_USET_DROPPING) { 74 - spin_unlock(&configfs_dirent_lock); 75 - kfree(sl); 76 - return -ENOENT; 77 - } 78 - sl->sl_target = config_item_get(item); 79 - list_add(&sl->sl_list, &target_sd->s_links); 80 - spin_unlock(&configfs_dirent_lock); 81 - ret = configfs_create_link(sl, parent_item->ci_dentry, 82 - dentry); 83 - if (ret) { 84 - spin_lock(&configfs_dirent_lock); 85 - list_del_init(&sl->sl_list); 86 - spin_unlock(&configfs_dirent_lock); 87 - config_item_put(item); 88 - kfree(sl); 89 - } 90 - } 88 + return -ENOENT; 91 89 92 - out: 90 + body = kzalloc(PAGE_SIZE, GFP_KERNEL); 91 + if (!body) 92 + return -ENOMEM; 93 + 94 + configfs_get(target_sd); 95 + spin_lock(&configfs_dirent_lock); 96 + if (target_sd->s_type & CONFIGFS_USET_DROPPING) { 97 + spin_unlock(&configfs_dirent_lock); 98 + configfs_put(target_sd); 99 + kfree(body); 100 + return -ENOENT; 101 + } 102 + target_sd->s_links++; 103 + spin_unlock(&configfs_dirent_lock); 104 + ret = configfs_get_target_path(item, item, body); 105 + if (!ret) 106 + ret = configfs_create_link(target_sd, parent_item->ci_dentry, 107 + dentry, body); 108 + if (ret) { 109 + spin_lock(&configfs_dirent_lock); 110 + target_sd->s_links--; 111 + spin_unlock(&configfs_dirent_lock); 112 + configfs_put(target_sd); 113 + kfree(body); 114 + } 93 115 return ret; 94 116 } 95 117 ··· 153 131 * Fake invisibility if dir belongs to a group/default groups hierarchy 154 132 * being attached 155 133 */ 156 - ret = -ENOENT; 157 134 if (!configfs_dirent_is_ready(sd)) 158 - goto out; 135 + return -ENOENT; 159 136 160 137 parent_item = configfs_get_config_item(dentry->d_parent); 161 138 type = parent_item->ci_type; ··· 164 143 !type->ct_item_ops->allow_link) 165 144 goto out_put; 166 145 146 + /* 147 + * This is really sick. What they wanted was a hybrid of 148 + * link(2) and symlink(2) - they wanted the target resolved 149 + * at syscall time (as link(2) would've done), be a directory 150 + * (which link(2) would've refused to do) *AND* be a deep 151 + * fucking magic, making the target busy from rmdir POV. 152 + * symlink(2) is nothing of that sort, and the locking it 153 + * gets matches the normal symlink(2) semantics. Without 154 + * attempts to resolve the target (which might very well 155 + * not even exist yet) done prior to locking the parent 156 + * directory. This perversion, OTOH, needs to resolve 157 + * the target, which would lead to obvious deadlocks if 158 + * attempted with any directories locked. 159 + * 160 + * Unfortunately, that garbage is userland ABI and we should've 161 + * said "no" back in 2005. Too late now, so we get to 162 + * play very ugly games with locking. 163 + * 164 + * Try *ANYTHING* of that sort in new code, and you will 165 + * really regret it. Just ask yourself - what could a BOFH 166 + * do to me and do I want to find it out first-hand? 167 + * 168 + * AV, a thoroughly annoyed bastard. 169 + */ 170 + inode_unlock(dir); 167 171 ret = get_target(symname, &path, &target_item, dentry->d_sb); 172 + inode_lock(dir); 168 173 if (ret) 169 174 goto out_put; 170 175 171 - ret = type->ct_item_ops->allow_link(parent_item, target_item); 176 + if (dentry->d_inode || d_unhashed(dentry)) 177 + ret = -EEXIST; 178 + else 179 + ret = inode_permission(dir, MAY_WRITE | MAY_EXEC); 180 + if (!ret) 181 + ret = type->ct_item_ops->allow_link(parent_item, target_item); 172 182 if (!ret) { 173 183 mutex_lock(&configfs_symlink_mutex); 174 184 ret = create_link(parent_item, target_item, dentry); ··· 214 162 215 163 out_put: 216 164 config_item_put(parent_item); 217 - 218 - out: 219 165 return ret; 220 166 } 221 167 222 168 int configfs_unlink(struct inode *dir, struct dentry *dentry) 223 169 { 224 - struct configfs_dirent *sd = dentry->d_fsdata; 225 - struct configfs_symlink *sl; 170 + struct configfs_dirent *sd = dentry->d_fsdata, *target_sd; 226 171 struct config_item *parent_item; 227 172 const struct config_item_type *type; 228 173 int ret; ··· 228 179 if (!(sd->s_type & CONFIGFS_ITEM_LINK)) 229 180 goto out; 230 181 231 - sl = sd->s_element; 182 + target_sd = sd->s_element; 232 183 233 184 parent_item = configfs_get_config_item(dentry->d_parent); 234 185 type = parent_item->ci_type; ··· 242 193 243 194 /* 244 195 * drop_link() must be called before 245 - * list_del_init(&sl->sl_list), so that the order of 196 + * decrementing target's ->s_links, so that the order of 246 197 * drop_link(this, target) and drop_item(target) is preserved. 247 198 */ 248 199 if (type && type->ct_item_ops && 249 200 type->ct_item_ops->drop_link) 250 201 type->ct_item_ops->drop_link(parent_item, 251 - sl->sl_target); 202 + target_sd->s_element); 252 203 253 204 spin_lock(&configfs_dirent_lock); 254 - list_del_init(&sl->sl_list); 205 + target_sd->s_links--; 255 206 spin_unlock(&configfs_dirent_lock); 256 - 257 - /* Put reference from create_link() */ 258 - config_item_put(sl->sl_target); 259 - kfree(sl); 207 + configfs_put(target_sd); 260 208 261 209 config_item_put(parent_item); 262 210 ··· 263 217 return ret; 264 218 } 265 219 266 - static int configfs_get_target_path(struct config_item * item, struct config_item * target, 267 - char *path) 268 - { 269 - char * s; 270 - int depth, size; 271 - 272 - depth = item_depth(item); 273 - size = item_path_length(target) + depth * 3 - 1; 274 - if (size > PATH_MAX) 275 - return -ENAMETOOLONG; 276 - 277 - pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); 278 - 279 - for (s = path; depth--; s += 3) 280 - strcpy(s,"../"); 281 - 282 - fill_item_path(target, path, size); 283 - pr_debug("%s: path = '%s'\n", __func__, path); 284 - 285 - return 0; 286 - } 287 - 288 - static int configfs_getlink(struct dentry *dentry, char * path) 289 - { 290 - struct config_item *item, *target_item; 291 - int error = 0; 292 - 293 - item = configfs_get_config_item(dentry->d_parent); 294 - if (!item) 295 - return -EINVAL; 296 - 297 - target_item = configfs_get_config_item(dentry); 298 - if (!target_item) { 299 - config_item_put(item); 300 - return -EINVAL; 301 - } 302 - 303 - down_read(&configfs_rename_sem); 304 - error = configfs_get_target_path(item, target_item, path); 305 - up_read(&configfs_rename_sem); 306 - 307 - config_item_put(item); 308 - config_item_put(target_item); 309 - return error; 310 - 311 - } 312 - 313 - static const char *configfs_get_link(struct dentry *dentry, 314 - struct inode *inode, 315 - struct delayed_call *done) 316 - { 317 - char *body; 318 - int error; 319 - 320 - if (!dentry) 321 - return ERR_PTR(-ECHILD); 322 - 323 - body = kzalloc(PAGE_SIZE, GFP_KERNEL); 324 - if (!body) 325 - return ERR_PTR(-ENOMEM); 326 - 327 - error = configfs_getlink(dentry, body); 328 - if (!error) { 329 - set_delayed_call(done, kfree_link, body); 330 - return body; 331 - } 332 - 333 - kfree(body); 334 - return ERR_PTR(error); 335 - } 336 - 337 220 const struct inode_operations configfs_symlink_inode_operations = { 338 - .get_link = configfs_get_link, 221 + .get_link = simple_get_link, 339 222 .setattr = configfs_setattr, 340 223 }; 341 224