From: Shachar Sharon Date: Tue, 3 Sep 2024 13:54:03 +0000 (+0300) Subject: vfs_ceph_new: switch to ceph_readdir_r X-Git-Tag: samba-4.20.8~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8231235652671b59f504aa21cbf415a8d666396c;p=thirdparty%2Fsamba.git vfs_ceph_new: switch to ceph_readdir_r Prefer a safe version of ceph_readdir, where the directory entry struct is allocated by the caller. Use a dynamic-allocated 'struct dirent' which is associated with a directory vfs_ceph_fh (optional), which is allocated on-the-fly upon start of READDIR and released at the end or CLOSEDIR (or unlikely readdir error). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15703 Signed-off-by: Shachar Sharon Reviewed-by: John Mulligan Reviewed-by: Anoop C S Autobuild-User(master): Anoop C S Autobuild-Date(master): Fri Oct 25 10:29:44 UTC 2024 on atb-devel-224 (cherry picked from commit ce459ddbcd0f32252858a7640f6871057eb14645) --- diff --git a/source3/modules/vfs_ceph_new.c b/source3/modules/vfs_ceph_new.c index c7a7c2d3ab6..e5517a98298 100644 --- a/source3/modules/vfs_ceph_new.c +++ b/source3/modules/vfs_ceph_new.c @@ -157,6 +157,7 @@ struct vfs_ceph_config { CEPH_FN(ceph_version); CEPH_FN(ceph_readdir); CEPH_FN(ceph_rewinddir); + CEPH_FN(ceph_readdir_r); }; /* @@ -405,6 +406,7 @@ static bool vfs_cephfs_load_lib(struct vfs_ceph_config *config) CHECK_CEPH_FN(libhandle, ceph_version); CHECK_CEPH_FN(libhandle, ceph_readdir); CHECK_CEPH_FN(libhandle, ceph_rewinddir); + CHECK_CEPH_FN(libhandle, ceph_readdir_r); config->libhandle = libhandle; @@ -625,6 +627,7 @@ struct vfs_ceph_fh { struct vfs_ceph_config *config; struct vfs_ceph_iref iref; struct Fh *fh; + struct dirent *de; int fd; }; @@ -642,6 +645,22 @@ static int cephmount_next_fd(struct cephmount_cached *cme) return (int)next; } +static struct dirent *vfs_ceph_get_fh_dirent(struct vfs_ceph_fh *cfh) +{ + if (cfh->de == NULL) { + cfh->de = talloc_zero_size(cfh->fsp, sizeof(*(cfh->de))); + } + return cfh->de; +} + +static void vfs_ceph_put_fh_dirent(struct vfs_ceph_fh *cfh) +{ + if (cfh->de != NULL) { + TALLOC_FREE(cfh->de); + cfh->de = NULL; + } +} + static int vfs_ceph_release_fh(struct vfs_ceph_fh *cfh) { int ret = 0; @@ -661,6 +680,7 @@ static int vfs_ceph_release_fh(struct vfs_ceph_fh *cfh) vfs_ceph_userperm_del(cfh->config, cfh->uperm); cfh->uperm = NULL; } + vfs_ceph_put_fh_dirent(cfh); cfh->fd = -1; return ret; @@ -1167,18 +1187,20 @@ static int vfs_ceph_ll_opendir(const struct vfs_handle_struct *handle, cfh->uperm); } -static struct dirent *vfs_ceph_ll_readdir(const struct vfs_handle_struct *hndl, - const struct vfs_ceph_fh *dircfh) +static int vfs_ceph_ll_readdir(const struct vfs_handle_struct *hndl, + const struct vfs_ceph_fh *dircfh) { struct vfs_ceph_config *config = NULL; SMB_VFS_HANDLE_GET_DATA(hndl, config, struct vfs_ceph_config, - return NULL); + return -ENOMEM); DBG_DEBUG("[ceph] ceph_readdir: ino=%" PRIu64 " fd=%d\n", dircfh->iref.ino, dircfh->fd); - return config->ceph_readdir_fn(config->mount, dircfh->dirp.cdr); + return config->ceph_readdir_r_fn(config->mount, + dircfh->dirp.cdr, + dircfh->de); } static void vfs_ceph_ll_rewinddir(const struct vfs_handle_struct *handle, @@ -1959,21 +1981,35 @@ static struct dirent *vfs_ceph_readdir(struct vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp) { - const struct vfs_ceph_fh *dircfh = (const struct vfs_ceph_fh *)dirp; + struct vfs_ceph_fh *dircfh = (struct vfs_ceph_fh *)dirp; struct dirent *result = NULL; int saved_errno = errno; + int ret = -1; DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp); - errno = 0; - result = vfs_ceph_ll_readdir(handle, dircfh); - if ((result == NULL) && (errno != 0)) { - saved_errno = errno; - DBG_DEBUG("[CEPH] readdir(...) = %d\n", errno); + result = vfs_ceph_get_fh_dirent(dircfh); + if (result == NULL) { + /* Memory allocation failure */ + return NULL; + } + + /* The low-level call uses 'dircfh->de' which is now 'result' */ + ret = vfs_ceph_ll_readdir(handle, dircfh); + if (ret < 0) { + /* Error case */ + DBG_DEBUG("[CEPH] readdir(...) = %d\n", ret); + vfs_ceph_put_fh_dirent(dircfh); + result = NULL; + saved_errno = ret; + } else if (ret == 0) { + /* End of directory stream */ + vfs_ceph_put_fh_dirent(dircfh); + result = NULL; } else { + /* Normal case */ DBG_DEBUG("[CEPH] readdir(...) = %p\n", result); } - errno = saved_errno; return result; }