Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DAOS-14149 client: add compatible mode for libpil4dfs #13294

Merged
merged 48 commits into from
Apr 29, 2024
Merged

Conversation

wiliamhuang
Copy link
Contributor

@wiliamhuang wiliamhuang commented Nov 5, 2023

Regular mode of the interception library libpil4dfs uses fake file descriptors (fd) allocated in user space. In case of some libc functions are not intercepted, applications could get error even crash due to fake fd. Compatibility mode is introduced to alleviate such issues and increase compatibility. open, openat, and opendir etc rely on dfuse to get real fd from dfuse and return them to applications with better compatibility and degraded performance.
Environmental variable "D_IL_COMPATIBLE=1" turns on compatible mode. Regular mode is set as default if "D_IL_COMPATIBLE" is unset.

Required-githooks: true

Before requesting gatekeeper:

  • Two review approvals and any prior change requests have been resolved.
  • Testing is complete and all tests passed or there is a reason documented in the PR why it should be force landed and forced-landing tag is set.
  • Features: (or Test-tag*) commit pragma was used or there is a reason documented that there are no appropriate tags for this PR.
  • Commit messages follows the guidelines outlined here.
  • Any tests skipped by the ticket being addressed have been run and passed in the PR.

Gatekeeper:

  • You are the appropriate gatekeeper to be landing the patch.
  • The PR has 2 reviews by people familiar with the code, including appropriate watchers.
  • Githooks were used. If not, request that user install them and check copyright dates.
  • Checkpatch issues are resolved. Pay particular attention to ones that will show up on future PRs.
  • All builds have passed. Check non-required builds for any new compiler warnings.
  • Sufficient testing is done. Check feature pragmas and test tags and that tests skipped for the ticket are run and now pass with the changes.
  • If applicable, the PR has addressed any potential version compatibility issues.
  • Check the target branch. If it is master branch, should the PR go to a feature branch? If it is a release branch, does it have merge approval in the JIRA ticket.
  • Extra checks if forced landing is requested
    • Review comments are sufficiently resolved, particularly by prior reviewers that requested changes.
    • No new NLT or valgrind warnings. Check the classic view.
    • Quick-build or Quick-functional is not used.
  • Fix the commit message upon landing. Check the standard here. Edit it to create a single commit. If necessary, ask submitter for a new summary.

Test-tag: pil4dfs

avoid using fake fd to get better compatibility with degraded
performance in open and opendir etc.

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Copy link

github-actions bot commented Nov 5, 2023

Bug-tracker data:
Ticket title is 'To implement a compatible mode in libpil4dfs for better compatibility'
Status is 'In Progress'
Labels: 'intercept_lib'
https://daosio.atlassian.net/browse/DAOS-14149

Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

Test-tag: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Test-tag: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Features: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

Features: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

Features: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
@daosbuild1
Copy link
Collaborator

Test stage Unit Test bdev on EL 8 completed with status FAILURE. https://build.hpdd.intel.com/job/daos-stack/job/daos/job/PR-13294/5/display/redirect

@daosbuild1
Copy link
Collaborator

Test stage NLT on EL 8 completed with status FAILURE. https://build.hpdd.intel.com/job/daos-stack/job/daos/job/PR-13294/5/display/redirect

Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

Features: pil4dfs

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Copy link
Collaborator

@daosbuild1 daosbuild1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. No errors found by checkpatch.

@wiliamhuang wiliamhuang marked this pull request as ready for review November 17, 2023 14:01
@wiliamhuang wiliamhuang requested review from a team as code owners November 17, 2023 14:01
@wiliamhuang
Copy link
Contributor Author

We may need a separate ticket and PR for more tests.

