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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '9p-for-6.12-rc5' of https://github.com/martinetd/linux

Pull more 9p reverts from Dominique Martinet:
"Revert patches causing inode collision problems.

The code simplification introduced significant regressions on servers
that do not remap inode numbers when exporting multiple underlying
filesystems with colliding inodes. See the top-most revert (commit
be2ca3825372) for details.

This problem had been ignored for too long and the reverts will also
head to stable (6.9+).

I'm confident this set of patches gets us back to previous behaviour
(another related patch had already been reverted back in April and
we're almost back to square 1, and the rest didn't touch inode
lifecycle)"

* tag '9p-for-6.12-rc5' of https://github.com/martinetd/linux:
Revert "fs/9p: simplify iget to remove unnecessary paths"
Revert "fs/9p: fix uaf in in v9fs_stat2inode_dotl"
Revert "fs/9p: remove redundant pointer v9ses"
Revert " fs/9p: mitigate inode collisions"

+192 -87
+27 -7
fs/9p/v9fs.h
··· 179 179 struct inode *old_dir, struct dentry *old_dentry, 180 180 struct inode *new_dir, struct dentry *new_dentry, 181 181 unsigned int flags); 182 - extern struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid, 183 - bool new); 182 + extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, 183 + struct p9_fid *fid, 184 + struct super_block *sb, int new); 184 185 extern const struct inode_operations v9fs_dir_inode_operations_dotl; 185 186 extern const struct inode_operations v9fs_file_inode_operations_dotl; 186 187 extern const struct inode_operations v9fs_symlink_inode_operations_dotl; 187 188 extern const struct netfs_request_ops v9fs_req_ops; 188 - extern struct inode *v9fs_fid_iget_dotl(struct super_block *sb, 189 - struct p9_fid *fid, bool new); 189 + extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, 190 + struct p9_fid *fid, 191 + struct super_block *sb, int new); 190 192 191 193 /* other default globals */ 192 194 #define V9FS_PORT 564 ··· 227 225 */ 228 226 static inline struct inode * 229 227 v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 230 - struct super_block *sb, bool new) 228 + struct super_block *sb) 231 229 { 232 230 if (v9fs_proto_dotl(v9ses)) 233 - return v9fs_fid_iget_dotl(sb, fid, new); 231 + return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0); 234 232 else 235 - return v9fs_fid_iget(sb, fid, new); 233 + return v9fs_inode_from_fid(v9ses, fid, sb, 0); 234 + } 235 + 236 + /** 237 + * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by 238 + * issuing a attribute request 239 + * @v9ses: session information 240 + * @fid: fid to issue attribute request for 241 + * @sb: superblock on which to create inode 242 + * 243 + */ 244 + static inline struct inode * 245 + v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 246 + struct super_block *sb) 247 + { 248 + if (v9fs_proto_dotl(v9ses)) 249 + return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1); 250 + else 251 + return v9fs_inode_from_fid(v9ses, fid, sb, 1); 236 252 } 237 253 238 254 #endif
+1 -1
fs/9p/v9fs_vfs.h
··· 42 42 void v9fs_free_inode(struct inode *inode); 43 43 void v9fs_set_netfs_context(struct inode *inode); 44 44 int v9fs_init_inode(struct v9fs_session_info *v9ses, 45 - struct inode *inode, struct p9_qid *qid, umode_t mode, dev_t rdev); 45 + struct inode *inode, umode_t mode, dev_t rdev); 46 46 void v9fs_evict_inode(struct inode *inode); 47 47 #if (BITS_PER_LONG == 32) 48 48 #define QID2INO(q) ((ino_t) (((q)->path+2) ^ (((q)->path) >> 32)))
+82 -47
fs/9p/vfs_inode.c
··· 256 256 } 257 257 258 258 int v9fs_init_inode(struct v9fs_session_info *v9ses, 259 - struct inode *inode, struct p9_qid *qid, umode_t mode, dev_t rdev) 259 + struct inode *inode, umode_t mode, dev_t rdev) 260 260 { 261 261 int err = 0; 262 - struct v9fs_inode *v9inode = V9FS_I(inode); 263 - 264 - memcpy(&v9inode->qid, qid, sizeof(struct p9_qid)); 265 262 266 263 inode_init_owner(&nop_mnt_idmap, inode, NULL, mode); 267 264 inode->i_blocks = 0; ··· 362 365 clear_inode(inode); 363 366 } 364 367 365 - struct inode * 366 - v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid, bool new) 368 + static int v9fs_test_inode(struct inode *inode, void *data) 369 + { 370 + int umode; 371 + dev_t rdev; 372 + struct v9fs_inode *v9inode = V9FS_I(inode); 373 + struct p9_wstat *st = (struct p9_wstat *)data; 374 + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 375 + 376 + umode = p9mode2unixmode(v9ses, st, &rdev); 377 + /* don't match inode of different type */ 378 + if (inode_wrong_type(inode, umode)) 379 + return 0; 380 + 381 + /* compare qid details */ 382 + if (memcmp(&v9inode->qid.version, 383 + &st->qid.version, sizeof(v9inode->qid.version))) 384 + return 0; 385 + 386 + if (v9inode->qid.type != st->qid.type) 387 + return 0; 388 + 389 + if (v9inode->qid.path != st->qid.path) 390 + return 0; 391 + return 1; 392 + } 393 + 394 + static int v9fs_test_new_inode(struct inode *inode, void *data) 395 + { 396 + return 0; 397 + } 398 + 399 + static int v9fs_set_inode(struct inode *inode, void *data) 400 + { 401 + struct v9fs_inode *v9inode = V9FS_I(inode); 402 + struct p9_wstat *st = (struct p9_wstat *)data; 403 + 404 + memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); 405 + return 0; 406 + } 407 + 408 + static struct inode *v9fs_qid_iget(struct super_block *sb, 409 + struct p9_qid *qid, 410 + struct p9_wstat *st, 411 + int new) 367 412 { 368 413 dev_t rdev; 369 414 int retval; 370 415 umode_t umode; 371 416 struct inode *inode; 372 - struct p9_wstat *st; 373 417 struct v9fs_session_info *v9ses = sb->s_fs_info; 418 + int (*test)(struct inode *inode, void *data); 374 419 375 - inode = iget_locked(sb, QID2INO(&fid->qid)); 376 - if (unlikely(!inode)) 420 + if (new) 421 + test = v9fs_test_new_inode; 422 + else 423 + test = v9fs_test_inode; 424 + 425 + inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st); 426 + if (!inode) 377 427 return ERR_PTR(-ENOMEM); 378 - if (!(inode->i_state & I_NEW)) { 379 - if (!new) { 380 - goto done; 381 - } else { 382 - p9_debug(P9_DEBUG_VFS, "WARNING: Inode collision %ld\n", 383 - inode->i_ino); 384 - iput(inode); 385 - remove_inode_hash(inode); 386 - inode = iget_locked(sb, QID2INO(&fid->qid)); 387 - WARN_ON(!(inode->i_state & I_NEW)); 388 - } 389 - } 390 - 428 + if (!(inode->i_state & I_NEW)) 429 + return inode; 391 430 /* 392 431 * initialize the inode with the stat info 393 432 * FIXME!! we may need support for stale inodes 394 433 * later. 395 434 */ 396 - st = p9_client_stat(fid); 397 - if (IS_ERR(st)) { 398 - retval = PTR_ERR(st); 399 - goto error; 400 - } 401 - 435 + inode->i_ino = QID2INO(qid); 402 436 umode = p9mode2unixmode(v9ses, st, &rdev); 403 - retval = v9fs_init_inode(v9ses, inode, &fid->qid, umode, rdev); 404 - v9fs_stat2inode(st, inode, sb, 0); 405 - p9stat_free(st); 406 - kfree(st); 437 + retval = v9fs_init_inode(v9ses, inode, umode, rdev); 407 438 if (retval) 408 439 goto error; 409 440 441 + v9fs_stat2inode(st, inode, sb, 0); 410 442 v9fs_set_netfs_context(inode); 411 443 v9fs_cache_inode_get_cookie(inode); 412 444 unlock_new_inode(inode); 413 - done: 414 445 return inode; 415 446 error: 416 447 iget_failed(inode); 417 448 return ERR_PTR(retval); 449 + 450 + } 451 + 452 + struct inode * 453 + v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 454 + struct super_block *sb, int new) 455 + { 456 + struct p9_wstat *st; 457 + struct inode *inode = NULL; 458 + 459 + st = p9_client_stat(fid); 460 + if (IS_ERR(st)) 461 + return ERR_CAST(st); 462 + 463 + inode = v9fs_qid_iget(sb, &st->qid, st, new); 464 + p9stat_free(st); 465 + kfree(st); 466 + return inode; 418 467 } 419 468 420 469 /** ··· 492 449 */ 493 450 static void v9fs_dec_count(struct inode *inode) 494 451 { 495 - if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) { 496 - if (inode->i_nlink) { 497 - drop_nlink(inode); 498 - } else { 499 - p9_debug(P9_DEBUG_VFS, 500 - "WARNING: unexpected i_nlink zero %d inode %ld\n", 501 - inode->i_nlink, inode->i_ino); 502 - } 503 - } 452 + if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) 453 + drop_nlink(inode); 504 454 } 505 455 506 456 /** ··· 543 507 v9fs_dec_count(dir); 544 508 } else 545 509 v9fs_dec_count(inode); 546 - 547 - if (inode->i_nlink <= 0) /* no more refs unhash it */ 548 - remove_inode_hash(inode); 549 510 550 511 v9fs_invalidate_inode_attr(inode); 551 512 v9fs_invalidate_inode_attr(dir); ··· 609 576 /* 610 577 * instantiate inode and assign the unopened fid to the dentry 611 578 */ 612 - inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, true); 579 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 613 580 if (IS_ERR(inode)) { 614 581 err = PTR_ERR(inode); 615 582 p9_debug(P9_DEBUG_VFS, ··· 737 704 inode = NULL; 738 705 else if (IS_ERR(fid)) 739 706 inode = ERR_CAST(fid); 707 + else if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) 708 + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); 740 709 else 741 - inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, false); 710 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 742 711 /* 743 712 * If we had a rename on the server and a parallel lookup 744 713 * for the new name, then make sure we instantiate with
+81 -31
fs/9p/vfs_inode_dotl.c
··· 52 52 return current_fsgid(); 53 53 } 54 54 55 + static int v9fs_test_inode_dotl(struct inode *inode, void *data) 56 + { 57 + struct v9fs_inode *v9inode = V9FS_I(inode); 58 + struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; 55 59 60 + /* don't match inode of different type */ 61 + if (inode_wrong_type(inode, st->st_mode)) 62 + return 0; 56 63 57 - struct inode * 58 - v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid, bool new) 64 + if (inode->i_generation != st->st_gen) 65 + return 0; 66 + 67 + /* compare qid details */ 68 + if (memcmp(&v9inode->qid.version, 69 + &st->qid.version, sizeof(v9inode->qid.version))) 70 + return 0; 71 + 72 + if (v9inode->qid.type != st->qid.type) 73 + return 0; 74 + 75 + if (v9inode->qid.path != st->qid.path) 76 + return 0; 77 + return 1; 78 + } 79 + 80 + /* Always get a new inode */ 81 + static int v9fs_test_new_inode_dotl(struct inode *inode, void *data) 82 + { 83 + return 0; 84 + } 85 + 86 + static int v9fs_set_inode_dotl(struct inode *inode, void *data) 87 + { 88 + struct v9fs_inode *v9inode = V9FS_I(inode); 89 + struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; 90 + 91 + memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); 92 + inode->i_generation = st->st_gen; 93 + return 0; 94 + } 95 + 96 + static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, 97 + struct p9_qid *qid, 98 + struct p9_fid *fid, 99 + struct p9_stat_dotl *st, 100 + int new) 59 101 { 60 102 int retval; 61 103 struct inode *inode; 62 - struct p9_stat_dotl *st; 63 104 struct v9fs_session_info *v9ses = sb->s_fs_info; 105 + int (*test)(struct inode *inode, void *data); 64 106 65 - inode = iget_locked(sb, QID2INO(&fid->qid)); 66 - if (unlikely(!inode)) 107 + if (new) 108 + test = v9fs_test_new_inode_dotl; 109 + else 110 + test = v9fs_test_inode_dotl; 111 + 112 + inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode_dotl, st); 113 + if (!inode) 67 114 return ERR_PTR(-ENOMEM); 68 - if (!(inode->i_state & I_NEW)) { 69 - if (!new) { 70 - goto done; 71 - } else { /* deal with race condition in inode number reuse */ 72 - p9_debug(P9_DEBUG_ERROR, "WARNING: Inode collision %lx\n", 73 - inode->i_ino); 74 - iput(inode); 75 - remove_inode_hash(inode); 76 - inode = iget_locked(sb, QID2INO(&fid->qid)); 77 - WARN_ON(!(inode->i_state & I_NEW)); 78 - } 79 - } 80 - 115 + if (!(inode->i_state & I_NEW)) 116 + return inode; 81 117 /* 82 118 * initialize the inode with the stat info 83 119 * FIXME!! we may need support for stale inodes 84 120 * later. 85 121 */ 86 - st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); 87 - if (IS_ERR(st)) { 88 - retval = PTR_ERR(st); 89 - goto error; 90 - } 91 - 92 - retval = v9fs_init_inode(v9ses, inode, &fid->qid, 122 + inode->i_ino = QID2INO(qid); 123 + retval = v9fs_init_inode(v9ses, inode, 93 124 st->st_mode, new_decode_dev(st->st_rdev)); 94 - v9fs_stat2inode_dotl(st, inode, 0); 95 - kfree(st); 96 125 if (retval) 97 126 goto error; 98 127 128 + v9fs_stat2inode_dotl(st, inode, 0); 99 129 v9fs_set_netfs_context(inode); 100 130 v9fs_cache_inode_get_cookie(inode); 101 131 retval = v9fs_get_acl(inode, fid); ··· 133 103 goto error; 134 104 135 105 unlock_new_inode(inode); 136 - done: 137 106 return inode; 138 107 error: 139 108 iget_failed(inode); 140 109 return ERR_PTR(retval); 110 + 111 + } 112 + 113 + struct inode * 114 + v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, 115 + struct super_block *sb, int new) 116 + { 117 + struct p9_stat_dotl *st; 118 + struct inode *inode = NULL; 119 + 120 + st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); 121 + if (IS_ERR(st)) 122 + return ERR_CAST(st); 123 + 124 + inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new); 125 + kfree(st); 126 + return inode; 141 127 } 142 128 143 129 struct dotl_openflag_map { ··· 305 259 p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); 306 260 goto out; 307 261 } 308 - inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true); 262 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 309 263 if (IS_ERR(inode)) { 310 264 err = PTR_ERR(inode); 311 265 p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err); ··· 355 309 umode_t omode) 356 310 { 357 311 int err; 312 + struct v9fs_session_info *v9ses; 358 313 struct p9_fid *fid = NULL, *dfid = NULL; 359 314 kgid_t gid; 360 315 const unsigned char *name; ··· 365 318 struct posix_acl *dacl = NULL, *pacl = NULL; 366 319 367 320 p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry); 321 + v9ses = v9fs_inode2v9ses(dir); 368 322 369 323 omode |= S_IFDIR; 370 324 if (dir->i_mode & S_ISGID) ··· 400 352 } 401 353 402 354 /* instantiate inode and assign the unopened fid to the dentry */ 403 - inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true); 355 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 404 356 if (IS_ERR(inode)) { 405 357 err = PTR_ERR(inode); 406 358 p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", ··· 797 749 kgid_t gid; 798 750 const unsigned char *name; 799 751 umode_t mode; 752 + struct v9fs_session_info *v9ses; 800 753 struct p9_fid *fid = NULL, *dfid = NULL; 801 754 struct inode *inode; 802 755 struct p9_qid qid; ··· 807 758 dir->i_ino, dentry, omode, 808 759 MAJOR(rdev), MINOR(rdev)); 809 760 761 + v9ses = v9fs_inode2v9ses(dir); 810 762 dfid = v9fs_parent_fid(dentry); 811 763 if (IS_ERR(dfid)) { 812 764 err = PTR_ERR(dfid); ··· 838 788 err); 839 789 goto error; 840 790 } 841 - inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true); 791 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 842 792 if (IS_ERR(inode)) { 843 793 err = PTR_ERR(inode); 844 794 p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
+1 -1
fs/9p/vfs_super.c
··· 139 139 else 140 140 sb->s_d_op = &v9fs_dentry_operations; 141 141 142 - inode = v9fs_get_inode_from_fid(v9ses, fid, sb, true); 142 + inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb); 143 143 if (IS_ERR(inode)) { 144 144 retval = PTR_ERR(inode); 145 145 goto release_sb;