fs/9p: fixes for 6.9-rc6
Contains a single mitigation to help deal with an apparent race condition between client and server having to deal with inode number collisions. Signed-off-by: Eric Van Hensbergen <ericvh@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEElpbw0ZalkJikytFRiP/V+0pf/5gFAmYqu2QACgkQiP/V+0pf /5h6FhAAjYxXb3zSeQouR7Nr+n4Hc1pIG2hwfwDg0ruZfXnKDCnDvCtMmKJZVQWc PtR51+wlKLsrCcVArD4zUI9dezJCAzHrG2W+MMn0tka4rQYIGA8TAVXWC0dpVs+e 0UxG/CFjwcHcwRIyCcgmzSetO+rR2kVaK9Nmsd+DkCixRFsJdmG1xZqMEsUg339b rAnA82fncR5cHvoaTNhFK3TIzIZ78v/xOTORjCSsXYgLBC1Sq7gwPxt11Ms9qZBK 2ttkU6PB/AIL2gXm7VfAQ82HZY5AWRlwH1EFHcgge1vylXoFJuqadhIaj+l6QC4N fgQGA6q+288vrjr5z5WXlBUCqHO2MXxPhJxEyViif+TIyJ/eCW+G777J4wPKHMiZ LHx3/4XpbzCMgAZs29Y5l7e53xE13OfnrIngC18iX3AP/fUPKi5fYkiDX59id++k PPjKlZJI7zW29hXXgBoqQtGG/h2H3d5y4B6dummDv4teGjnY5jPhA+KaL8Z9MUkV NzSozmsL+zFVK9El+FRI+4REltrg/UwdznknMHe7MJeqigdCMWUSpn7TWh9rxWft 0yLzf3QXZuYG06o3YP6RAwBTdeRay5THU8X09nusPnmoJf9oXYB/lxlqa1k/4msa kBrZzAHGOmVTpJQYTrspgWp57NyFsAbQqkzYCg6zrBj6P0mdCfs= =IrQ9 -----END PGP SIGNATURE----- Merge tag '9p-for-6.9-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs Pull 9p fix from Eric Van Hensbergen: "This contains a single mitigation to help deal with an apparent race condition between client and server having to deal with inode number collisions" * tag '9p-for-6.9-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: fs/9p: mitigate inode collisions
This commit is contained in:
commit
dda89e2fbc
11
fs/9p/v9fs.h
11
fs/9p/v9fs.h
|
@ -179,13 +179,14 @@ extern int v9fs_vfs_rename(struct mnt_idmap *idmap,
|
||||||
struct inode *old_dir, struct dentry *old_dentry,
|
struct inode *old_dir, struct dentry *old_dentry,
|
||||||
struct inode *new_dir, struct dentry *new_dentry,
|
struct inode *new_dir, struct dentry *new_dentry,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
extern struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid);
|
extern struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid,
|
||||||
|
bool new);
|
||||||
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
|
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
|
||||||
extern const struct inode_operations v9fs_file_inode_operations_dotl;
|
extern const struct inode_operations v9fs_file_inode_operations_dotl;
|
||||||
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
|
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
|
||||||
extern const struct netfs_request_ops v9fs_req_ops;
|
extern const struct netfs_request_ops v9fs_req_ops;
|
||||||
extern struct inode *v9fs_fid_iget_dotl(struct super_block *sb,
|
extern struct inode *v9fs_fid_iget_dotl(struct super_block *sb,
|
||||||
struct p9_fid *fid);
|
struct p9_fid *fid, bool new);
|
||||||
|
|
||||||
/* other default globals */
|
/* other default globals */
|
||||||
#define V9FS_PORT 564
|
#define V9FS_PORT 564
|
||||||
|
@ -224,12 +225,12 @@ static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
|
||||||
*/
|
*/
|
||||||
static inline struct inode *
|
static inline struct inode *
|
||||||
v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
||||||
struct super_block *sb)
|
struct super_block *sb, bool new)
|
||||||
{
|
{
|
||||||
if (v9fs_proto_dotl(v9ses))
|
if (v9fs_proto_dotl(v9ses))
|
||||||
return v9fs_fid_iget_dotl(sb, fid);
|
return v9fs_fid_iget_dotl(sb, fid, new);
|
||||||
else
|
else
|
||||||
return v9fs_fid_iget(sb, fid);
|
return v9fs_fid_iget(sb, fid, new);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -364,7 +364,8 @@ void v9fs_evict_inode(struct inode *inode)
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid)
|
struct inode *
|
||||||
|
v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid, bool new)
|
||||||
{
|
{
|
||||||
dev_t rdev;
|
dev_t rdev;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -376,8 +377,18 @@ struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid)
|
||||||
inode = iget_locked(sb, QID2INO(&fid->qid));
|
inode = iget_locked(sb, QID2INO(&fid->qid));
|
||||||
if (unlikely(!inode))
|
if (unlikely(!inode))
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
if (!(inode->i_state & I_NEW))
|
if (!(inode->i_state & I_NEW)) {
|
||||||
return inode;
|
if (!new) {
|
||||||
|
goto done;
|
||||||
|
} else {
|
||||||
|
p9_debug(P9_DEBUG_VFS, "WARNING: Inode collision %ld\n",
|
||||||
|
inode->i_ino);
|
||||||
|
iput(inode);
|
||||||
|
remove_inode_hash(inode);
|
||||||
|
inode = iget_locked(sb, QID2INO(&fid->qid));
|
||||||
|
WARN_ON(!(inode->i_state & I_NEW));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the inode with the stat info
|
* initialize the inode with the stat info
|
||||||
|
@ -401,11 +412,11 @@ struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid)
|
||||||
v9fs_set_netfs_context(inode);
|
v9fs_set_netfs_context(inode);
|
||||||
v9fs_cache_inode_get_cookie(inode);
|
v9fs_cache_inode_get_cookie(inode);
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
done:
|
||||||
return inode;
|
return inode;
|
||||||
error:
|
error:
|
||||||
iget_failed(inode);
|
iget_failed(inode);
|
||||||
return ERR_PTR(retval);
|
return ERR_PTR(retval);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,8 +448,15 @@ static int v9fs_at_to_dotl_flags(int flags)
|
||||||
*/
|
*/
|
||||||
static void v9fs_dec_count(struct inode *inode)
|
static void v9fs_dec_count(struct inode *inode)
|
||||||
{
|
{
|
||||||
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
|
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) {
|
||||||
drop_nlink(inode);
|
if (inode->i_nlink) {
|
||||||
|
drop_nlink(inode);
|
||||||
|
} else {
|
||||||
|
p9_debug(P9_DEBUG_VFS,
|
||||||
|
"WARNING: unexpected i_nlink zero %d inode %ld\n",
|
||||||
|
inode->i_nlink, inode->i_ino);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,6 +507,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
|
||||||
} else
|
} else
|
||||||
v9fs_dec_count(inode);
|
v9fs_dec_count(inode);
|
||||||
|
|
||||||
|
if (inode->i_nlink <= 0) /* no more refs unhash it */
|
||||||
|
remove_inode_hash(inode);
|
||||||
|
|
||||||
v9fs_invalidate_inode_attr(inode);
|
v9fs_invalidate_inode_attr(inode);
|
||||||
v9fs_invalidate_inode_attr(dir);
|
v9fs_invalidate_inode_attr(dir);
|
||||||
|
|
||||||
|
@ -554,7 +575,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
|
||||||
/*
|
/*
|
||||||
* instantiate inode and assign the unopened fid to the dentry
|
* instantiate inode and assign the unopened fid to the dentry
|
||||||
*/
|
*/
|
||||||
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
|
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, true);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
p9_debug(P9_DEBUG_VFS,
|
p9_debug(P9_DEBUG_VFS,
|
||||||
|
@ -683,7 +704,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
else if (IS_ERR(fid))
|
else if (IS_ERR(fid))
|
||||||
inode = ERR_CAST(fid);
|
inode = ERR_CAST(fid);
|
||||||
else
|
else
|
||||||
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
|
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, false);
|
||||||
/*
|
/*
|
||||||
* If we had a rename on the server and a parallel lookup
|
* If we had a rename on the server and a parallel lookup
|
||||||
* for the new name, then make sure we instantiate with
|
* for the new name, then make sure we instantiate with
|
||||||
|
|
|
@ -52,7 +52,10 @@ static kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
|
||||||
return current_fsgid();
|
return current_fsgid();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode *v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid)
|
|
||||||
|
|
||||||
|
struct inode *
|
||||||
|
v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid, bool new)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
@ -62,8 +65,18 @@ struct inode *v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid)
|
||||||
inode = iget_locked(sb, QID2INO(&fid->qid));
|
inode = iget_locked(sb, QID2INO(&fid->qid));
|
||||||
if (unlikely(!inode))
|
if (unlikely(!inode))
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
if (!(inode->i_state & I_NEW))
|
if (!(inode->i_state & I_NEW)) {
|
||||||
return inode;
|
if (!new) {
|
||||||
|
goto done;
|
||||||
|
} else { /* deal with race condition in inode number reuse */
|
||||||
|
p9_debug(P9_DEBUG_ERROR, "WARNING: Inode collision %lx\n",
|
||||||
|
inode->i_ino);
|
||||||
|
iput(inode);
|
||||||
|
remove_inode_hash(inode);
|
||||||
|
inode = iget_locked(sb, QID2INO(&fid->qid));
|
||||||
|
WARN_ON(!(inode->i_state & I_NEW));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the inode with the stat info
|
* initialize the inode with the stat info
|
||||||
|
@ -90,12 +103,11 @@ struct inode *v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
done:
|
||||||
return inode;
|
return inode;
|
||||||
error:
|
error:
|
||||||
iget_failed(inode);
|
iget_failed(inode);
|
||||||
return ERR_PTR(retval);
|
return ERR_PTR(retval);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dotl_openflag_map {
|
struct dotl_openflag_map {
|
||||||
|
@ -247,7 +259,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
|
||||||
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
inode = v9fs_fid_iget_dotl(dir->i_sb, fid);
|
inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
|
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
|
||||||
|
@ -340,7 +352,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* instantiate inode and assign the unopened fid to the dentry */
|
/* instantiate inode and assign the unopened fid to the dentry */
|
||||||
inode = v9fs_fid_iget_dotl(dir->i_sb, fid);
|
inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
|
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
|
||||||
|
@ -776,7 +788,7 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
err);
|
err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
inode = v9fs_fid_iget_dotl(dir->i_sb, fid);
|
inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
|
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
|
||||||
|
|
|
@ -139,7 +139,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
|
||||||
else
|
else
|
||||||
sb->s_d_op = &v9fs_dentry_operations;
|
sb->s_d_op = &v9fs_dentry_operations;
|
||||||
|
|
||||||
inode = v9fs_get_inode_from_fid(v9ses, fid, sb);
|
inode = v9fs_get_inode_from_fid(v9ses, fid, sb, true);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
retval = PTR_ERR(inode);
|
retval = PTR_ERR(inode);
|
||||||
goto release_sb;
|
goto release_sb;
|
||||||
|
|
Loading…
Reference in New Issue