if (rc != 0) {
rc = errno;
if (rc != ENOTTY)
DS_WARN(rc, "ioctl call on %d failed", fd);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of those sounds like legitimate errors and not warnings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even fetch_dfs_cont_file_obj_with_fd() failed, open() still can return the fd allocated by kernel. If you think error is more appropriate here, I can change it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a question to you..
Warning messages should be used when something that the user is expecting but another path was taken and the operation is still onging / succeeds.
Error messages are for when we get legitimate errors from DAOS that something went wrong like EIO, etc.
otherwise, like if user is opening a non-existent file, this is more of a debug message that can be logged at the DAOS log level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I will change this and several other warnings in this function to debug message. Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably print the errno (or string version of it here), no? (applies to subsequent messages).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DS_WARN does print errno and string version message.
fetch_dfs_cont_file_obj_with_fd() is called inside open. When it is called, we already get fd from dfuse without issue. Even fetch_dfs_cont_file_obj_with_fd fails, we still return fd allocated by dfuse. I think warning is appropriate here.

@@ -850,6 +979,13 @@ retrieve_handles_from_fuse(int idx)
errno_saved, strerror(errno_saved));
goto err;
}
rc = dc_cont_hdl2uuid(dfs_list[idx].coh, NULL, &dfs_list[idx].uuid_cont);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally we don't want to use internal functions like these here. is this for the UNS support?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I can remove this for now. It is not for UNS support. I just used the container uuid to double check the container uuid returned by ioctl(fd, DFUSE_IOCTL_IL, &il_reply).

