+/*!
+ * \internal
+ * \brief Put obj into the arg container.
+ * \since 11.0
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \retval 0 on success.
+ * \retval CMP_STOP|CMP_MATCH on error.
+ */
+static int dup_obj_cb(void *obj, void *arg, int flags)
+{
+ struct ao2_container *dest = arg;
+
+ return __ao2_link(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
+{
+ void *obj;
+ int res = 0;
+
+ if (!(flags & OBJ_NOLOCK)) {
+ ao2_lock(src);
+ ao2_lock(dest);
+ }
+ obj = __ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
+ if (obj) {
+ /* Failed to put this obj into the dest container. */
+ __ao2_ref(obj, -1);
+
+ /* Remove all items from the dest container. */
+ __ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
+ NULL);
+ res = -1;
+ }
+ if (!(flags & OBJ_NOLOCK)) {
+ ao2_unlock(dest);
+ ao2_unlock(src);
+ }
+
+ return res;
+}
+
+struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags)
+{
+ struct ao2_container *clone;
+ int failed;
+
+ /* Create the clone container with the same properties as the original. */
+ clone = __ao2_container_alloc(orig->n_buckets, orig->hash_fn, orig->cmp_fn);
+ if (!clone) {
+ return NULL;
+ }
+
+ if (flags & OBJ_NOLOCK) {
+ ao2_lock(clone);
+ }
+ failed = ao2_container_dup(clone, orig, flags);
+ if (flags & OBJ_NOLOCK) {
+ ao2_unlock(clone);
+ }
+ if (failed) {
+ /* Object copy into the clone container failed. */
+ __ao2_ref(clone, -1);
+ clone = NULL;
+ }
+ return clone;
+}
+
+struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, char *file, int line, const char *funcname, int ref_debug)
+{
+ struct ao2_container *clone;
+ int failed;
+
+ /* Create the clone container with the same properties as the original. */
+ clone = __ao2_container_alloc_debug(orig->n_buckets, orig->hash_fn, orig->cmp_fn, tag,
+ file, line, funcname, ref_debug);
+ if (!clone) {
+ return NULL;
+ }
+
+ if (flags & OBJ_NOLOCK) {
+ ao2_lock(clone);
+ }
+ failed = ao2_container_dup(clone, orig, flags);
+ if (flags & OBJ_NOLOCK) {
+ ao2_unlock(clone);
+ }
+ if (failed) {
+ /* Object copy into the clone container failed. */
+ if (ref_debug) {
+ __ao2_ref_debug(clone, -1, tag, file, line, funcname);
+ } else {
+ __ao2_ref(clone, -1);
+ }
+ clone = NULL;
+ }
+ return clone;
+}
+