The only user of LAST_XXX outside of fs/namei.c is fs/smb/server/vfs.c; ksmbd_vfs_path_lookup() calls vfs_path_parent_lookup() and expects a LAST_NORM last type (or it will be ENOENT). ksmbd_vfs_rename() also calls vfs_path_parent_lookup() but forgets the LAST_NORM check. It does not really make sense to have vfs_path_parent_lookup() expose the last_type because it is only needed to ensure it is LAST_NORM. So let's do this check in vfs_path_parent_lookup() instead and keep the LAST_XXX internal to fs/namei.c. This changes the ENOENT errno in ksmbd_vfs_path_lookup() to EINVAL, which matches better with how this is handled by callers of filename_parentat(). Signed-off-by: Jori Koolstra --- fs/namei.c | 20 ++++++++++++++++---- fs/smb/server/vfs.c | 15 +++------------ include/linux/namei.h | 7 +------ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index c7fac83c9a85..889792761bc2 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -129,6 +129,11 @@ static struct kmem_cache *__names_cache __ro_after_init; #define names_cache runtime_const_ptr(__names_cache) +/* + * Type of the last component on LOOKUP_PARENT + */ +enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; + void __init filename_init(void) { __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0, @@ -3051,15 +3056,22 @@ EXPORT_SYMBOL(kern_path); * @flags: lookup flags * @parent: pointer to struct path to fill * @last: last component - * @type: type of the last component * @root: pointer to struct path of the base directory */ int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, - struct path *parent, struct qstr *last, int *type, + struct path *parent, struct qstr *last, const struct path *root) { - return __filename_parentat(AT_FDCWD, filename, flags, parent, last, - type, root); + int type; + int err = __filename_parentat(AT_FDCWD, filename, flags, parent, last, + &type, root); + if (err) + return err; + if (unlikely(type != LAST_NORM)) { + path_put(parent); + return -EINVAL; + } + return 0; } EXPORT_SYMBOL(vfs_path_parent_lookup); diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index d08973b288e5..cd1dbca0cffb 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "glob.h" @@ -56,7 +55,7 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf, { struct qstr last; const struct path *root_share_path = &share_conf->vfs_path; - int err, type; + int err; struct dentry *d; if (pathname[0] == '\0') { @@ -67,17 +66,11 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf, } CLASS(filename_kernel, filename)(pathname); - err = vfs_path_parent_lookup(filename, flags, - path, &last, &type, + err = vfs_path_parent_lookup(filename, flags, path, &last, root_share_path); if (err) return err; - if (unlikely(type != LAST_NORM)) { - path_put(path); - return -ENOENT; - } - if (for_remove) { err = mnt_want_write(path->mnt); if (err) { @@ -668,7 +661,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, struct renamedata rd; struct ksmbd_share_config *share_conf = work->tcon->share_conf; struct ksmbd_file *parent_fp; - int new_type; int err, lookup_flags = LOOKUP_NO_SYMLINKS; if (ksmbd_override_fsids(work)) @@ -678,8 +670,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, retry: err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH, - &new_path, &new_last, &new_type, - &share_conf->vfs_path); + &new_path, &new_last, &share_conf->vfs_path); if (err) goto out1; diff --git a/include/linux/namei.h b/include/linux/namei.h index 2ad6dd9987b9..3941b9f1dec7 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -13,11 +13,6 @@ enum { MAX_NESTED_LINKS = 8 }; #define MAXSYMLINKS 40 -/* - * Type of the last component on LOOKUP_PARENT - */ -enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; - /* pathwalk mode */ #define LOOKUP_FOLLOW BIT(0) /* follow links at the end */ #define LOOKUP_DIRECTORY BIT(1) /* require a directory */ @@ -67,7 +62,7 @@ static inline void end_removing_path(const struct path *path , struct dentry *de end_creating_path(path, dentry); } int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, - struct path *parent, struct qstr *last, int *type, + struct path *parent, struct qstr *last, const struct path *root); int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); -- 2.54.0 Several functions in namei.c take an "int *type" parameter, such as filename_parentat(). To know what values this can take you have to find the anonymous struct that defines the LAST_XXX values. Define an enum last_type to make this type explicit. Signed-off-by: Jori Koolstra --- fs/namei.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 889792761bc2..a1ba45f9faa9 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -132,7 +132,7 @@ static struct kmem_cache *__names_cache __ro_after_init; /* * Type of the last component on LOOKUP_PARENT */ -enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; +enum last_type {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; void __init filename_init(void) { @@ -732,7 +732,7 @@ struct nameidata { struct inode *inode; /* path.dentry.d_inode */ unsigned int flags, state; unsigned seq, next_seq, m_seq, r_seq; - int last_type; + enum last_type last_type; unsigned depth; int total_link_count; struct saved { @@ -2225,7 +2225,7 @@ static struct dentry *follow_dotdot(struct nameidata *nd) return dget(nd->path.dentry); } -static const char *handle_dots(struct nameidata *nd, int type) +static const char *handle_dots(struct nameidata *nd, enum last_type type) { if (type == LAST_DOTDOT) { const char *error = NULL; @@ -2873,7 +2873,7 @@ static int path_parentat(struct nameidata *nd, unsigned flags, /* Note: this does not consume "name" */ static int __filename_parentat(int dfd, struct filename *name, unsigned int flags, struct path *parent, - struct qstr *last, int *type, + struct qstr *last, enum last_type *type, const struct path *root) { int retval; @@ -2898,7 +2898,7 @@ static int __filename_parentat(int dfd, struct filename *name, static int filename_parentat(int dfd, struct filename *name, unsigned int flags, struct path *parent, - struct qstr *last, int *type) + struct qstr *last, enum last_type *type) { return __filename_parentat(dfd, name, flags, parent, last, type, NULL); } @@ -2966,7 +2966,8 @@ static struct dentry *__start_removing_path(int dfd, struct filename *name, struct path parent_path __free(path_put) = {}; struct dentry *d; struct qstr last; - int type, error; + enum last_type type; + int error; error = filename_parentat(dfd, name, 0, &parent_path, &last, &type); if (error) @@ -3012,7 +3013,8 @@ struct dentry *kern_path_parent(const char *name, struct path *path) CLASS(filename_kernel, filename)(name); struct dentry *d; struct qstr last; - int type, error; + enum last_type type; + int error; error = filename_parentat(AT_FDCWD, filename, 0, &parent_path, &last, &type); if (error) @@ -3062,7 +3064,7 @@ int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, struct path *parent, struct qstr *last, const struct path *root) { - int type; + enum last_type type; int err = __filename_parentat(AT_FDCWD, filename, flags, parent, last, &type, root); if (err) @@ -4937,7 +4939,7 @@ static struct dentry *filename_create(int dfd, struct filename *name, bool want_dir = lookup_flags & LOOKUP_DIRECTORY; unsigned int reval_flag = lookup_flags & LOOKUP_REVAL; unsigned int create_flags = LOOKUP_CREATE | LOOKUP_EXCL; - int type; + enum last_type type; int error; error = filename_parentat(dfd, name, reval_flag, path, &last, &type); @@ -5399,7 +5401,7 @@ int filename_rmdir(int dfd, struct filename *name) struct dentry *dentry; struct path path; struct qstr last; - int type; + enum last_type type; unsigned int lookup_flags = 0; struct delegated_inode delegated_inode = { }; retry: @@ -5408,6 +5410,8 @@ int filename_rmdir(int dfd, struct filename *name) return error; switch (type) { + case LAST_NORM: + break; case LAST_DOTDOT: error = -ENOTEMPTY; goto exit2; @@ -5541,7 +5545,7 @@ int filename_unlinkat(int dfd, struct filename *name) struct dentry *dentry; struct path path; struct qstr last; - int type; + enum last_type type; struct inode *inode; struct delegated_inode delegated_inode = { }; unsigned int lookup_flags = 0; @@ -6108,7 +6112,7 @@ int filename_renameat2(int olddfd, struct filename *from, struct renamedata rd; struct path old_path, new_path; struct qstr old_last, new_last; - int old_type, new_type; + enum last_type old_type, new_type; struct delegated_inode delegated_inode = { }; unsigned int lookup_flags = 0; bool should_retry = false; -- 2.54.0