@@ -212,3 +212,18 @@ def test_bashcmd_pil4dfs(self):
:avocado: tags=Cmd,test_bashcmd_pil4dfs
"""
self.run_bashcmd(il_lib="libpil4dfs.so")

def test_bashcmd_pil4dfs_compatible(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to add some more testing for the most common use cases that we know are not supported currently that will be with compatibility mode.


rc = dfs_get_mode(dfs_obj_local, &mode_query);
if (rc)
goto out_compatible;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to close dfs_obj_local?
error ignored?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. "dfs_obj_local" should be closed. I will add a debug message when dfs_get_mode() fails. Thank you!

src/client/dfuse/pil4dfs/int_dfs.c Show resolved Hide resolved
src/client/dfuse/pil4dfs/int_dfs.c Show resolved Hide resolved
@daosbuild1
Copy link
Collaborator

Test stage Functional Hardware Medium Verbs Provider completed with status FAILURE. https://build.hpdd.intel.com//job/daos-stack/job/daos/view/change-requests/job/PR-13294/7/execution/node/1511/log

Copy link
Contributor

@jolivier23 jolivier23 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was chatting with Johann last week and he had an interesting idea.

If we have a special file, let's say .fd_alloc, where dfuse does nothing but just allow the kernel to create a new file descriptor, then we can use ioctl to map that file descriptor to our real dfs file. Then we have a real file descriptor to return to the application. If we ever encounter a situation that is difficult to implement at least in the near term (e.g. mmap), we can simply disable interception and defer back to dfuse which now knows the mapping between the fd and the dfs file.

so open handling would be something like
Open the dfs file
If not successful
return

fd = real_open("/path/to/dfuse/.fd_alloc", ...);
ioctl(fd, DFUSE_MAP_FILE, ....);
save mapping from fd to dfs_obj
return fd;

if (rc != 0) {
rc = errno;
if (rc != ENOTTY)
DS_WARN(rc, "ioctl call on %d failed", fd);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably print the errno (or string version of it here), no? (applies to subsequent messages).

@@ -974,6 +974,10 @@ libpil4dfs intercepting summary for ops on DFS:
[op_sum ] 5003
```

### Turn on compatible mode in libpil4dfs

"D_IL_COMPATIBLE=1" or "D_IL_COMPATIBLE=true" turns on compatible mode. Fake fd will not be returned to applications. This mode provides better compatibility with degraded performance in open, openat, and opendir, etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue this should be the default setting and the performant version should be a use at your own risk option. Though I think we can probably make this better if we do something like opening the special fake file on the actual fuse mountpoint to avoid lookup calls and maybe acceptable enough that we don't even need this environment variable at all.

Anyway, my reasoning here is that people will not care about a small bump in performance if it means half of their applications don't run at all. I don't think open is as big of a bottleneck as many other metadata ops

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I can set compatible mode as default in next commit. Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure i agree actually. I do not think the performance effect is small but can be quite substantial in metadata heavy cases.
ideally these use cases should be found and eventually resolved. if we set this as the default, im afraid we are going to get not reports of new issues found, and more importantly have performance issues.

Copy link
Contributor

@jolivier23 jolivier23 Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we move to fake file method, perf difference will be minimal, IMO. The issue with the current version, is it will cause a bunch of lookups for items in path whereas a fake file will minimize that churn.

The main issue I have with not being compatible by default, is that it may take significant cycles for someone to discover this and their first experience will be that DAOS doesn't work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this to Ashley and he had an even better idea, IMO. If you allocate a bunch of these at startup, you can just keep a cache of such kernel allocated file descriptors and assign them to real files as needed.

Signed-off-by: Lei Huang <lei.huang@intel.com>
Test-provider-hw-medium: ofi+tcp;ofi_rxm
Priority: 2

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
@wiliamhuang wiliamhuang requested a review from a team as a code owner March 17, 2024 04:13
@wiliamhuang
Copy link
Contributor Author

A test case for a shell script that calls if [ -d <dir> ] and then calls mkdir as a subprocess and checks for the dir again would be good. For the case we're discussing I guess you'd have to create the dir, test for it using -d, then delete it and test for it again with -d, with caching on the second -d test should get the wrong result but with disabling the caching for bash processes then it should correctly detect the dir is missing.

Thank you! Since dir caching now is automatically disabled inside bash, I plan to add such test in unit test. src/tests/ftest/dfuse/utest/pil4dfs_dcache.c

Could you write one in bash so it's closer to the case you're testing for.

ok. I will test it in bash then. I also need to expose an env to enable/disable auto-disabling dir caching in bash.

@daosbuild1
Copy link
Collaborator

Test stage Functional Hardware Medium Verbs Provider completed with status UNSTABLE. https://build.hpdd.intel.com/job/daos-stack/job/daos//view/change-requests/job/PR-13294/43/testReport/

@wiliamhuang
Copy link
Contributor Author

All CI tests passed except one failure. It was reported in ticket, https://daosio.atlassian.net/issues/DAOS-15662.
I am preparing the ftest Ashley suggested. I will update soon.

2. add a test to create dir and file, then remove them and recreate them.

Priority: 2
Test-tag: test_bashdcache_pil4dfs
Skip-unit-tests: true

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
SConstruct Outdated
@@ -363,7 +363,8 @@ MINIMAL_ENV = ('HOME', 'TERM', 'SSH_AUTH_SOCK', 'http_proxy', 'https_proxy', 'PK

# Environment variables that are also kept when LD_PRELOAD is set.
PRELOAD_ENV = ('LD_PRELOAD', 'D_LOG_FILE', 'DAOS_AGENT_DRPC_DIR', 'D_LOG_MASK', 'DD_MASK',
'DD_SUBSYS', 'D_IL_MAX_EQ', 'D_IL_ENFORCE_EXEC_ENV', 'D_IL_COMPATIBLE')
'DD_SUBSYS', 'D_IL_MAX_EQ', 'D_IL_ENFORCE_EXEC_ENV', 'D_IL_COMPATIBLE',
'D_IL_NO_DCACHE_BASH')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im going to object on adding more env variables like this.. it's counter productive for users and hard to keep track of. if we know this has issues, then why we need a flag to enable it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about if compatible mode is on, dcache in bash is disabled.
otherwise it's enabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option would be to have a D_IL_NO_CACHE_EXE and have it be a comma separated list of process named with the default being sh,bash, that way the default would work and not need a hack in this file and there would be the option to enable/disable it for other procs as needed.

This shouldn't hold up the PR from landing however, the previous code is good enough to pass the test and land the PR IMO and we should improve this in a follow up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I can add an env "D_IL_NO_CACHE_EXE" to support user supplied app list in a follow up PR.
I think we should disable dcahe in bash in regular mode too. bash is not sensitive to performance. Disabling cache can avoid possible consistency issue.

@wiliamhuang
Copy link
Contributor Author

@ashleypittman Shall I remove "'git -C {} checkout lei/DAOS-14149'.format(build_dir)," in src/tests/ftest/dfuse/daos_build.py now?

2. fix tags in test_bashdcache_pil4dfs

Priority: 2
Test-tag: test_bashdcache_pil4dfs
Skip-unit-tests: true

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Features: pil4dfs
Priority: 2

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
@wiliamhuang
Copy link
Contributor Author

mchaarawi
mchaarawi previously approved these changes Apr 25, 2024


class DFuseBashdcacheTest(DfuseTestBase):
"""Base Bashdcache test class.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to resolve or silence these warnings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to fix this in last commit. I will add "Bashdcache" into utils/cq/words.dict after current build completes. Thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added "#pylint: disable-next=wrong-spelling-in-docstring" to suppress the warning. Thank you!

