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-16924 dfs: new readdir API #15687

Open
wants to merge 1 commit into
base: feature/dfs_dcache
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion src/client/dfs/dcache.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2022-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -75,7 +76,7 @@ typedef void (*drec_decref_fn_t)(dfs_dcache_t *, dfs_obj_t *);
typedef void (*drec_del_at_fn_t)(dfs_dcache_t *, dfs_obj_t *);
typedef int (*drec_del_fn_t)(dfs_dcache_t *, char *, dfs_obj_t *);

/** DFS directory cache */
/** DFS dentry cache */
struct dfs_dcache {
/** Cached DAOS file system */
dfs_t *dd_dfs;
Expand Down Expand Up @@ -990,3 +991,6 @@ drec_del(dfs_dcache_t *dcache, char *path, dfs_obj_t *parent)

return dcache->drec_del_fn(dcache, path, parent);
}

// dcache_readdir(dfs_dcache_t *dcache, dfs_obj_t *obj, dfs_dir_anchor_t *anchor, struct dirent dir)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could be usefull to add some comments on why this function declaration is commented.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

since i plan to add it next :-)
note this is all going to the feature branch, so this is just the first piece of the puzzle

// {}
10 changes: 10 additions & 0 deletions src/client/dfs/dfs_internal.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2019-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -274,6 +275,15 @@ struct dfs_mnt_hdls {
int type;
};

/** readdir anchor for dfs_readdir2(). If dcache is disabled, the only valid setting is the
* daos_anchor_t. */
struct dfs_dir_anchor {
dfs_obj_t *dda_dir;
daos_anchor_t dda_anchor_int;
size_t dda_bucket_id;
off_t dda_bucket_offset;
};

