// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "librbd/image/CloseRequest.h" #include "common/dout.h" #include "common/errno.h" #include "librbd/ExclusiveLock.h" #include "librbd/ImageCtx.h" #include "librbd/ImageState.h" #include "librbd/ImageWatcher.h" #include "librbd/ObjectMap.h" #include "librbd/Utils.h" #include "librbd/io/ImageRequestWQ.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::image::CloseRequest: " namespace librbd { namespace image { using util::create_async_context_callback; using util::create_context_callback; template CloseRequest::CloseRequest(I *image_ctx, Context *on_finish) : m_image_ctx(image_ctx), m_on_finish(on_finish), m_error_result(0), m_exclusive_lock(nullptr) { assert(image_ctx != nullptr); } template void CloseRequest::send() { send_block_image_watcher(); } template void CloseRequest::send_block_image_watcher() { if (m_image_ctx->image_watcher == nullptr) { send_shut_down_update_watchers(); return; } CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; // prevent incoming requests from our peers m_image_ctx->image_watcher->block_notifies(create_context_callback< CloseRequest, &CloseRequest::handle_block_image_watcher>(this)); } template void CloseRequest::handle_block_image_watcher(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; send_shut_down_update_watchers(); } template void CloseRequest::send_shut_down_update_watchers() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->state->shut_down_update_watchers(create_async_context_callback( *m_image_ctx, create_context_callback< CloseRequest, &CloseRequest::handle_shut_down_update_watchers>(this))); } template void CloseRequest::handle_shut_down_update_watchers(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; save_result(r); if (r < 0) { lderr(cct) << "failed to shut down update watchers: " << cpp_strerror(r) << dendl; } send_shut_down_io_queue(); } template void CloseRequest::send_shut_down_io_queue() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; RWLock::RLocker owner_locker(m_image_ctx->owner_lock); m_image_ctx->io_work_queue->shut_down(create_context_callback< CloseRequest, &CloseRequest::handle_shut_down_io_queue>(this)); } template void CloseRequest::handle_shut_down_io_queue(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; send_shut_down_exclusive_lock(); } template void CloseRequest::send_shut_down_exclusive_lock() { { RWLock::WLocker owner_locker(m_image_ctx->owner_lock); m_exclusive_lock = m_image_ctx->exclusive_lock; // if reading a snapshot -- possible object map is open RWLock::WLocker snap_locker(m_image_ctx->snap_lock); if (m_exclusive_lock == nullptr) { delete m_image_ctx->object_map; m_image_ctx->object_map = nullptr; } } if (m_exclusive_lock == nullptr) { send_flush(); return; } CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; // in-flight IO will be flushed and in-flight requests will be canceled // before releasing lock m_exclusive_lock->shut_down(create_context_callback< CloseRequest, &CloseRequest::handle_shut_down_exclusive_lock>(this)); } template void CloseRequest::handle_shut_down_exclusive_lock(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; { RWLock::RLocker owner_locker(m_image_ctx->owner_lock); assert(m_image_ctx->exclusive_lock == nullptr); // object map and journal closed during exclusive lock shutdown RWLock::RLocker snap_locker(m_image_ctx->snap_lock); assert(m_image_ctx->journal == nullptr); assert(m_image_ctx->object_map == nullptr); } delete m_exclusive_lock; m_exclusive_lock = nullptr; save_result(r); if (r < 0) { lderr(cct) << "failed to shut down exclusive lock: " << cpp_strerror(r) << dendl; } send_unregister_image_watcher(); } template void CloseRequest::send_flush() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; RWLock::RLocker owner_locker(m_image_ctx->owner_lock); m_image_ctx->flush(create_async_context_callback( *m_image_ctx, create_context_callback< CloseRequest, &CloseRequest::handle_flush>(this))); } template void CloseRequest::handle_flush(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; if (r < 0) { lderr(cct) << "failed to flush IO: " << cpp_strerror(r) << dendl; } send_unregister_image_watcher(); } template void CloseRequest::send_unregister_image_watcher() { if (m_image_ctx->image_watcher == nullptr) { send_flush_readahead(); return; } CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->image_watcher->unregister_watch(create_context_callback< CloseRequest, &CloseRequest::handle_unregister_image_watcher>(this)); } template void CloseRequest::handle_unregister_image_watcher(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; save_result(r); if (r < 0) { lderr(cct) << "failed to unregister image watcher: " << cpp_strerror(r) << dendl; } send_flush_readahead(); } template void CloseRequest::send_flush_readahead() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->readahead.wait_for_pending(create_async_context_callback( *m_image_ctx, create_context_callback< CloseRequest, &CloseRequest::handle_flush_readahead>(this))); } template void CloseRequest::handle_flush_readahead(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; send_shut_down_cache(); } template void CloseRequest::send_shut_down_cache() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->shut_down_cache(create_context_callback< CloseRequest, &CloseRequest::handle_shut_down_cache>(this)); } template void CloseRequest::handle_shut_down_cache(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; save_result(r); if (r < 0) { lderr(cct) << "failed to shut down cache: " << cpp_strerror(r) << dendl; } send_flush_op_work_queue(); } template void CloseRequest::send_flush_op_work_queue() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->op_work_queue->queue(create_context_callback< CloseRequest, &CloseRequest::handle_flush_op_work_queue>(this), 0); } template void CloseRequest::handle_flush_op_work_queue(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; send_close_parent(); } template void CloseRequest::send_close_parent() { if (m_image_ctx->parent == nullptr) { send_flush_image_watcher(); return; } CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_image_ctx->parent->state->close(create_async_context_callback( *m_image_ctx, create_context_callback< CloseRequest, &CloseRequest::handle_close_parent>(this))); } template void CloseRequest::handle_close_parent(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; delete m_image_ctx->parent; save_result(r); if (r < 0) { lderr(cct) << "error closing parent image: " << cpp_strerror(r) << dendl; } send_flush_image_watcher(); } template void CloseRequest::send_flush_image_watcher() { if (m_image_ctx->image_watcher == nullptr) { finish(); return; } m_image_ctx->image_watcher->flush(create_context_callback< CloseRequest, &CloseRequest::handle_flush_image_watcher>(this)); } template void CloseRequest::handle_flush_image_watcher(int r) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; if (r < 0) { lderr(cct) << "error flushing image watcher: " << cpp_strerror(r) << dendl; } save_result(r); finish(); } template void CloseRequest::finish() { m_image_ctx->shutdown(); m_on_finish->complete(m_error_result); delete this; } } // namespace image } // namespace librbd template class librbd::image::CloseRequest;