From 50f307401113350a8d46ca45cace07a92c9bedc8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jun 2018 20:27:29 -0400 Subject: [PATCH 1/5] hostfs_lookup: switch to d_splice_alias() Signed-off-by: Al Viro --- fs/hostfs/hostfs_kern.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 2597b290c2a5..444c7b170359 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -610,33 +610,21 @@ static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, int err; inode = hostfs_iget(ino->i_sb); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); + if (IS_ERR(inode)) goto out; - } err = -ENOMEM; name = dentry_name(dentry); - if (name == NULL) - goto out_put; - - err = read_name(inode, name); - - __putname(name); - if (err == -ENOENT) { - iput(inode); - inode = NULL; + if (name) { + err = read_name(inode, name); + __putname(name); + } + if (err) { + iput(inode); + inode = (err == -ENOENT) ? NULL : ERR_PTR(err); } - else if (err) - goto out_put; - - d_add(dentry, inode); - return NULL; - - out_put: - iput(inode); out: - return ERR_PTR(err); + return d_splice_alias(inode, dentry); } static int hostfs_link(struct dentry *to, struct inode *ino, From e876c445df4009d7b1ebdd2a92ca23566ca05440 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jun 2018 20:33:59 -0400 Subject: [PATCH 2/5] hpfs: fix an inode leak in lookup, switch to d_splice_alias() Signed-off-by: Al Viro --- fs/hpfs/dir.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index c83ece7facc5..d85230c84ef2 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -244,6 +244,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in result = iget_locked(dir->i_sb, ino); if (!result) { hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode"); + result = ERR_PTR(-ENOMEM); goto bail1; } if (result->i_state & I_NEW) { @@ -266,6 +267,8 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in if (de->has_acl || de->has_xtd_perm) if (!sb_rdonly(dir->i_sb)) { hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); + iput(result); + result = ERR_PTR(-EINVAL); goto bail1; } @@ -301,29 +304,17 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in } } +bail1: hpfs_brelse4(&qbh); /* * Made it. */ - end: - end_add: +end: +end_add: hpfs_unlock(dir->i_sb); - d_add(dentry, result); - return NULL; - - /* - * Didn't. - */ - bail1: - - hpfs_brelse4(&qbh); - - /*bail:*/ - - hpfs_unlock(dir->i_sb); - return ERR_PTR(-ENOENT); + return d_splice_alias(result, dentry); } const struct file_operations hpfs_dir_ops = From 855371bd01b4cd8cf0e2b8ca172a5c30a481f963 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jun 2018 20:48:31 -0400 Subject: [PATCH 3/5] afs: switch dynroot lookups to d_splice_alias() ->lookup() methods can (and should) use d_splice_alias() instead of d_add(). Even if they are not going to be hit by open_by_handle(), code does get copied around... Acked-by: David Howells Signed-off-by: Al Viro --- fs/afs/dynroot.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c index 174e843f0633..40fea59067b3 100644 --- a/fs/afs/dynroot.c +++ b/fs/afs/dynroot.c @@ -143,7 +143,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr { struct afs_vnode *vnode; struct inode *inode; - int ret; vnode = AFS_FS_I(dir); @@ -161,21 +160,10 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr return afs_lookup_atcell(dentry); inode = afs_try_auto_mntpt(dentry, dir); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - if (ret == -ENOENT) { - d_add(dentry, NULL); - _leave(" = NULL [negative]"); - return NULL; - } - _leave(" = %d [do]", ret); - return ERR_PTR(ret); - } + if (inode == ERR_PTR(-ENOENT)) + inode = NULL; - d_add(dentry, inode); - _leave(" = 0 { ino=%lu v=%u }", - d_inode(dentry)->i_ino, d_inode(dentry)->i_generation); - return NULL; + return d_splice_alias(inode, dentry); } const struct inode_operations afs_dynroot_inode_operations = { From 34b2a88fb4aa4de34e1d5f9fc2761b746980f9b1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Jun 2018 10:43:51 -0400 Subject: [PATCH 4/5] afs_lookup(): switch to d_splice_alias() ->lookup() methods can (and should) use d_splice_alias() instead of d_add(). Even if they are not going to be hit by open_by_handle(), code does get copied around; besides, d_splice_alias() has better calling conventions for use in ->lookup(), so the code gets simpler. Acked-by: David Howells Signed-off-by: Al Viro --- fs/afs/dir.c | 47 ++++++++++++----------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 7d623008157f..52f44255f65d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -822,6 +822,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, { struct afs_vnode *dvnode = AFS_FS_I(dir); struct inode *inode; + struct dentry *d; struct key *key; int ret; @@ -862,43 +863,19 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, afs_stat_v(dvnode, n_lookup); inode = afs_do_lookup(dir, dentry, key); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - if (ret == -ENOENT) { - inode = afs_try_auto_mntpt(dentry, dir); - if (!IS_ERR(inode)) { - key_put(key); - goto success; - } - - ret = PTR_ERR(inode); - } - - key_put(key); - if (ret == -ENOENT) { - d_add(dentry, NULL); - _leave(" = NULL [negative]"); - return NULL; - } - _leave(" = %d [do]", ret); - return ERR_PTR(ret); - } - dentry->d_fsdata = (void *)(unsigned long)dvnode->status.data_version; - - /* instantiate the dentry */ key_put(key); - if (IS_ERR(inode)) { - _leave(" = %ld", PTR_ERR(inode)); - return ERR_CAST(inode); + if (inode == ERR_PTR(-ENOENT)) { + inode = afs_try_auto_mntpt(dentry, dir); + if (inode == ERR_PTR(-ENOENT)) + inode = NULL; + } else { + dentry->d_fsdata = + (void *)(unsigned long)dvnode->status.data_version; } - -success: - d_add(dentry, inode); - _leave(" = 0 { ino=%lu v=%u }", - d_inode(dentry)->i_ino, - d_inode(dentry)->i_generation); - - return NULL; + d = d_splice_alias(inode, dentry); + if (!IS_ERR_OR_NULL(d)) + d->d_fsdata = dentry->d_fsdata; + return d; } /* From 1401a0fc2d47988677dc1dbfd56ff89daa323717 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Jun 2018 10:45:44 -0400 Subject: [PATCH 5/5] afs_try_auto_mntpt(): return NULL instead of ERR_PTR(-ENOENT) simpler logics in callers that way Acked-by: David Howells Signed-off-by: Al Viro --- fs/afs/dir.c | 2 -- fs/afs/dynroot.c | 13 ++----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 52f44255f65d..855bf2b79fed 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -866,8 +866,6 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, key_put(key); if (inode == ERR_PTR(-ENOENT)) { inode = afs_try_auto_mntpt(dentry, dir); - if (inode == ERR_PTR(-ENOENT)) - inode = NULL; } else { dentry->d_fsdata = (void *)(unsigned long)dvnode->status.data_version; diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c index 40fea59067b3..1cde710a8013 100644 --- a/fs/afs/dynroot.c +++ b/fs/afs/dynroot.c @@ -83,7 +83,7 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir) out: _leave("= %d", ret); - return ERR_PTR(ret); + return ret == -ENOENT ? NULL : ERR_PTR(ret); } /* @@ -141,11 +141,6 @@ out_p: static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { - struct afs_vnode *vnode; - struct inode *inode; - - vnode = AFS_FS_I(dir); - _enter("%pd", dentry); ASSERTCMP(d_inode(dentry), ==, NULL); @@ -159,11 +154,7 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr memcmp(dentry->d_name.name, "@cell", 5) == 0) return afs_lookup_atcell(dentry); - inode = afs_try_auto_mntpt(dentry, dir); - if (inode == ERR_PTR(-ENOENT)) - inode = NULL; - - return d_splice_alias(inode, dentry); + return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry); } const struct inode_operations afs_dynroot_inode_operations = {