Massive pathwalk rewrite and cleanups. Several iterations had been posted; hopefully the damn thing is getting readable and understandable now. Pretty much all parts of pathname resolutions are affected... The branch is identical to what has sat in -next, except for commit message in "lift all calls of step_into() out of follow_dotdot/follow_dotdot_rcu", crediting Qian Cai for reporting the bug; only commit message changed there. I'd folded the fix back in Mar 25, and it had been present in -next since then (see #work.dotdot). I asked Qian Cai whether he wanted his tested-by on that thing, got no reply... Anyway, all diffs in that branch are identical to the ones in #work.dotdot, which is what has sat in linux-next for the last week. The following changes since commit bb6d3fb354c5ee8d6bde2d576eb7220ea09862b9: Linux 5.6-rc1 (2020-02-09 16:08:48 -0800) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git work.dotdot1 for you to fetch changes up to 99a4a90c8e9337e364136393286544e3753673c3: lookup_open(): don't bother with fallbacks to lookup+create (2020-04-02 01:09:31 -0400) ---------------------------------------------------------------- Al Viro (69): do_add_mount(): lift lock_mount/unlock_mount into callers fix automount/automount race properly follow_automount(): get rid of dead^Wstillborn code follow_automount() doesn't need the entire nameidata make build_open_flags() treat O_CREAT | O_EXCL as implying O_NOFOLLOW handle_mounts(): start building a sane wrapper for follow_managed() atomic_open(): saner calling conventions (return dentry on success) lookup_open(): saner calling conventions (return dentry on success) do_last(): collapse the call of path_to_nameidata() handle_mounts(): pass dentry in, turn path into a pure out argument lookup_fast(): consolidate the RCU success case teach handle_mounts() to handle RCU mode lookup_fast(): take mount traversal into callers step_into() callers: dismiss the symlink earlier new step_into() flag: WALK_NOFOLLOW fold handle_mounts() into step_into() LOOKUP_MOUNTPOINT: fold path_mountpointat() into path_lookupat() expand the only remaining call of path_lookup_conditional() merging pick_link() with get_link(), part 1 merging pick_link() with get_link(), part 2 merging pick_link() with get_link(), part 3 merging pick_link() with get_link(), part 4 merging pick_link() with get_link(), part 5 merging pick_link() with get_link(), part 6 finally fold get_link() into pick_link() sanitize handling of nd->last_type, kill LAST_BIND namei: invert the meaning of WALK_FOLLOW pick_link(): check for WALK_TRAILING, not LOOKUP_PARENT link_path_walk(): simplify stack handling namei: have link_path_walk() maintain LOOKUP_PARENT massage __follow_mount_rcu() a bit new helper: traverse_mounts() atomic_open(): return the right dentry in FMODE_OPENED case atomic_open(): lift the call of may_open() into do_last() do_last(): merge the may_open() calls do_last(): don't bother with keeping got_write in FMODE_OPENED case do_last(): rejoing the common path earlier in FMODE_{OPENED,CREATED} case do_last(): simplify the liveness analysis past finish_open_created do_last(): rejoin the common path even earlier in FMODE_{OPENED,CREATED} case split the lookup-related parts of do_last() into a separate helper path_connected(): pass mount and dentry separately path_parent_directory(): leave changing path->dentry to callers expand path_parent_directory() in its callers follow_dotdot{,_rcu}(): lift switching nd->path to parent out of loop follow_dotdot{,_rcu}(): lift LOOKUP_BENEATH checks out of loop move handle_dots(), follow_dotdot() and follow_dotdot_rcu() past step_into() handle_dots(), follow_dotdot{,_rcu}(): preparation to switch to step_into() follow_dotdot{,_rcu}(): switch to use of step_into() lift all calls of step_into() out of follow_dotdot/follow_dotdot_rcu follow_dotdot{,_rcu}(): massage loops follow_dotdot_rcu(): be lazy about changing nd->path follow_dotdot(): be lazy about changing nd->path helper for mount rootwards traversal non-RCU analogue of the previous commit fs/namei.c: kill follow_mount() pick_link(): pass it struct path already with normal refcounting rules fold path_to_nameidata() into its only remaining caller pick_link(): more straightforward handling of allocation failures pick_link(): take reserving space on stack into a new helper reserve_stack(): switch to __nd_alloc_stack() __nd_alloc_stack(): make it return bool link_path_walk(): sample parent's i_uid and i_mode for the last component take post-lookup part of do_last() out of loop open_last_lookups(): consolidate fsnotify_create() calls open_last_lookups(): don't abuse complete_walk() when all we want is unlazy open_last_lookups(): lift O_EXCL|O_CREAT handling into do_open() open_last_lookups(): move complete_walk() into do_open() atomic_open(): no need to pass struct open_flags anymore lookup_open(): don't bother with fallbacks to lookup+create Documentation/filesystems/path-lookup.rst | 7 +- fs/autofs/dev-ioctl.c | 6 +- fs/internal.h | 1 - fs/namei.c | 1488 ++++++++++++----------------- fs/namespace.c | 96 +- fs/open.c | 4 +- include/linux/namei.h | 4 +- 7 files changed, 687 insertions(+), 919 deletions(-)