Spdk/module/bdev/lvol/vbdev_lvol.h

174 lines
5.6 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2017 Intel Corporation.
* All rights reserved.
* Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#ifndef SPDK_VBDEV_LVOL_H
#define SPDK_VBDEV_LVOL_H
#include "spdk/lvol.h"
#include "spdk/bdev_module.h"
#include "spdk_internal/lvolstore.h"
struct lvol_store_bdev {
struct spdk_lvol_store *lvs;
struct spdk_bdev *bdev;
struct spdk_lvs_req *req;
lvol: lvol destruction race leads to null deref As an lvolstore is being destroyed, _vbdev_lvs_remove() starts an interation through the lvols to delete each one, ultimately leading to the destruction of the lvolstore with a call to lvs_free(). The callback passed to vbdev_lvs_destruct() is always called asynchronously via spdk_io_device_unregister() in bs_free(). When the lvolstore resides on bdevs that perform async IO (i.e. most bdevs other than malloc), this gives a small window when the lvol bdev is not registered but a lookup with spdk_lvol_get_by_uuid() or spdk_lvol_get_by_names() will succeed. If rpc_bdev_lvol_delete() runs during this window, it can get a reference to an lvol that has just been unregistered and lvol->blob may be NULL. This lvol is then passed to vbdev_lvol_destroy(). Before this fix, vbdev_lvol_destroy() would call: spdk_blob_is_degraded(lvol->blob); Which would then lead to a NULL pointer dereference, as spdk_blob_is_degraded() assumes a valid blob is passed. While a NULL check would avoid this particular problem, a NULL blob is not necessarily caused by the condition described above. It would better to flag the lvstore's destruction before returning from vbdev_lvs_destruct() and use that flag to prevent operations on the lvolstore that is being deleted. Such a flag already exists in the form of 'lvs_bdev->req != NULL', but that is set too late to close this race. This fix introduces lvs_bdev->removal_in_progress which is set prior to returning from vbdev_lvs_unload() and vbdev_lvs_destruct(). It is checked by vbdev_lvol_destroy() before trying to destroy the lvol. Now, any lvol destruction initiated by something other than vbdev_lvs_destruct() while an lvolstore unload or destroy is in progress will fail with -ENODEV. Fixes issue: #2998 Signed-off-by: Mike Gerdts <mgerdts@nvidia.com> Change-Id: I4d861879097703b0d8e3180e6de7ad6898f340fd Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17891 Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2023-05-01 18:02:47 +00:00
bool removal_in_progress;
TAILQ_ENTRY(lvol_store_bdev) lvol_stores;
};
struct lvol_bdev {
struct spdk_bdev bdev;
struct spdk_lvol *lvol;
bdev/lvol: remove lvs with lvols during application shutdown Once bdev finish starts, bdev unregister is called on all unclaimed bdevs. This means that for lvs with at least one lvol present, there will be a corresponding bdev unregister. Yet the vbdev_lvol module does not attempt to unload the lvs, once last lvol from that lvs is unregistered. Leaving the base bdev for lvs claimed. This patch fixes that by using fini_start callback from bdev_module to mark when shutdown begins. After that last lvol unregistered on lvs will unload it. Expanded struct lvol_bdev to contain lvol_store_bdev. Closing the lvol will free spdk_lvol, so lvol->lvol_store cannot be accessed. Changed ut_lvol_destroy UT to ut_bdev_finish. Previous UT didn't really test vbdev_lvol_destroy, but 'hotremove' of the lvol bdev. In effect there is no hotremove of the lvol bdevs (only lvs bdev). spdk_bdev_unregister() can only be called from within vbdev_lvol, or during bdev module finish. This UT will now check the bdev module finish. Note that at this point lvs with no lvols will not trigger lvs unload. Next patches in series will introduce async fini_start, to allow for the unload. Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Change-Id: I8f51e8c1fcfdc55a5d090a3bc84ccefda813aef8 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9093 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
2021-08-05 10:14:54 +00:00
struct lvol_store_bdev *lvs_bdev;
};
int vbdev_lvs_create(const char *base_bdev_name, const char *name, uint32_t cluster_sz,
enum lvs_clear_method clear_method, uint32_t num_md_pages_per_cluster_ratio,
spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg);
void vbdev_lvs_destruct(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg);
void vbdev_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg);
int vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provisioned, enum lvol_clear_method clear_method,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg);
void vbdev_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
void vbdev_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
void vbdev_lvol_create_bdev_clone(const char *esnap_uuid,
struct spdk_lvol_store *lvs, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
/**
* \brief Change size of lvol
* \param lvol Handle to lvol
* \param sz Size of lvol to change
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
* \return error
*/
void vbdev_lvol_resize(struct spdk_lvol *lvol, uint64_t sz, spdk_lvol_op_complete cb_fn,
void *cb_arg);
/**
* \brief Mark lvol as read only
* \param lvol Handle to lvol
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvol_set_read_only(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
void vbdev_lvol_rename(struct spdk_lvol *lvol, const char *new_lvol_name,
spdk_lvol_op_complete cb_fn, void *cb_arg);
/**
* \brief Set lvol's xattr
* \param lvol Handle to lvol
* \param name xattr name
* \param value xattr value
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvol_set_xattr(struct spdk_lvol *lvol, const char *name,
const char *value, spdk_lvol_op_complete cb_fn, void *cb_arg);
/**
* \brief Get lvol's xattr
* \param lvol Handle to lvol
* \param name Xattr name
* \param value Xattr value
* \param value_len Xattr value length
*/
int vbdev_lvol_get_xattr(struct spdk_lvol *lvol, const char *name,
const void **value, size_t *value_len);
/**
* Destroy a logical volume
* \param lvol Handle to lvol
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
/**
* \brief Renames given lvolstore.
*
* \param lvs Pointer to lvolstore
* \param new_name New name of lvs
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvs_rename(struct spdk_lvol_store *lvs, const char *new_lvs_name,
spdk_lvs_op_complete cb_fn, void *cb_arg);
/**
* \brief Search for handle lvolstore
* \param uuid_str UUID of lvolstore
* \return Handle to spdk_lvol_store or NULL if not found.
*/
struct spdk_lvol_store *vbdev_get_lvol_store_by_uuid(const char *uuid_str);
/**
* \brief Search for handle to lvolstore
* \param name name of lvolstore
* \return Handle to spdk_lvol_store or NULL if not found.
*/
struct spdk_lvol_store *vbdev_get_lvol_store_by_name(const char *name);
/**
* \brief Search for handle to lvol_store_bdev
* \param lvs handle to lvolstore
* \return Handle to lvol_store_bdev or NULL if not found.
*/
struct lvol_store_bdev *vbdev_get_lvs_bdev_by_lvs(struct spdk_lvol_store *lvs);
struct spdk_lvol *vbdev_lvol_get_from_bdev(struct spdk_bdev *bdev);
/**
* \brief Grow given lvolstore.
*
* \param lvs Pointer to lvolstore
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvs_grow(struct spdk_lvol_store *lvs,
spdk_lvs_op_complete cb_fn, void *cb_arg);
int vbdev_lvol_esnap_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
const void *esnap_id, uint32_t id_len,
struct spdk_bs_dev **_bs_dev);
/**
* \brief Make a shallow copy of lvol over a bdev
*
* \param lvol Handle to lvol
* \param bdev_name Name of the bdev to copy on
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvol_shallow_copy(struct spdk_lvol *lvol, const char *bdev_name,
spdk_lvol_op_complete cb_fn, void *cb_arg);
/**
* @brief Get a fragmap for a specific segment of a logical volume using the provided offset and size
*
* @param lvol Handle to lvol
* @param offset Offset in bytes of the specific segment of the logical volume
* @param size Size in bytes of the specific segment of the logical volume
* @param cb_fn Completion callback
* @param cb_arg Completion callback custom arguments
*/
void
vbdev_lvol_get_fragmap(struct spdk_lvol *lvol, uint64_t offset, uint64_t size,
spdk_lvol_op_with_fragmap_handle_complete cb_fn, void *cb_arg);
#endif /* SPDK_VBDEV_LVOL_H */