static inline bool
tspec_gt(struct timespec l, struct timespec r)
{
Expand Down
74 changes: 74 additions & 0 deletions src/client/dfs/readdir.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2018-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand All @@ -9,6 +10,7 @@
#define D_LOGFAC DD_FAC(dfs)

#include <daos/common.h>
#include <daos/object.h>

#include "dfs_internal.h"

Expand Down Expand Up @@ -113,6 +115,78 @@ dfs_readdirplus(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr,
return readdir_int(dfs, obj, anchor, nr, dirs, stbufs);
}

int
dfs_dir_anchor_init(dfs_obj_t *obj, dfs_dir_anchor_t **_anchor)
{
dfs_dir_anchor_t *anchor;

if (obj == NULL || !S_ISDIR(obj->mode))
return ENOTDIR;

D_ALLOC_PTR(anchor);
if (anchor == NULL)
return ENOMEM;

anchor->dda_dir = obj;
daos_anchor_init(&anchor->dda_anchor_int, 0);
anchor->dda_bucket_id = 0;
anchor->dda_bucket_offset = 0;
*_anchor = anchor;
return 0;
}

void
dfs_dir_anchor_reset(dfs_dir_anchor_t *anchor)
{
daos_anchor_init(&anchor->dda_anchor_int, 0);
anchor->dda_bucket_id = 0;
anchor->dda_bucket_offset = 0;
}

bool
dfs_dir_anchor_is_eof(dfs_dir_anchor_t *anchor)
{
return daos_anchor_is_eof(&anchor->dda_anchor_int);
}

void
dfs_dir_anchor_destroy(dfs_dir_anchor_t *anchor)
{
D_FREE(anchor);
}

int
dfs_readdir_s(dfs_t *dfs, dfs_obj_t *dir, dfs_dir_anchor_t *anchor, struct dirent *entry)
{
uint32_t nr = 1;
int rc;

if (daos_oid_cmp(dir->oid, anchor->dda_dir->oid) != 0)
return EINVAL;
if (daos_anchor_is_eof(&anchor->dda_anchor_int))
return -1;

rc = readdir_int(dfs, dir, &anchor->dda_anchor_int, &nr, entry, NULL);
if (rc)
return rc;

/** if we did not enumerate anything, try again to make sure we hit EOF */
if (nr == 0) {
if (daos_anchor_is_eof(&anchor->dda_anchor_int))
return -1; /** typically EOF code */
Copy link
Contributor

@knard38 knard38 Jan 15, 2025

Choose a reason for hiding this comment

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

Probably a stupid question but why not using EOF macro directly ?

Suggested change
return -1; /** typically EOF code */
return EOF;

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 can make that change in the follow on PR. i just wasn't sure if EOF was -1 on all linux platforms

else
return EIO;
}
return rc;
#if 0
/** if no caching, just use the internal anchor with 1 entry */
if (dfs->dcache == NULL)
return readdir_int(dfs, obj, &anchor->dda_anchor_int, 1, &dir, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

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

dir --> entry?

else
dcache_readdir(dfs->dcache, obj, anchor, dir);
Copy link
Contributor

Choose a reason for hiding this comment

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

dir --> entry?
You can update it in future PR since the code is currently commented out.

#endif
}

int
dfs_iterate(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr, size_t size,
dfs_filler_cb_t op, void *udata)
Expand Down
73 changes: 73 additions & 0 deletions src/include/daos_fs.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* (C) Copyright 2018-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -47,6 +48,8 @@ extern "C" {
typedef struct dfs_obj dfs_obj_t;
/** DFS mount handle struct */
typedef struct dfs dfs_t;
/** DFS readdir anchor for dfs_readdir_s() */
typedef struct dfs_dir_anchor dfs_dir_anchor_t;

/*
* Consistency modes of the DFS container. A container created with balanced
Expand Down Expand Up @@ -741,6 +744,76 @@ int
dfs_readdirplus(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr,
struct dirent *dirs, struct stat *stbufs);

/**
* Initialize a readdir anchor for dfs_readdir_s().
*
* \param[in] dir Opened directory object for readdir.
* \param[out] anchor Pointer to initialized anchor. This muse be freed with
* dfs_dir_anchor_destroy().
*
* \return 0 on success, errno code on failure.
*/
int
dfs_dir_anchor_init(dfs_obj_t *dir, dfs_dir_anchor_t **anchor);

/**
* Reset an anchor the beginning of dir stream.
*
* \param[in] anchor anchor to reset
*
*/
void
dfs_dir_anchor_reset(dfs_dir_anchor_t *anchor);

/**
* check if the anchor is at EOF.
*
* \param[in] anchor anchor to check
*
* \return true if anchor is at EOF, false otherwise.
*/
bool
dfs_dir_anchor_is_eof(dfs_dir_anchor_t *anchor);

/**
* Destroy/free a DFS readdir anchor.
*
* \param[in] anchor anchor to free
*
*/
void
dfs_dir_anchor_destroy(dfs_dir_anchor_t *anchor);

/**
* Directory readdir that just returns the next entry in the directory anchor stream. The stream is
* actually determined by the anchor which can be reset at anytime to start from the beginning. For
* every call of this function with the anchor, it returns 0 with the d_name of the dirent struct
* populated for the next entry. The function returns -1 if it reaches the end of stream and sets
* anchor to EOF. It is possible to get the last entry in the stream and the anchor being set to EOF
* in that call. It is also possible to get the last entry in the stream and the anchor still not
* set to EOF in that readdir call. In both situations the return code of the readdir call is 0
* (success) and the entry is valid and should be consumed. In the latter case, the caller does not
* know that we reached the end of the directory and should make another readdir call. The next call
* in both scenarios will return -1 and the anchor will be set to EOF in that call. Further calls
* will behave similarly until the anchor is reset to the beginning.
*
* If caching is enabled on this dfs mount, this readdir call will utilize the readdir cache and may
* pull in an entire bucket of entries at once if the current stream is not in the cache.
*
* \param[in] dfs Pointer to the mounted file system.
* \param[in] obj Opened directory object.
* \param[in,out]
* anchor Anchor for the next call, it should initialized before first use.
* \param[out] dir returned dirent. Unlike the libc call, this dirent pointer is provided by
* the caller and not an internal pointer.
*
* \return 0 on success
* -1 on end of dir stream (no more entries to enumerate)
* errno code on failure
*/
int
dfs_readdir_s(dfs_t *dfs, dfs_obj_t *obj, dfs_dir_anchor_t *anchor, struct dirent *dir);

/**
* User callback defined for dfs_readdir_size.
*/
Expand Down
Loading
Loading