Skip to content

Commit 850925a

Browse files
committed
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 be2ca38) 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"
2 parents c71f8fb + be2ca38 commit 850925a

File tree

5 files changed

+192
-87
lines changed

5 files changed

+192
-87
lines changed

fs/9p/v9fs.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,16 @@ extern int v9fs_vfs_rename(struct mnt_idmap *idmap,
179179
struct inode *old_dir, struct dentry *old_dentry,
180180
struct inode *new_dir, struct dentry *new_dentry,
181181
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);
184185
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
185186
extern const struct inode_operations v9fs_file_inode_operations_dotl;
186187
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
187188
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);
190192

191193
/* other default globals */
192194
#define V9FS_PORT 564
@@ -225,12 +227,30 @@ static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
225227
*/
226228
static inline struct inode *
227229
v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
228-
struct super_block *sb, bool new)
230+
struct super_block *sb)
229231
{
230232
if (v9fs_proto_dotl(v9ses))
231-
return v9fs_fid_iget_dotl(sb, fid, new);
233+
return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0);
232234
else
233-
return v9fs_fid_iget(sb, fid, new);
235+
return v9fs_inode_from_fid(v9ses, fid, sb, 0);
236+
}
237+
238+
/**
239+
* v9fs_get_new_inode_from_fid - Helper routine to populate an inode by
240+
* issuing a attribute request
241+
* @v9ses: session information
242+
* @fid: fid to issue attribute request for
243+
* @sb: superblock on which to create inode
244+
*
245+
*/
246+
static inline struct inode *
247+
v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
248+
struct super_block *sb)
249+
{
250+
if (v9fs_proto_dotl(v9ses))
251+
return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1);
252+
else
253+
return v9fs_inode_from_fid(v9ses, fid, sb, 1);
234254
}
235255

236256
#endif

fs/9p/v9fs_vfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb);
4242
void v9fs_free_inode(struct inode *inode);
4343
void v9fs_set_netfs_context(struct inode *inode);
4444
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);
4646
void v9fs_evict_inode(struct inode *inode);
4747
#if (BITS_PER_LONG == 32)
4848
#define QID2INO(q) ((ino_t) (((q)->path+2) ^ (((q)->path) >> 32)))

fs/9p/vfs_inode.c

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,9 @@ void v9fs_set_netfs_context(struct inode *inode)
256256
}
257257

258258
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)
260260
{
261261
int err = 0;
262-
struct v9fs_inode *v9inode = V9FS_I(inode);
263-
264-
memcpy(&v9inode->qid, qid, sizeof(struct p9_qid));
265262

266263
inode_init_owner(&nop_mnt_idmap, inode, NULL, mode);
267264
inode->i_blocks = 0;
@@ -365,59 +362,105 @@ void v9fs_evict_inode(struct inode *inode)
365362
clear_inode(inode);
366363
}
367364