src/tests/ftest/dfuse/bash_dcache.py Outdated Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Outdated Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
src/tests/ftest/dfuse/bash_dcache.py Outdated Show resolved Hide resolved
Comment on lines +60 to +62
result = run_remote(self.log, self.hostlist_clients, env_str + cmd)
if not result.passed:
self.fail(f'"{cmd}" failed on {result.failed_hosts}')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check the output?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated as you suggested. Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checks the output but both files have the same contents so it's not checking as much as it could.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I can write difference content for the second write. Will update it in another PR. Thank you!

src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
Features: pil4dfs
Priority: 2

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
@daosbuild1
Copy link
Collaborator

Test stage Functional on EL 8.8 completed with status FAILURE. https://build.hpdd.intel.com/job/daos-stack/job/daos/job/PR-13294/46/display/redirect

@wiliamhuang
Copy link
Contributor Author

A few minor lint related changes will be needed after current build is finished.

wrong-spelling-in-docstring, Wrong spelling of a word 'Bashdcache' in a docstring:
wrong-spelling-in-docstring, Wrong spelling of a word 'conftest' in a docstring:
superfluous-parens, Unnecessary parens after 'if' keyword
wrong-spelling-in-comment, Wrong spelling of a word 'dcache' in a comment:

@ashleypittman Is there anything else we should change? Thank you!

@wiliamhuang
Copy link
Contributor Author

wiliamhuang commented Apr 26, 2024

@ashleypittman All tests finished in CI without issue in build 49 https://build.hpdd.intel.com/job/daos-stack/job/daos/job/PR-13294/49/. Any more comments? I will push another commit to fix pylint related issue soon. Thank you!

Priority: 2
Test-tag: test_bash_dcache_pil4dfs
Skip-unit-tests: true

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Priority: 2
Test-tag: test_bash_dcache_pil4dfs
Skip-unit-tests: true

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
Priority: 2
Test-tag: test_bash_dcache_pil4dfs
Skip-unit-tests: true

Required-githooks: true

Signed-off-by: Lei Huang <lei.huang@intel.com>
@wiliamhuang
Copy link
Contributor Author

@ashleypittman @mchaarawi Do you have more feedback? Thank you!

Comment on lines +60 to +62
result = run_remote(self.log, self.hostlist_clients, env_str + cmd)
if not result.passed:
self.fail(f'"{cmd}" failed on {result.failed_hosts}')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checks the output but both files have the same contents so it's not checking as much as it could.

src/tests/ftest/dfuse/bash_dcache.py Show resolved Hide resolved
:avocado: tags=daosio,dfuse,il,dfs,pil4dfs
:avocado: tags=DaosBuild,test_dfuse_daos_build_wt_pil4dfs
"""
self.run_build_test("nocache", il_lib='libpil4dfs.so', run_on_vms=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this doesn't work with anything other than nocache as dfuse would cache negative dentries and then lots of things would fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. That's what I found in local test.

@wiliamhuang wiliamhuang requested a review from a team April 29, 2024 15:47
@mchaarawi mchaarawi merged commit 8511455 into master Apr 29, 2024
44 of 45 checks passed
@mchaarawi mchaarawi deleted the lei/DAOS-14149 branch April 29, 2024 16:02
@mjmac mjmac mentioned this pull request Apr 30, 2024
mjmac pushed a commit that referenced this pull request Apr 30, 2024
Regular mode of the interception library (libpil4dfs) uses fake file descriptors (fd) allocated in user space. In case of some libc functions are not intercepted, applications could get errors or even crash due to the fake fd. Compatibility mode is introduced to alleviate such issues and increase compatibility. open, openat, and opendir etc rely on dfuse to get real fd from dfuse and return them to applications with better compatibility but with some degraded performance.
Environmental variable "D_IL_COMPATIBLE=1" turns on compatible mode. Regular mode is set as default if "D_IL_COMPATIBLE" is unset.

Signed-off-by: Lei Huang <lei.huang@intel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants