... and parse_longname() is not guaranteed that. That's the reason why it uses kmemdup_nul() to build the argument for kstrtou64(); the problem is, kstrtou64() is not the only thing that need it. Just get a NUL-terminated copy of the entire thing and be done with that... Fixes: dd66df0053ef "ceph: add support for encrypted snapshot names" Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- fs/ceph/crypto.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index 3b3c4d8d401e..164e7981aecb 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -215,35 +215,30 @@ static struct inode *parse_longname(const struct inode *parent, struct ceph_client *cl = ceph_inode_to_client(parent); struct inode *dir = NULL; struct ceph_vino vino = { .snap = CEPH_NOSNAP }; - char *inode_number; char *name_end; - int orig_len = *name_len; int ret = -EIO; - + /* NUL-terminate */ + char *s __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL); + if (!s) + return ERR_PTR(-ENOMEM); /* Skip initial '_' */ - name++; - name_end = strrchr(name, '_'); + s++; + name_end = strrchr(s, '_'); if (!name_end) { - doutc(cl, "failed to parse long snapshot name: %s\n", name); + doutc(cl, "failed to parse long snapshot name: %s\n", s); return ERR_PTR(-EIO); } - *name_len = (name_end - name); + *name_len = (name_end - s); if (*name_len <= 0) { pr_err_client(cl, "failed to parse long snapshot name\n"); return ERR_PTR(-EIO); } /* Get the inode number */ - inode_number = kmemdup_nul(name_end + 1, - orig_len - *name_len - 2, - GFP_KERNEL); - if (!inode_number) - return ERR_PTR(-ENOMEM); - ret = kstrtou64(inode_number, 10, &vino.ino); + ret = kstrtou64(name_end + 1, 10, &vino.ino); if (ret) { - doutc(cl, "failed to parse inode number: %s\n", name); - dir = ERR_PTR(ret); - goto out; + doutc(cl, "failed to parse inode number: %s\n", s); + return ERR_PTR(ret); } /* And finally the inode */ @@ -252,11 +247,8 @@ static struct inode *parse_longname(const struct inode *parent, /* This can happen if we're not mounting cephfs on the root */ dir = ceph_get_inode(parent->i_sb, vino, NULL); if (IS_ERR(dir)) - doutc(cl, "can't find inode %s (%s)\n", inode_number, name); + doutc(cl, "can't find inode %s (%s)\n", name_end + 1, name); } - -out: - kfree(inode_number); return dir; } -- 2.39.5