summaryrefslogtreecommitdiff
path: root/fs/d_path.c
AgeCommit message (Collapse)Author
2021-05-18getcwd(2): clean up error handlingAl Viro
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: prepend_path() is unlikely to return non-zeroAl Viro
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: prepend_path(): lift the inner loop into a new helperAl Viro
... and leave the rename_lock/mount_lock handling in prepend_path() itself Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: prepend_path(): lift resetting b in case when we'd return 3 out of loopAl Viro
preparation to extracting the loop into helper (next commit) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: prepend_path(): get rid of vfsmntAl Viro
it's kept equal to &mnt->mnt all along. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: introduce struct prepend_bufferAl Viro
We've a lot of places where we have pairs of form (pointer to end of buffer, amount of space left in front of that). These sit in pairs of variables located next to each other and usually passed by reference. Turn those into instances of new type (struct prepend_buffer) and pass reference to the pair instead of pairs of references to its fields. Declared and initialized by DECLARE_BUFFER(name, buf, buflen). extract_string(prepend_buffer) returns the buffer contents if no overflow has happened, ERR_PTR(ENAMETOOLONG) otherwise. All places where we used to have that boilerplate converted to use of that helper. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: make prepend_name() booleanAl Viro
It returns only 0 or -ENAMETOOLONG and both callers only check if the result is negative. Might as well return true on success and false on failure... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: lift -ENAMETOOLONG handling into callers of prepend_path()Al Viro
The only negative value ever returned by prepend_path() is -ENAMETOOLONG and callers can recognize that situation (overflow) by looking at the sign of buflen. Lift that into the callers; we already have the same logics (buf if buflen is non-negative, ERR_PTR(-ENAMETOOLONG) otherwise) in several places and that'll become a new primitive several commits down the road. Make prepend_path() return 0 instead of -ENAMETOOLONG. That makes for saner calling conventions (0/1/2/3/-ENAMETOOLONG is obnoxious) and callers actually get simpler, especially once the aforementioned primitive gets added. In prepend_path() itself we switch prepending the / (in case of empty path) to use of prepend() - no need to open-code that, compiler will do the right thing. It's exactly the same logics as in __dentry_path(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: don't bother with return value of prepend()Al Viro
Only simple_dname() checks it, and there we can simply do those calls and check for overflow (by looking of negative buflen) in the end. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18getcwd(2): saner logics around prepend_path() callAl Viro
The only negative value that might get returned by prepend_path() is -ENAMETOOLONG, and that happens only on overflow. The same goes for prepend_unreachable(). Overflow is detectable by observing negative buflen, so we can simplify the control flow around the prepend_path() call. Expand prepend_unreachable(), while we are at it - that's the only caller. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: get rid of path_with_deleted()Al Viro
expand in the sole caller; transform the initial prepends similar to what we'd done in dentry_path() (prepend_path() will fail the right way if we call it with negative buflen, same as __dentry_path() does). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-18d_path: regularize handling of root dentry in __dentry_path()Al Viro
All path-forming primitives boil down to sequence of prepend_name() on dentries encountered along the way toward root. Each time we prepend / + dentry name to the buffer. Normally that does exactly what we want, but there's a corner case when we don't call prepend_name() at all (in case of __dentry_path() that happens if we are given root dentry). We obviously want to end up with "/", rather than "", so this corner case needs to be handled. __dentry_path() used to manually put '/' in the end of buffer before doing anything else, to be overwritten by the first call of prepend_name() if one happens and to be left in place if we don't call prepend_name() at all. That required manually checking that we had space in the buffer (prepend_name() and prepend() take care of such checks themselves) and lead to clumsy keeping track of return value. A better approach is to check if the main loop has added anything into the buffer and prepend "/" if it hasn't. A side benefit of using prepend() is that it does the right thing if we'd already run out of buffer, making the overflow-handling logics simpler. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-17d_path: saner calling conventions for __dentry_path()Al Viro
1) lift NUL-termination into the callers 2) pass pointer to the end of buffer instead of that to beginning. (1) allows to simplify dentry_path() - we don't need to play silly games with restoring the leading / of "//deleted" after __dentry_path() would've overwritten it with NUL. We also do not need to check if (either) prepend() in there fails - if the buffer is not large enough, we'll end with negative buflen after prepend() and __dentry_path() will return the right value (ERR_PTR(-ENAMETOOLONG)) just fine. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-05-17d_path: "\0" is {0,0}, not {0}Al Viro
Single-element array consisting of one NUL is spelled ""... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2021-03-21constify dentry argument of dentry_path()/dentry_path_raw()Al Viro
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2020-10-14fs: fix NULL dereference due to data race in prepend_path()Andrii Nakryiko
Fix data race in prepend_path() with re-reading mnt->mnt_ns twice without holding the lock. is_mounted() does check for NULL, but is_anon_ns(mnt->mnt_ns) might re-read the pointer again which could be NULL already, if in between reads one of kern_unmount()/kern_unmount_array()/umount_tree() sets mnt->mnt_ns to NULL. This is seen in production with the following stack trace: BUG: kernel NULL pointer dereference, address: 0000000000000048 ... RIP: 0010:prepend_path.isra.4+0x1ce/0x2e0 Call Trace: d_path+0xe6/0x150 proc_pid_readlink+0x8f/0x100 vfs_readlink+0xf8/0x110 do_readlinkat+0xfd/0x120 __x64_sys_readlinkat+0x1a/0x20 do_syscall_64+0x42/0x110 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: f2683bd8d5bd ("[PATCH] fix d_absolute_path() interplay with fsmount()") Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-08-30[PATCH] fix d_absolute_path() interplay with fsmount()Al Viro
stuff in anon namespace should be treated as unattached. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2019-05-21unexport simple_dname()Al Viro
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-03-29split d_path() and friends into a separate fileAl Viro
Those parts of fs/dcache.c are pretty much self-contained. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>