Page MenuHomeFreeBSD

vfs: add kernel-side realpathat
ClosedPublic

Authored by mjg on Feb 7 2020, 7:05 PM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Jun 20, 9:12 PM
Unknown Object (File)
Wed, Jun 19, 11:59 PM
Unknown Object (File)
May 8 2024, 2:08 PM
Unknown Object (File)
May 8 2024, 10:40 AM
Unknown Object (File)
May 8 2024, 10:38 AM
Unknown Object (File)
May 8 2024, 10:36 AM
Unknown Object (File)
May 8 2024, 10:35 AM
Unknown Object (File)
May 8 2024, 3:28 AM

Details

Summary

realpath(3) is a major source of fstatat calls e.g., during buildkernel (used heavily by clang).

Moving realpath into the kernel removes most stats and getcwd calls (see below for example test result).

This works by performing a regular lookup while saving the name and found parent directory. If the terminal vnode is a directory we can resolve it using usual means. Otherwise we can use the name saved by lookup and resolve the parent.

The patch is almost complete (may use some comments). truss correctly dumps data, but ktrace only dumps one buffer and not the other one. I have not checked yet how to sort that out, but I don't think it should be a blocker.

before:

__getcwd                                                      66065
mprotect                                                      72233
open                                                          94032
sigaction                                                    111967
write                                                        133762
pread                                                        195676
openat                                                       281137
fstat                                                        318231
close                                                        325406
sigprocmask                                                  718695
fstatat                                                     1423441
mmap                                                        3259492

after:

mprotect                                                      72233
open                                                          94032
sigaction                                                    111967
write                                                        133761
fstatat                                                      148846
pread                                                        195676
__realpath                                                   225900
openat                                                       281137
fstat                                                        318231
close                                                        325404
sigprocmask                                                  718699
mmap                                                        3260705

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 29234

Event Timeline

lib/libc/sys/Symbol.map
405

Does this actually need to be exported?

sys/kern/syscalls.master
3218
_Out_writes_z_(size) char *buf,
  • fix syscalls.master entry
  • few nits
lib/libc/sys/Symbol.map
405

I'm just following __getcwd. I have no opinion otherwise.

lib/libc/sys/Symbol.map
405

The __getcwd export was probably a mistake (we exported WAY too much stuff in the first cut and that wasn't fixed...)

lib/libc/sys/Symbol.map
405

I support this, sys__realpath() should be enough for libc use.

sys/kern/vfs_cache.c
2230

This blank line is excessive.

2241

And this too.

2377–2378

The function lacks a herald comment explaining it. Asserts are good but not enough.

2477

Again no herald comment.

2481

Make slash_prefixed bool, in all places ?

2487

Don't you need to check that there is no underflow ? If you rely on the caller providing enough initial length, then this should be asserted instead.

  • unexport __realpath
  • convert slash_prexied to bool
  • add more comments
  • validate length in vn_fullpath_any
  • slash_prefixed and whitespace cosmetics
  • remove wrong Symbol.map entry

For some reason libc started to fail to compile for me (regardless of the state of Symbol.map):

ld: error: can't create dynamic relocation R_X86_64_32 against symbol: SYS___realpath in reado
nly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocatio
ns in the output
>>> defined in __realpath.pico
>>> referenced by __realpath.S:4
>>>               __realpath.pico:(___realpath)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
*** [libc.so.7.full] Error code 1

any idea what's going on here? I compared the entries with older syscalls and I don't see any differences of note. i did make sysent on top of /usr/src.

  • only set freebuf after success to match other routines
  • handle rtld-elf
  • add __getosreldate check as a temporary aid for upgrades. the value in there is to be changed

this builds and works fine for me

Can I get further review on this?

I verified that former vn_fullpath1 consumers which now call vn_fullpath_any/dir get the same results (both the content of the buffer and length returned).

realpath tests in kyua trivialy pass. one concerns the userspace implementation and is partially moot, the other a case of an empty symlink which is handled in the expected manner by lookup itself.

What I verified by hand and could be added to kyua is that hardlinks are properly handled (as in, realpath to foo is not the same as realpath to bar, even if they are the same vnode).

How jails and chroots are handled ?

lib/libc/stdlib/realpath.c
228

You do remember about this place. Not sure if at_bsdflags would be easier.

lib/libc/sys/Symbol.map
831

so you are still exporting this

Same way as in the code prior to the patch -- routines resolve up to a point of reaching the passed 'rdir' vnode and I'm passing the same stuff getcwd does.

lib/libc/stdlib/realpath.c
228

This is at temporary aid for upgrading which I'm going to remove in few weeks. I had no difficulty remembering to remove equivalent compat for F_ISUNIONSTACK so I think we are fine here..

lib/libc/sys/Symbol.map
831

I moved it to FBSDprivate_1.0 just like __sys_sigfastblock, I thought this counts as not exporting.

lib/libc/sys/Symbol.map
831

if this is invalid what should be done here? I want to move forward with this review as it impacts some other pending work

lib/libc/sys/Symbol.map
831

Just don't mention in in Symbol.map. Nothing outside libc needs to know it exists.

lib/libc/sys/Symbol.map
831

I noted rtld-elf slurps in realpath(3) and consequently the new syscall

831

... which given the sigfastblock entry I presume makes it mandatory to note here

lib/libc/sys/Symbol.map
831

I don't think so. Rtld-elf is a "static" link. I believe __sys_sigfastblock is exported because libthr uses it.

lib/libc/sys/Symbol.map
831

This is right, libthr uses the syscall.

sys/kern/vfs_cache.c
2231

I do not see a reason to not make the syscall*at()-aware from the start.

2560

So if the last component is symlink, this code just leaves the symlink in the result ? I do not think it is a right behavior for realpath(2).

You might want to add AT_SYMLINK_NOFOLLOW flag, because I can see that both cases make sense for syscall.

mjg retitled this revision from vfs: add realpath(2) to vfs: add kernel-side realpathat.
  • rename to realpathat
mjg marked an inline comment as done.Feb 20 2020, 3:09 AM
mjg added inline comments.
sys/kern/vfs_cache.c
2560

The last component can't be a symlink because they are always resolved and if resolving fails, lookup also fails. I don't think adding the specific flag is of much use at this stage, there is the flags argument hardwired to 0 so this can always be extended later.

Ok, lets postpone AT_NOFOLLOW.

I think this is fine, and I remembered something that might make this even more useful. It may be, if AT_BENEATH plus allowing this syscall under cap mode with relative paths (with relative against dirfd result). I added Ryan who could comment more.

This revision is now accepted and ready to land.Feb 20 2020, 1:30 PM
This revision was automatically updated to reflect the committed changes.

The flags argument is there specifically so these kind of extensions are possible without adding new syscalls. The only consumer does not use them and I think adding capability-aware realpath is a separate effort. Since this partially blocks other work I just went ahead with the commit.