368-
struct inode *
369-
v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid, bool new)
365+
static int v9fs_test_inode(struct inode *inode, void *data)
366+
{
367+
int umode;
368+
dev_t rdev;
369+
struct v9fs_inode *v9inode = V9FS_I(inode);
370+
struct p9_wstat *st = (struct p9_wstat *)data;
371+
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
372+
373+
umode = p9mode2unixmode(v9ses, st, &rdev);
374+
/* don't match inode of different type */
375+
if (inode_wrong_type(inode, umode))
376+
return 0;
377+
378+
/* compare qid details */
379+
if (memcmp(&v9inode->qid.version,
380+
&st->qid.version, sizeof(v9inode->qid.version)))
381+
return 0;
382+
383+
if (v9inode->qid.type != st->qid.type)
384+
return 0;
385+
386+
if (v9inode->qid.path != st->qid.path)
387+
return 0;
388+
return 1;
389+
}
390+
391+
static int v9fs_test_new_inode(struct inode *inode, void *data)
392+
{
393+
return 0;
394+
}
395+
396+
static int v9fs_set_inode(struct inode *inode, void *data)
397+
{
398+
struct v9fs_inode *v9inode = V9FS_I(inode);
399+
struct p9_wstat *st = (struct p9_wstat *)data;
400+
401+
memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
402+
return 0;
403+
}
404+
405+
static struct inode *v9fs_qid_iget(struct super_block *sb,
406+
struct p9_qid *qid,
407+
struct p9_wstat *st,
408+
int new)
370409
{
371410
dev_t rdev;
372411
int retval;
373412
umode_t umode;
374413
struct inode *inode;
375-
struct p9_wstat *st;
376414
struct v9fs_session_info *v9ses = sb->s_fs_info;
415+
int (*test)(struct inode *inode, void *data);
377416

378-
inode = iget_locked(sb, QID2INO(&fid->qid));
379-
if (unlikely(!inode))
380-
return ERR_PTR(-ENOMEM);
381-
if (!(inode->i_state & I_NEW)) {
382-
if (!new) {
383-
goto done;
384-
} else {
385-
p9_debug(P9_DEBUG_VFS, "WARNING: Inode collision %ld\n",
386-
inode->i_ino);
387-
iput(inode);
388-
remove_inode_hash(inode);
389-
inode = iget_locked(sb, QID2INO(&fid->qid));
390-
WARN_ON(!(inode->i_state & I_NEW));
391-
}
392-
}
417+
if (new)
418+
test = v9fs_test_new_inode;
419+
else
420+
test = v9fs_test_inode;
393421

422+
inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st);
423+
if (!inode)
424+
return ERR_PTR(-ENOMEM);
425+
if (!(inode->i_state & I_NEW))
426+
return inode;
394427
/*
395428
* initialize the inode with the stat info
396429
* FIXME!! we may need support for stale inodes
397430
* later.
398431
*/
399-
st = p9_client_stat(fid);
400-
if (IS_ERR(st)) {
401-
retval = PTR_ERR(st);
402-
goto error;
403-
}
404-
432+
inode->i_ino = QID2INO(qid);
405433
umode = p9mode2unixmode(v9ses, st, &rdev);
406-
retval = v9fs_init_inode(v9ses, inode, &fid->qid, umode, rdev);
407-
v9fs_stat2inode(st, inode, sb, 0);
408-
p9stat_free(st);
409-
kfree(st);
434+
retval = v9fs_init_inode(v9ses, inode, umode, rdev);
410435
if (retval)
411436
goto error;
412437

438+
v9fs_stat2inode(st, inode, sb, 0);
413439
v9fs_set_netfs_context(inode);
414440
v9fs_cache_inode_get_cookie(inode);
415441
unlock_new_inode(inode);
416-
done:
417442
return inode;
418443
error:
419444
iget_failed(inode);
420445
return ERR_PTR(retval);
446+
447+
}
448+
449+
struct inode *
450+
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
451+
struct super_block *sb, int new)
452+
{
453+
struct p9_wstat *st;
454+
struct inode *inode = NULL;
455+
456+
st = p9_client_stat(fid);
457+
if (IS_ERR(st))
458+
return ERR_CAST(st);
459+
460+
inode = v9fs_qid_iget(sb, &st->qid, st, new);
461+
p9stat_free(st);
462+
kfree(st);
463+
return inode;
421464
}
422465

423466
/**
@@ -449,15 +492,8 @@ static int v9fs_at_to_dotl_flags(int flags)
449492
*/
450493
static void v9fs_dec_count(struct inode *inode)
451494
{
452-
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) {
453-
if (inode->i_nlink) {
454-
drop_nlink(inode);
455-
} else {
456-
p9_debug(P9_DEBUG_VFS,
457-
"WARNING: unexpected i_nlink zero %d inode %ld\n",
458-
inode->i_nlink, inode->i_ino);
459-
}
460-
}
495+
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
496+
drop_nlink(inode);
461497
}
462498

463499
/**
@@ -508,9 +544,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
508544
} else
509545
v9fs_dec_count(inode);
510546

511-
if (inode->i_nlink <= 0) /* no more refs unhash it */
512-
remove_inode_hash(inode);
513-
514547
v9fs_invalidate_inode_attr(inode);
515548
v9fs_invalidate_inode_attr(dir);
516549

@@ -576,7 +609,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
576609
/*
577610
* instantiate inode and assign the unopened fid to the dentry
578611
*/
579-
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, true);
612+
inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
580613
if (IS_ERR(inode)) {
581614
err = PTR_ERR(inode);
582615
p9_debug(P9_DEBUG_VFS,
@@ -704,8 +737,10 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
704737
inode = NULL;
705738
else if (IS_ERR(fid))
706739
inode = ERR_CAST(fid);
740+
else if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
741+
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
707742
else
708-
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, false);
743+
inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
709744
/*
710745
* If we had a rename on the server and a parallel lookup
711746
* for the new name, then make sure we instantiate with

0 commit comments

Comments
 (0)