Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ pipeline {
inst_repos: daosRepos(),
test_script: 'ci/unit/test_nlt.sh' +
' --system-ram-reserved 4' +
' --max-log-size 1950MiB' +
' --max-log-size 2500MiB' +
' --dfuse-dir /localhome/jenkins/' +
' --log-usage-save nltir.xml' +
' --log-usage-export nltr.json' +
Expand Down
20 changes: 20 additions & 0 deletions docs/user/filesystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,20 @@ The following types of data will be cached by default.
applications to fail. Please disable caching (--disable-caching option) if
you experience this or want up to date data sharing between nodes.

!!! warning
I/O issued through an interception library (`libioil` or `libpil4dfs`) goes
directly to DAOS and is not seen by dfuse, so dfuse cannot invalidate cached
file data for handles that are already open through dfuse. With data caching
enabled, such handles, in the same or another process, may return stale data
for ranges written through the interception library until they are closed.
While a file is open for writing through `libioil`, dfuse disables attribute
caching for it, so file sizes stay correct. `libpil4dfs` does not notify dfuse
per file, so attributes such as the file size may also be stale for up to the
attribute timeout. If the same files are accessed both through an
interception library and directly through dfuse, disable data caching
(`dfuse-data-cache` set to off) when using `libioil`, and disable all caching
(`--disable-caching`) when using `libpil4dfs`.

To selectively control caching within a container the following container
attributes should be used, if any attribute is set then the rest are assumed
to be set to 0 or off, except dentry-dir-time which defaults to dentry-time
Expand Down Expand Up @@ -820,6 +834,9 @@ $ LD_PRELOAD=/usr/lib64/libioil.so dd if=/dev/zero of=./bar bs=1G count=20
Alternatively, it's possible to simply link the interception library into the application
at compile time with the `-lioil` flag.

See the [Caching](#caching) section for consistency limits when files written through `libioil`
are also accessed through dfuse with data caching enabled.

### Monitoring Activity

The interception library is intended to be transparent to the user, and no other
Expand Down Expand Up @@ -969,6 +986,9 @@ Example:
$ LD_PRELOAD=/usr/lib64/libpil4dfs.so mdtest -a POSIX -z 0 -F -C -i 1 -n 1667 -e 4096 -d /scratch_fs/dfuse/ -w 4096
```

See the [Caching](#caching) section for consistency limits when files written through
`libpil4dfs` are also accessed through dfuse with caching enabled.

### Using libpil4dfs without dfuse

When no dfuse mountpoint is specified, several environment variables must be set to
Expand Down
25 changes: 22 additions & 3 deletions src/client/dfuse/dfuse.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* (C) Copyright 2016-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
* (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -550,6 +550,13 @@ struct dfuse_cont {
bool dfc_save_ino;
};

/* True if any handle on this container can use the page cache, chunk reads or zero-fill reads */
static inline bool
dfuse_cont_data_caching(struct dfuse_cont *dfc)
{
return dfc->dfc_data_timeout != 0 || dfc->dfc_data_otoc || dfc->dfc_direct_io_disable;
}

#define dfs_entry core.dfcc_entry
#define dfc_uuid core.dfcc_uuid
#define dfs_ino core.dfcc_ino
Expand Down Expand Up @@ -979,7 +986,7 @@ struct dfuse_inode_entry {
/* Time of last kernel cache data update, also used for kernel readdir caching. */
struct timespec ie_dcache_last_update;

/** written region for truncated files (i.e. ie_truncated set) */
/** Written region for truncated files, protected by ie_active->lock while open. */
size_t ie_start_off;
size_t ie_end_off;

Expand All @@ -997,7 +1004,7 @@ struct dfuse_inode_entry {
/* Readdir handle, if present. May be shared */
struct dfuse_readdir_hdl *ie_rd_hdl;

/** file was truncated from 0 to a certain size */
/** File was truncated from 0 to a certain size; protected by ie_active->lock while open. */
bool ie_truncated;

/** file is the root of a container */
Expand Down Expand Up @@ -1027,6 +1034,10 @@ struct active_inode {
d_list_t chunks;
pthread_spinlock_t lock;
struct dfuse_pre_read *readahead;
/* Local mutations disable cached EOF and pre-read replies.
* Remains set until the last handle closes.
*/
ATOMIC bool read_cache_invalidated;
};

/* Increase active count on inode. This takes a reference and allocates ie->active as required */
Expand All @@ -1041,6 +1052,10 @@ active_oh_decref(struct dfuse_info *dfuse_info, struct dfuse_obj_hdl *oh);
void
active_ie_decref(struct dfuse_info *dfuse_info, struct dfuse_inode_entry *ie);

/* Reset chunk and synthetic-zero read state for an inode which may have no open handle. */
void
active_ie_set_truncated(struct dfuse_inode_entry *ie, bool truncated);

/* Flush write-back cache writes to a inode. It does this by waiting for and then releasing an
* exclusive lock on the inode. Writes take a shared lock so this will block until all pending
* writes are complete.
Expand Down Expand Up @@ -1143,6 +1158,10 @@ dfuse_cache_evict_dir(struct dfuse_info *dfuse_info, struct dfuse_inode_entry *i
bool
read_chunk_close(struct dfuse_inode_entry *ie);

/* Drop cached chunk-read data overlapping [position, position + len). */
void
read_chunk_invalidate(struct dfuse_inode_entry *ie, off_t position, size_t len);

/* Metadata caching functions. */

/* Mark the cache as up-to-date from now */
Expand Down
18 changes: 18 additions & 0 deletions src/client/dfuse/file.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2024 Intel Corporation.
* (C) Copyright 2026 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -124,3 +125,20 @@ active_ie_decref(struct dfuse_info *dfuse_info, struct dfuse_inode_entry *ie)
out:
D_MUTEX_UNLOCK(&alock);
}

/* Reset read state after truncate, including for an inode with no open handle. */
void
active_ie_set_truncated(struct dfuse_inode_entry *ie, bool truncated)
{
D_MUTEX_LOCK(&alock);
if (ie->ie_active) {
read_chunk_invalidate(ie, 0, DFS_MAX_FSIZE);
D_SPIN_LOCK(&ie->ie_active->lock);
}
ie->ie_truncated = truncated;
ie->ie_start_off = 0;
ie->ie_end_off = 0;
if (ie->ie_active)
D_SPIN_UNLOCK(&ie->ie_active->lock);
D_MUTEX_UNLOCK(&alock);
}
1 change: 1 addition & 0 deletions src/client/dfuse/ops/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ dfuse_cb_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
rc = dfs_punch(ie->ie_dfs->dfs_ns, ie->ie_obj, 0, DFS_MAX_FSIZE);
if (rc)
D_GOTO(decref, rc);
read_chunk_invalidate(ie, 0, DFS_MAX_FSIZE);
dfuse_dcache_evict(oh->doh_ie);
}

Expand Down
Loading
Loading