The branch, v4-22-test has been updated via bf440caab97 vfs_ceph_new: Do not resolve by inode number via d26177dcaeb vfs_ceph_new: Handle absolute path in vfs_ceph_ll_walk via 8b38092890d vfs_ceph_new: Remove unused code in cephmount_mount_fs() via 4e9eb916024 vfs_ceph_new: Remove redundant re-intialization to NULL via 6ca80fb612b vfs_ceph_new: use libcephfs nonblocking API for async-io ops via f8f85cf8533 s3:utils: Remove call of ads_startup() from net_ads_keytab_create() via 83c60df6e8d s3:libads: Make sure that REALM is always added to keytab principals via 3849e7abe6d lib:krb5_wrap: Add smb_krb5_parse_name_flags() from 0e864939620 VERSION: Bump version up to Samba 4.22.1...
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-22-test - Log ----------------------------------------------------------------- commit bf440caab97778ae6ce312d4905585abe277884c Author: Anoop C S <anoo...@samba.org> Date: Tue Feb 25 17:40:13 2025 +0530 vfs_ceph_new: Do not resolve by inode number CephFS snapshots within snap directory shares the same inode number from its parent. Until unless we resolve by name we may incorrectly point at an inode which is not a snapshot directory. Therefore to be functionally correct we avoid resolving by inode number but proper name. For example: path (ino = 3) | --- dir (ino = 4) | --- .snap (ino = 3) | --- snap1 (ino = 3) | --- dir (ino = 4) In this case an attempt to resolve 'snap1' by inode number 3 results in pointing at 'path' which is not the desired outcome. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15818 Signed-off-by: Anoop C S <anoo...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> Autobuild-User(master): Günther Deschner <g...@samba.org> Autobuild-Date(master): Fri Mar 7 18:20:47 UTC 2025 on atb-devel-224 (cherry picked from commit a96f0542c8317a7dd0470b32350de6893fd98723) Autobuild-User(v4-22-test): Jule Anger <jan...@samba.org> Autobuild-Date(v4-22-test): Thu Mar 13 17:06:25 UTC 2025 on atb-devel-224 commit d26177dcaeb757e01a480ebd7a7a9dd7528ddbad Author: Anoop C S <anoo...@samba.org> Date: Mon Feb 24 14:00:56 2025 +0530 vfs_ceph_new: Handle absolute path in vfs_ceph_ll_walk It can very well be the case that the incoming path is absolute in nature which breaks the assumption inside vfs_ceph_ll_walk that it is within the current working directory. Instead perform a check to see whether the path includes current working directory path in its components and accordingly trim it to make it relative in nature. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15818 Signed-off-by: Anoop C S <anoo...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> (cherry picked from commit 9341d7fb466c95ea5aa0643049ce2a1f4183b9d0) commit 8b38092890dc18183ed3190e6731f4a21d341d9e Author: Anoop C S <anoo...@samba.org> Date: Mon Feb 24 12:09:06 2025 +0530 vfs_ceph_new: Remove unused code in cephmount_mount_fs() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15818 Signed-off-by: Anoop C S <anoo...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> (cherry picked from commit ee1c3e1db9a2d12ba6d9dd24faccf0020b1daf0d) commit 4e9eb916024a61fdebb3aedd10e972ac957cc8c1 Author: Anoop C S <anoo...@samba.org> Date: Mon Feb 24 11:54:45 2025 +0530 vfs_ceph_new: Remove redundant re-intialization to NULL TALLOC_FREE() by default re-initializes the pointer to NULL after corresponding memory is freed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15818 Signed-off-by: Anoop C S <anoo...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> (cherry picked from commit c5ddd94a08503a52914ce351ebf1083178e8c8bc) commit 6ca80fb612b461c21897ee5e868395da381276dc Author: Shachar Sharon <ssha...@redhat.com> Date: Tue Oct 1 12:09:40 2024 +0300 vfs_ceph_new: use libcephfs nonblocking API for async-io ops Use libcephfs non-blocking API (ceph_ll_nonblocking_readv_writev[1]) in combination with smb VFS async hooks ({pread,pwrite,fsync}_send/_recv). Fills libcephfs' struct ceph_ll_io_info with single iovec and submit/complete the operation asynchronously on libcephfs side, with corresponding tevent schedule-immediate upon completion on smbd side. Control nonblocking/normal I/O mode via config parameter. The common parts of async I/O (with/without HAVE_CEPH_ASYNCIO) are united. Specifically, use same struct vfs_ceph_aio_state and common code via helper function for all async I/O hooks. When HAVE_CEPH_ASYNCIO is True _and_ config option 'asyncio = yes' use libcephfs asynchronous I/O API. Otherwise, fake async operation using normal blocking APIs. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15810 [1] https://github.com/ceph/ceph/commit/b4e39f3eccd6734f1ed13c700c136e3aef1777f8 Signed-off-by: Shachar Sharon <ssha...@redhat.com> Reviewed-by: Ralph Boehme <s...@samba.org> Reviewed-by: Volker Lendecke <v...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> Autobuild-User(master): Günther Deschner <g...@samba.org> Autobuild-Date(master): Tue Mar 4 16:53:21 UTC 2025 on atb-devel-224 (cherry picked from commit 4ae9224138449fe7b8dd1e8ce8141aedd014efc4) commit f8f85cf8533824e0c3fae7e4cac363c692f249c5 Author: Pavel Filipenský <pfilipen...@samba.org> Date: Thu Mar 6 15:24:05 2025 +0100 s3:utils: Remove call of ads_startup() from net_ads_keytab_create() Calling ads_startup() is not needed in net_ads_keytab_create. Keytab creation code in sync_pw2keytabs() decides if it needs to talk to DC or not and connects to AD accordingly. Fixing this, makes the bug below easier to reproduce using 'net ads keytab create'. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15727 Signed-off-by: Pavel Filipenský <pfilipen...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> Autobuild-User(master): Pavel Filipensky <pfilipen...@samba.org> Autobuild-Date(master): Mon Mar 10 11:09:29 UTC 2025 on atb-devel-224 (cherry picked from commit 5cadaf91bc96cd2a8e0f6bcbd8a212e86b714180) commit 83c60df6e8dd604c4954e1b444b8d2332dbff62b Author: Pavel Filipenský <pfilipen...@samba.org> Date: Fri Mar 7 10:32:40 2025 +0100 s3:libads: Make sure that REALM is always added to keytab principals The code responsible for adding SPNs to keytab should always set the REALM part. Current code is not adding it for e.g. SPNs synced from AD. If REALM is missing, krb5_parse_name() will succeed (and add the REALM) only if the krb5.conf contains libdefaults section with default_realm set and will fail otherwise. E.g.: [libdefaults] default_realm = SOMETESTDOMAIN1.MY.COM When calling 'net ads join' we get the following error if SPN is missing REALM and krb5.conf does not provide the default_realm: pw2kt_process_add_info: Failed to parse principal: RestrictedKrbHost/$MACHINE_NAME Failed to join domain: failed to create kerberos keytab BUG: https://bugzilla.samba.org/show_bug.cgi?id=15727 Pair-Programmed-With: Noel Power <noel.po...@suse.com> Signed-off-by: Pavel Filipenský <pfilipen...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Alexander Bokovoy <a...@samba.org> Autobuild-User(master): Pavel Filipensky <pfilipen...@samba.org> Autobuild-Date(master): Sun Mar 9 00:25:08 UTC 2025 on atb-devel-224 (cherry picked from commit c72554260c950d0ef7652955a59f0f68a026f4f2) commit 3849e7abe6d7b1724ae6ab285e25c22086525d3f Author: Pavel Filipenský <pfilipen...@samba.org> Date: Thu Mar 6 23:20:53 2025 +0100 lib:krb5_wrap: Add smb_krb5_parse_name_flags() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15727 Signed-off-by: Pavel Filipenský <pfilipen...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Alexander Bokovoy <a...@samba.org> (cherry picked from commit cf34645050df64d6b8c4fa45394c3feebe691e79) ----------------------------------------------------------------------- Summary of changes: lib/krb5_wrap/krb5_samba.c | 39 ++- lib/krb5_wrap/krb5_samba.h | 5 + source3/libads/kerberos_keytab.c | 19 +- source3/modules/vfs_ceph_new.c | 577 ++++++++++++++++++++++++++------------- source3/utils/net_ads.c | 11 - source3/wscript | 4 + 6 files changed, 451 insertions(+), 204 deletions(-) Changeset truncated at 500 lines: diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 451616c79e5..0a4a7ea986f 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -836,6 +836,29 @@ krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context, krb5_error_code smb_krb5_parse_name(krb5_context context, const char *name, krb5_principal *principal) +{ + return smb_krb5_parse_name_flags(context, name, 0, principal); +} + +/** + * @brief Convert a string principal name to a Kerberos principal. + * + * @param[in] context The library context + * + * @param[in] name The principal as a unix charset string. + * + * @param[in] flags Flags for krb5_parse_name_flags() + * + * @param[out] principal The newly allocated principal. + * + * Use krb5_free_principal() to free a principal when it is no longer needed. + * + * @return 0 on success, a Kerberos error code otherwise. + */ +krb5_error_code smb_krb5_parse_name_flags(krb5_context context, + const char *name, + int flags, + krb5_principal *principal) { krb5_error_code ret; char *utf8_name; @@ -843,17 +866,19 @@ krb5_error_code smb_krb5_parse_name(krb5_context context, TALLOC_CTX *frame = talloc_stackframe(); if (!push_utf8_talloc(frame, &utf8_name, name, &converted_size)) { - talloc_free(frame); + TALLOC_FREE(frame); return ENOMEM; } + TALLOC_FREE(frame); - ret = krb5_parse_name(context, utf8_name, principal); - if (ret == KRB5_PARSE_MALFORMED) { - ret = krb5_parse_name_flags(context, utf8_name, - KRB5_PRINCIPAL_PARSE_ENTERPRISE, - principal); + ret = krb5_parse_name_flags(context, utf8_name, flags, principal); + if (ret != KRB5_PARSE_MALFORMED) { + return ret; } - TALLOC_FREE(frame); + + flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; + ret = krb5_parse_name_flags(context, utf8_name, flags, principal); + return ret; } diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h index 173307f7c88..a562359e121 100644 --- a/lib/krb5_wrap/krb5_samba.h +++ b/lib/krb5_wrap/krb5_samba.h @@ -186,6 +186,11 @@ krb5_error_code smb_krb5_parse_name(krb5_context context, const char *name, /* in unix charset */ krb5_principal *principal); +krb5_error_code smb_krb5_parse_name_flags(krb5_context context, + const char *name, /* unix charset */ + int flags, + krb5_principal *principal); + krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, krb5_context context, krb5_const_principal principal, diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c index 5913db299ad..49a892e5a55 100644 --- a/source3/libads/kerberos_keytab.c +++ b/source3/libads/kerberos_keytab.c @@ -364,12 +364,29 @@ static krb5_error_code pw2kt_process_add_info(struct pw2kt_keytab_state *state2, krb5_principal princ = NULL; krb5_principal *a = NULL; size_t len; + const char *realm = NULL; - ret = smb_krb5_parse_name(state2->context, princs, &princ); + ret = smb_krb5_parse_name_flags(state2->context, + princs, + KRB5_PRINCIPAL_PARSE_NO_DEF_REALM, + &princ); if (ret != 0) { DBG_ERR("Failed to parse principal: %s\n", princs); return ret; } + /* Add realm part if missing (e.g. SPNs synced from DC) */ + realm = smb_krb5_principal_get_realm(state2, state2->context, princ); + if (realm == NULL || *realm == 0) { + ret = smb_krb5_principal_set_realm(state2->context, + princ, + lp_realm()); + if (ret != 0) { + DBG_ERR("Failed to add realm to principal: %s\n", + princs); + return ret; + } + } + len = talloc_array_length(state2->princ_array); a = talloc_realloc(state2, state2->princ_array, diff --git a/source3/modules/vfs_ceph_new.c b/source3/modules/vfs_ceph_new.c index cae8317b1c8..05c2a72d57f 100644 --- a/source3/modules/vfs_ceph_new.c +++ b/source3/modules/vfs_ceph_new.c @@ -102,6 +102,9 @@ static const struct enum_list enum_vfs_cephfs_proxy_vals[] = { #define CEPH_FN(_name) typeof(_name) *_name ## _fn struct vfs_ceph_config { +#if HAVE_CEPH_ASYNCIO + struct tevent_threaded_context *tctx; +#endif const char *conf_file; const char *user_id; const char *fsname; @@ -110,7 +113,6 @@ struct vfs_ceph_config { enum vfs_cephfs_proxy_mode proxy; void *libhandle; - CEPH_FN(ceph_ll_lookup_inode); CEPH_FN(ceph_ll_walk); CEPH_FN(ceph_ll_getattr); CEPH_FN(ceph_ll_setattr); @@ -157,6 +159,9 @@ struct vfs_ceph_config { CEPH_FN(ceph_version); CEPH_FN(ceph_rewinddir); CEPH_FN(ceph_readdir_r); +#if HAVE_CEPH_ASYNCIO + CEPH_FN(ceph_ll_nonblocking_readv_writev); +#endif }; /* @@ -274,7 +279,6 @@ static struct ceph_mount_info *cephmount_mount_fs( struct vfs_ceph_config *config) { int ret; - char buf[256]; struct ceph_mount_info *mnt = NULL; /* if config_file and/or user_id are NULL, ceph will use defaults */ @@ -294,12 +298,6 @@ static struct ceph_mount_info *cephmount_mount_fs( goto out; } - DBG_DEBUG("[CEPH] calling ceph_conf_get: option='%s'\n", "log_file"); - ret = config->ceph_conf_get_fn(mnt, "log_file", buf, sizeof(buf)); - if (ret < 0) { - goto out; - } - /* libcephfs disables POSIX ACL support by default, enable it... */ ret = cephmount_update_conf(config, mnt, @@ -396,7 +394,6 @@ static bool vfs_cephfs_load_lib(struct vfs_ceph_config *config) break; } - CHECK_CEPH_FN(libhandle, ceph_ll_lookup_inode); CHECK_CEPH_FN(libhandle, ceph_ll_walk); CHECK_CEPH_FN(libhandle, ceph_ll_getattr); CHECK_CEPH_FN(libhandle, ceph_ll_setattr); @@ -443,6 +440,9 @@ static bool vfs_cephfs_load_lib(struct vfs_ceph_config *config) CHECK_CEPH_FN(libhandle, ceph_version); CHECK_CEPH_FN(libhandle, ceph_rewinddir); CHECK_CEPH_FN(libhandle, ceph_readdir_r); +#if HAVE_CEPH_ASYNCIO + CHECK_CEPH_FN(libhandle, ceph_ll_nonblocking_readv_writev); +#endif config->libhandle = libhandle; @@ -698,10 +698,7 @@ static struct dirent *vfs_ceph_get_fh_dirent(struct vfs_ceph_fh *cfh) static void vfs_ceph_put_fh_dirent(struct vfs_ceph_fh *cfh) { - if (cfh->de != NULL) { - TALLOC_FREE(cfh->de); - cfh->de = NULL; - } + TALLOC_FREE(cfh->de); } static int vfs_ceph_release_fh(struct vfs_ceph_fh *cfh) @@ -798,21 +795,6 @@ static void vfs_ceph_assign_fh_fd(struct vfs_ceph_fh *cfh) /* Ceph low-level wrappers */ -static int vfs_ceph_ll_lookup_inode(const struct vfs_handle_struct *handle, - uint64_t inoval, - Inode **pout) -{ - struct inodeno_t ino = {.val = inoval}; - struct vfs_ceph_config *config = NULL; - - SMB_VFS_HANDLE_GET_DATA(handle, config, struct vfs_ceph_config, - return -ENOMEM); - - DBG_DEBUG("[CEPH] ceph_ll_lookup_inode: ino=%" PRIu64 "\n", inoval); - - return config->ceph_ll_lookup_inode_fn(config->mount, ino, pout); -} - static int vfs_ceph_ll_walk(const struct vfs_handle_struct *handle, const char *name, struct Inode **pin, @@ -823,10 +805,31 @@ static int vfs_ceph_ll_walk(const struct vfs_handle_struct *handle, struct UserPerm *uperm = NULL; int ret = -1; struct vfs_ceph_config *config = NULL; + const char *cwd = NULL; + size_t cwdlen; SMB_VFS_HANDLE_GET_DATA(handle, config, struct vfs_ceph_config, return -ENOMEM); + cwd = config->ceph_getcwd_fn(config->mount); + cwdlen = strlen(cwd); + + /* + * ceph_ll_walk() always operate on "name" relative to current working + * directory even if it starts with a '/' i.e, absolute path is never + * honoured. But why?? For now stick to the current behaviour and ensure + * that the "name" is always relative when it contains current working + * directory path with an exception to "/". + */ + if ((strcmp(cwd, "/") != 0) && + (strncmp(name, cwd, cwdlen) == 0)) { + if (name[cwdlen] == '/') { + name += cwdlen + 1; + } else if (name[cwdlen] == '\0') { + name = "."; + } + } + DBG_DEBUG("[CEPH] ceph_ll_walk: name=%s\n", name); uperm = vfs_ceph_userperm_new(config, handle->conn); @@ -1795,76 +1798,56 @@ static int vfs_ceph_ll_fremovexattr(const struct vfs_handle_struct *handle, cfh->uperm); } +#if HAVE_CEPH_ASYNCIO +static int64_t vfs_ceph_ll_nonblocking_readv_writev( + const struct vfs_handle_struct *handle, + const struct vfs_ceph_fh *cfh, + struct ceph_ll_io_info *io_info) +{ + struct vfs_ceph_config *config = NULL; + + SMB_VFS_HANDLE_GET_DATA(handle, + config, + struct vfs_ceph_config, + return -EINVAL); + + DBG_DEBUG("[CEPH] ceph_ll_nonblocking_readv_writev: ino=%" PRIu64 + " fd=%d off=%jd\n", + cfh->iref.ino, + cfh->fd, + io_info->off); + + return config->ceph_ll_nonblocking_readv_writev_fn(config->mount, + io_info); +} +#endif + /* Ceph Inode-refernce get/put wrappers */ static int vfs_ceph_iget(const struct vfs_handle_struct *handle, - uint64_t ino, const char *name, unsigned int flags, struct vfs_ceph_iref *iref) { struct Inode *inode = NULL; int ret = -1; + struct ceph_statx stx = {.stx_ino = 0}; - if (ino > CEPH_INO_ROOT) { - /* get-by-ino */ - ret = vfs_ceph_ll_lookup_inode(handle, ino, &inode); - if (ret != 0) { - return ret; - } - } else { - /* get-by-path */ - struct ceph_statx stx = {.stx_ino = 0}; - - ret = vfs_ceph_ll_walk(handle, - name, - &inode, - &stx, - CEPH_STATX_INO, - flags); - if (ret != 0) { - return ret; - } - ino = stx.stx_ino; + ret = vfs_ceph_ll_walk(handle, + name, + &inode, + &stx, + CEPH_STATX_INO, + flags); + if (ret != 0) { + return ret; } iref->inode = inode; - iref->ino = ino; + iref->ino = stx.stx_ino; iref->owner = true; DBG_DEBUG("[CEPH] iget: %s ino=%" PRIu64 "\n", name, iref->ino); return 0; } -static int vfs_ceph_iget_by_fname(const struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - struct vfs_ceph_iref *iref) -{ - const char *name = smb_fname->base_name; - const char *cwd = NULL; - int ret = -1; - struct vfs_ceph_config *config = NULL; - - SMB_VFS_HANDLE_GET_DATA(handle, config, struct vfs_ceph_config, - return -ENOMEM); - - cwd = config->ceph_getcwd_fn(config->mount); - if (!strcmp(name, cwd)) { - ret = vfs_ceph_iget(handle, 0, "./", 0, iref); - } else { - ret = vfs_ceph_iget(handle, 0, name, 0, iref); - } - return ret; -} - -static int vfs_ceph_igetl(const struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - struct vfs_ceph_iref *iref) -{ - return vfs_ceph_iget(handle, - 0, - smb_fname->base_name, - AT_SYMLINK_NOFOLLOW, - iref); -} - static int vfs_ceph_igetd(struct vfs_handle_struct *handle, const struct files_struct *dirfsp, struct vfs_ceph_iref *iref) @@ -1883,25 +1866,16 @@ static int vfs_ceph_igetd(struct vfs_handle_struct *handle, /* case-2: resolve by current work-dir */ if (fsp_get_pathref_fd(dirfsp) == AT_FDCWD) { - return vfs_ceph_iget(handle, 0, ".", 0, iref); + return vfs_ceph_iget(handle, ".", 0, iref); } /* case-3: resolve by parent dir and name */ return vfs_ceph_iget(handle, - dirfsp->file_id.inode, dirfsp->fsp_name->base_name, AT_SYMLINK_NOFOLLOW, iref); } -static int vfs_ceph_igetf(struct vfs_handle_struct *handle, - const struct files_struct *fsp, - struct vfs_ceph_iref *iref) -{ - return vfs_ceph_iget( - handle, fsp->file_id.inode, fsp->fsp_name->base_name, 0, iref); -} - static void vfs_ceph_iput(const struct vfs_handle_struct *handle, struct vfs_ceph_iref *iref) { @@ -1966,7 +1940,7 @@ static int vfs_ceph_statvfs(struct vfs_handle_struct *handle, struct vfs_ceph_iref iref = {0}; int ret; - ret = vfs_ceph_iget_by_fname(handle, smb_fname, &iref); + ret = vfs_ceph_iget(handle, smb_fname->base_name, 0, &iref); if (ret != 0) { goto out; } @@ -2272,17 +2246,28 @@ out: } struct vfs_ceph_aio_state { + struct vfs_ceph_config *config; + struct vfs_ceph_fh *cfh; +#if HAVE_CEPH_ASYNCIO + struct tevent_req *req; + bool orphaned; + struct tevent_immediate *im; + void *data; + size_t len; + off_t off; + bool write; + bool fsync; + + struct ceph_ll_io_info io_info; + struct iovec iov; +#endif struct timespec start_time; struct timespec finish_time; + ssize_t result; struct vfs_aio_state vfs_aio_state; SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes); }; -struct vfs_ceph_pread_state { - ssize_t bytes_read; - struct vfs_ceph_aio_state ceph_aio_state; -}; - static void vfs_ceph_aio_start(struct vfs_ceph_aio_state *state) { SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes); @@ -2298,22 +2283,218 @@ static void vfs_ceph_aio_finish(struct vfs_ceph_aio_state *state, if (result < 0) { state->vfs_aio_state.error = (int)result; } + + state->result = result; SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); } -/* - * Fake up an async ceph read by calling the synchronous API. - */ +#if HAVE_CEPH_ASYNCIO + +static void vfs_ceph_aio_done(struct tevent_context *ev, + struct tevent_immediate *im, + void *private_data); + +static int vfs_ceph_require_tctx(struct vfs_ceph_aio_state *state, + struct tevent_context *ev) +{ + struct vfs_ceph_config *config = state->config; + + if (config->tctx != NULL) { + return 0; + } + + config->tctx = tevent_threaded_context_create(config, ev); + if (config->tctx == NULL) { + return -ENOMEM; + } + + return 0; +} + +static void vfs_ceph_aio_complete(struct ceph_ll_io_info *io_info) +{ + struct vfs_ceph_aio_state *state = io_info->priv; + + if (state->orphaned) { + return; + } + + DBG_DEBUG("[CEPH] aio_complete: ino=%" PRIu64 + " fd=%d off=%jd len=%ju result=%jd\n", + state->cfh->iref.ino, + state->cfh->fd, + state->off, + state->len, + state->io_info.result); + + tevent_threaded_schedule_immediate(state->config->tctx, + state->im, + vfs_ceph_aio_done, + state->req); +} + +static void vfs_ceph_aio_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) +{ + struct vfs_ceph_aio_state *state = tevent_req_data( + req, struct vfs_ceph_aio_state); + + if (req_state == TEVENT_REQ_IN_PROGRESS) { + /* + * The job thread is still running, we need to protect the + * memory used by the job completion function. + */ + (void)talloc_reparent(req, NULL, state); + state->orphaned = true; -- Samba Shared Repository