Introduce MountedFast function to determine mount points faster.#97
Introduce MountedFast function to determine mount points faster.#97
Conversation
|
cc @kolyshkin please have a look |
| // sure is true. When sure is false, the caller needs to check for other ' | ||
| // methods (eg: parse /proc/mounts) to successfully determine if it is a | ||
| // mount-point. | ||
| func mountedByOpenat2(path string) (mounted, sure bool, err error) { |
There was a problem hiding this comment.
How about returning an exported error instead of the sure flag?
Apparently in all error cases, sure=false. So returning an error wouldn't override the original errors.
Generally speaking Go code checks err first and doesn't consume other returning values if err != nil. I want to follow the convention here.
There was a problem hiding this comment.
@kolyshkin Do you have thoughts as you suggested this? I think it boils down to preference.
There was a problem hiding this comment.
I agree with @kzys here -- no need to change mountedByOpenat2 signature.
Basically, you need to take mounted from mountinfo/mounted_linux.go, add sure bool to it, and remove the fallback to mountinfo parsing. That's all what's needed.
|
Also, please cherry-pick 03cca99 since you're adding more implementations to test, and this becomes ugly -- and this commit is a nice solution to that. |
Instead of copy/pasting the code to check individual mountedBy* implementations, add a list and a loop to check them. The only special thing is, we have to check if the name of the function being tested is "mountedByStat", to skip erroring out on bind mounts. Otherwise the code is the same. Signed-off-by: Kir Kolyshkin <[email protected]> Signed-off-by: Manu Gupta <[email protected]>
e3c9d7c to
62d2d10
Compare
| // mount-point or not only when sure is true. When sure is false, the | ||
| // caller needs to check for other methods (eg: parse /proc/mounts) | ||
| // to successfully determine if it is a mount-point. | ||
| func MountedFast(path string) (mounted, sure bool, err error) { |
There was a problem hiding this comment.
I think in case of "not sure", we can return error indicating cannot figure out whether it is mounted or not.
in this way, we only need return two parameters "bool, error" as before.
1354229 to
59772ab
Compare
59772ab to
788a5c1
Compare
|
Hi @kolyshkin, would you be able to have a look at it? I would like to get it reviewed and address comments if you have any. I have added things that I have found out; but a final review would be great. |
|
The code looks good to me. On personal note, running unit tests as root and depending on kernel version is IMHO bad, as different people (and CI) will test different things. It seems moby is fine with that. |
74edffe to
5e7a91b
Compare
| if sure == true { | ||
| t.Errorf("MountFast: expected sure to be false, got %v", sure) | ||
| } | ||
| if mounted != false { |
There was a problem hiding this comment.
The code would be easier to read if you use the same comparison (either == false or != true) in both cases.
| if sure == true { | ||
| t.Errorf("MountFast: expected sure to be false, got %v", sure) | ||
| } | ||
| if mounted != false { |
| // mountinfo from procfs. A mount-point check is guaranteed to be a | ||
| // mount-point or not only when sure is true. When sure is false, the |
There was a problem hiding this comment.
nit: s/mount-point/mount point/. Here "mount point" is a common term, see e.g. man 8 mount.
| // mountinfo from procfs. A mount-point check is guaranteed to be a | ||
| // mount-point or not only when sure is true. When sure is false, the | ||
| // caller needs to check for other methods (eg: parse /proc/mounts) | ||
| // to successfully determine if it is a mount-point. |
There was a problem hiding this comment.
Also, probably makes sense to say this function is only available on Linux.
|
I think we're almost good to go. Please
|
MountedFast is a method of detecting mount points ie without reading /proc/mounts. It works for all kinds of mounts (incl. bind mounts) but requires a recent (v5.6+) Linux kernel. A mount-point check is guaranteed to be a mount-point or not only when sure is true. When sure is false, the caller needs to check for other methods (eg: parse /proc/mounts) to successfully determine if it is a mount-point. Signed-off-by: Manu Gupta <[email protected]>
5e7a91b to
fbde1ac
Compare
|
@kolyshkin Would you be able to have a final go and check it please? |
|
@kolyshkin could you help approve this? Thanks! |
|
I started to re-review this, and ended up fixing various nits myself. Please see #100 🙏🏻 |
|
This was carried in #100 and now merged, so closing this one thanks for contributing and reviewing, @manugupt1 ! |
MountedFast is a method of detecting mount points really fast.
It works for all kinds of mounts (incl. bind mounts) but requires
a recent (v5.6+) Linux kernel. A mount-point check is guaranteed to
be a mount-point or not only when sure is true. When sure is false,
the caller needs to check for other methods (eg: parse /proc/mounts)
to successfully determine if it is a mount-point.
This has been motivated by
kubernetes/kubernetes#105833 (comment)
and
#96 (comment)
Context
The context is that; k8s relies on reading /proc/mounts to determine mount points. It also enforces a consistency check (ie ensure that two reads of proc/mounts are exactly the same) before determining a mount-point which leads to resource contention. This is different than docker where a lock is acquired before reading the entire /proc/mounts.
Now, k8s wont remove the consistency check as it could lead to all sorts of error that Kir demonstrated here (https://github.com/kolyshkin/procfs-test) and the consistency check mitigates that.
To solve for that k8s took inspiration from moby/sys to do its own openat2 call (kubernetes/kubernetes#105833) and when openat2 is not available, fallback on reading /proc/mounts with the consistency check I mentioned above.
During the course of the discussion, Kir suggested it might be better to upstream the change to moby/sys and k8s can take it as a dependency which is what this PR does. It introduces a MountedFast which uses openat2 (for kernel 5.6+) or stat calls to determine a mount-point, it sends back a sure bool to the caller to guarantee the caller if it is a mount-point or not.
k8s will now first call MountedFast when this change is merged and then if sure is false or an error is thrown, it will fall back to reading /proc/mounts. This is beneficial for k8s on newer kernels as they will never read /proc/mounts because of openat2 path and for older kernels only bind mounts will be validated using /proc/mounts.