diff --git a/include/spdk/blob.h b/include/spdk/blob.h index e955987a351..c761ae18e1f 100644 --- a/include/spdk/blob.h +++ b/include/spdk/blob.h @@ -733,8 +733,8 @@ void spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, * \param cb_fn Called when the operation is complete. * \param cb_arg Argument passed to function cb_fn. */ -void spdk_bs_open_blob_ext(struct spdk_blob_store *bs, spdk_blob_id blobid, - struct spdk_blob_open_opts *opts, spdk_blob_op_with_handle_complete cb_fn, void *cb_arg); +int spdk_bs_open_blob_ext(struct spdk_blob_store *bs, spdk_blob_id blobid, + struct spdk_blob_open_opts *opts, spdk_blob_op_with_handle_complete cb_fn, void *cb_arg); /** * Resize a blob to 'sz' clusters. These changes are not persisted to disk until diff --git a/include/spdk_internal/lvolstore.h b/include/spdk_internal/lvolstore.h index abd32c83421..582e5807239 100644 --- a/include/spdk_internal/lvolstore.h +++ b/include/spdk_internal/lvolstore.h @@ -98,6 +98,11 @@ struct spdk_lvol { TAILQ_ENTRY(spdk_lvol) link; }; +struct spdk_lvol_snapshot_req { + struct spdk_lvol *parent; + struct spdk_lvol_with_handle_req *req; +}; + struct lvol_store_bdev *vbdev_lvol_store_first(void); struct lvol_store_bdev *vbdev_lvol_store_next(struct lvol_store_bdev *prev); @@ -108,5 +113,10 @@ void spdk_lvol_set_read_only(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn void *cb_arg); int vbdev_lvs_examine(struct spdk_bdev *bdev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg); - +/** + * Reset num_used_clusters_cache, if blob is thin provisioned and snapshot is + * created from it. New snapshot will own the data, hence the clusted information + * present in the blob cache can be cleared. + */ +void blob_reset_used_clusters_cache(struct spdk_blob *blob); #endif /* SPDK_INTERNAL_LVOLSTORE_H */ diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index 5bafcf03616..902690dc9a7 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -19,6 +19,7 @@ #include "spdk/bdev_module.h" #include "spdk_internal/assert.h" +#include "spdk_internal/lvolstore.h" #include "spdk/log.h" #include "blobstore.h" @@ -5789,6 +5790,16 @@ spdk_blob_calc_used_clusters(struct spdk_blob *blob) return num; } +void +blob_reset_used_clusters_cache(struct spdk_blob *blob) +{ + assert(blob != NULL); + if (spdk_blob_is_thin_provisioned(blob)) { + spdk_spin_lock(&blob->bs->used_lock); + blob->num_used_clusters_cache = 0; + spdk_spin_unlock(&blob->bs->used_lock); + } +} /* START spdk_bs_create_blob */ static void @@ -7414,7 +7425,7 @@ blob_open_opts_copy(const struct spdk_blob_open_opts *src, struct spdk_blob_open #undef SET_FIELD } -static void +static int bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, struct spdk_blob_open_opts *opts, @@ -7434,20 +7445,20 @@ bs_open_blob(struct spdk_blob_store *bs, if (spdk_bit_array_get(bs->used_blobids, page_num) == false) { /* Invalid blobid */ cb_fn(cb_arg, NULL, -ENOENT); - return; + return -ENOENT; } blob = blob_lookup(bs, blobid); if (blob) { blob->open_ref++; cb_fn(cb_arg, blob, 0); - return; + return 0; } blob = blob_alloc(bs, blobid); if (!blob) { cb_fn(cb_arg, NULL, -ENOMEM); - return; + return -ENOMEM; } spdk_blob_open_opts_init(&opts_local, sizeof(opts_local)); @@ -7466,10 +7477,11 @@ bs_open_blob(struct spdk_blob_store *bs, if (!seq) { blob_free(blob); cb_fn(cb_arg, NULL, -ENOMEM); - return; + return -ENOMEM; } blob_load(seq, blob, bs_open_blob_cpl, blob); + return 0; } void @@ -7479,11 +7491,11 @@ spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, bs_open_blob(bs, blobid, NULL, cb_fn, cb_arg); } -void +int spdk_bs_open_blob_ext(struct spdk_blob_store *bs, spdk_blob_id blobid, struct spdk_blob_open_opts *opts, spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) { - bs_open_blob(bs, blobid, opts, cb_fn, cb_arg); + return bs_open_blob(bs, blobid, opts, cb_fn, cb_arg); } /* END spdk_bs_open_blob */ diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c index 4a304c31374..7ef26a0ccab 100644 --- a/lib/lvol/lvol.c +++ b/lib/lvol/lvol.c @@ -979,6 +979,39 @@ lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno) spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req); } +static void +lvol_create_snapshot_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno) +{ + struct spdk_lvol_snapshot_req *snap_req = cb_arg; + struct spdk_blob_store *bs; + struct spdk_blob_open_opts opts; + + if (lvolerrno < 0) { + TAILQ_REMOVE(&snap_req->req->lvol->lvol_store->pending_lvols, snap_req->req->lvol, link); + free(snap_req->req->lvol); + assert(snap_req->req->cb_fn != NULL); + snap_req->req->cb_fn(snap_req->req->cb_arg, NULL, lvolerrno); + free(snap_req->req); + free(snap_req); + return; + } + + spdk_blob_open_opts_init(&opts, sizeof(opts)); + opts.clear_method = snap_req->req->lvol->clear_method; + bs = snap_req->req->lvol->lvol_store->blobstore; + + lvolerrno = spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, snap_req->req); + /* + * Reset used clusters cache if blob is thin provisioned and new snapshot + * is created from it. + */ + if (lvolerrno == 0) { + blob_reset_used_clusters_cache(snap_req->parent->blob); + } + + free(snap_req); +} + static void lvol_get_xattr_value(void *xattr_ctx, const char *name, const void **value, size_t *value_len) @@ -1153,6 +1186,7 @@ create_lvol_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name, struct spdk_lvol *newlvol; struct spdk_blob *origblob; struct spdk_lvol_with_handle_req *req; + struct spdk_lvol_snapshot_req *snap_req; struct xattr_value_ext_arg xattr_args; char *xattr_names[SPDK_LVOL_MAX_SNAPSHOT_ATTRS + 2]; /* Extra default attributes. */ int rc; @@ -1225,18 +1259,25 @@ create_lvol_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name, cb_fn(cb_arg, NULL, rc); return; } - + snap_req = calloc(1, sizeof(*snap_req)); + if (!snap_req) { + SPDK_ERRLOG("Cannot alloc memory for snapshot request pointer\n"); + cb_fn(cb_arg, NULL, -ENOMEM); + return; + } req = calloc(1, sizeof(*req)); if (!req) { SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n"); cb_fn(cb_arg, NULL, -ENOMEM); + free(snap_req); return; } - + snap_req->req = req; newlvol = calloc(1, sizeof(*newlvol)); if (!newlvol) { SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n"); free(req); + free(snap_req); cb_fn(cb_arg, NULL, -ENOMEM); return; } @@ -1265,12 +1306,13 @@ create_lvol_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name, xattr_args.user_xattrs = xattrs; xattr_args.user_xattrs_count = xattrs_count; - req->lvol = newlvol; - req->cb_fn = cb_fn; - req->cb_arg = cb_arg; + snap_req->req->lvol = newlvol; + snap_req->req->cb_fn = cb_fn; + snap_req->req->cb_arg = cb_arg; + snap_req->parent = origlvol; spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &xattr_args.lvol_xattrs, - lvol_create_cb, req); + lvol_create_snapshot_cb, snap_req); } void