diff options
| author | Jori Koolstra <jkoolstra@xs4all.nl> | 2026-05-28 17:58:46 +0000 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-05-29 09:47:02 +0200 |
| commit | f2f1dddccae50f7a1d088285c53c376e26cedf67 (patch) | |
| tree | f60f94262825438ae6a6df1542e7f39caf423207 | |
| parent | 8c47b5e9b9f4a861a87e40d5294de7fda548fa37 (diff) | |
| download | lwn-f2f1dddccae50f7a1d088285c53c376e26cedf67.tar.gz lwn-f2f1dddccae50f7a1d088285c53c376e26cedf67.zip | |
vfs: make LAST_XXX private to fs/namei.c
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 <jkoolstra@xs4all.nl>
Link: https://patch.msgid.link/20260528175854.57626-1-jkoolstra@xs4all.nl
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: NeilBrown <neil@brown.name>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
| -rw-r--r-- | fs/namei.c | 20 | ||||
| -rw-r--r-- | fs/smb/server/vfs.c | 15 | ||||
| -rw-r--r-- | include/linux/namei.h | 7 |
3 files changed, 20 insertions, 22 deletions
diff --git a/fs/namei.c b/fs/namei.c index e1fe0f28b923..05291e6f4bba 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 <linux/vmalloc.h> #include <linux/sched/xacct.h> #include <linux/crc32c.h> -#include <linux/namei.h> #include <linux/splice.h> #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 *); |
