Merge tag 'ntfs3_for_6.6' of https://github.com/Paragon-Software-Group/linux-ntfs3
[platform/kernel/linux-rpi.git] / drivers / block / rbd.c
index 3de11f0..a999b69 100644 (file)
@@ -632,9 +632,8 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
 
 static int rbd_dev_refresh(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev);
-static int rbd_dev_header_info(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev);
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+                                    struct rbd_image_header *header);
 static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
                                        u64 snap_id);
 static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
@@ -995,15 +994,24 @@ static void rbd_init_layout(struct rbd_device *rbd_dev)
        RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
 }
 
+static void rbd_image_header_cleanup(struct rbd_image_header *header)
+{
+       kfree(header->object_prefix);
+       ceph_put_snap_context(header->snapc);
+       kfree(header->snap_sizes);
+       kfree(header->snap_names);
+
+       memset(header, 0, sizeof(*header));
+}
+
 /*
  * Fill an rbd image header with information from the given format 1
  * on-disk header.
  */
-static int rbd_header_from_disk(struct rbd_device *rbd_dev,
-                                struct rbd_image_header_ondisk *ondisk)
+static int rbd_header_from_disk(struct rbd_image_header *header,
+                               struct rbd_image_header_ondisk *ondisk,
+                               bool first_time)
 {
-       struct rbd_image_header *header = &rbd_dev->header;
-       bool first_time = header->object_prefix == NULL;
        struct ceph_snap_context *snapc;
        char *object_prefix = NULL;
        char *snap_names = NULL;
@@ -1070,11 +1078,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
        if (first_time) {
                header->object_prefix = object_prefix;
                header->obj_order = ondisk->options.order;
-               rbd_init_layout(rbd_dev);
-       } else {
-               ceph_put_snap_context(header->snapc);
-               kfree(header->snap_names);
-               kfree(header->snap_sizes);
        }
 
        /* The remaining fields always get updated (when we refresh) */
@@ -4859,7 +4862,9 @@ out_req:
  * return, the rbd_dev->header field will contain up-to-date
  * information about the image.
  */
-static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header,
+                                 bool first_time)
 {
        struct rbd_image_header_ondisk *ondisk = NULL;
        u32 snap_count = 0;
@@ -4907,7 +4912,7 @@ static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
                snap_count = le32_to_cpu(ondisk->snap_count);
        } while (snap_count != want_count);
 
-       ret = rbd_header_from_disk(rbd_dev, ondisk);
+       ret = rbd_header_from_disk(header, ondisk, first_time);
 out:
        kfree(ondisk);
 
@@ -4931,39 +4936,6 @@ static void rbd_dev_update_size(struct rbd_device *rbd_dev)
        }
 }
 
-static int rbd_dev_refresh(struct rbd_device *rbd_dev)
-{
-       u64 mapping_size;
-       int ret;
-
-       down_write(&rbd_dev->header_rwsem);
-       mapping_size = rbd_dev->mapping.size;
-
-       ret = rbd_dev_header_info(rbd_dev);
-       if (ret)
-               goto out;
-
-       /*
-        * If there is a parent, see if it has disappeared due to the
-        * mapped image getting flattened.
-        */
-       if (rbd_dev->parent) {
-               ret = rbd_dev_v2_parent_info(rbd_dev);
-               if (ret)
-                       goto out;
-       }
-
-       rbd_assert(!rbd_is_snap(rbd_dev));
-       rbd_dev->mapping.size = rbd_dev->header.image_size;
-
-out:
-       up_write(&rbd_dev->header_rwsem);
-       if (!ret && mapping_size != rbd_dev->mapping.size)
-               rbd_dev_update_size(rbd_dev);
-
-       return ret;
-}
-
 static const struct blk_mq_ops rbd_mq_ops = {
        .queue_rq       = rbd_queue_rq,
 };
@@ -5503,17 +5475,12 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
        return 0;
 }
 
-static int rbd_dev_v2_image_size(struct rbd_device *rbd_dev)
-{
-       return _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
-                                       &rbd_dev->header.obj_order,
-                                       &rbd_dev->header.image_size);
-}
-
-static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev,
+                                   char **pobject_prefix)
 {
        size_t size;
        void *reply_buf;
+       char *object_prefix;
        int ret;
        void *p;
 
@@ -5531,16 +5498,16 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
                goto out;
 
        p = reply_buf;
-       rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p,
-                                               p + ret, NULL, GFP_NOIO);
+       object_prefix = ceph_extract_encoded_string(&p, p + ret, NULL,
+                                                   GFP_NOIO);
+       if (IS_ERR(object_prefix)) {
+               ret = PTR_ERR(object_prefix);
+               goto out;
+       }
        ret = 0;
 
-       if (IS_ERR(rbd_dev->header.object_prefix)) {
-               ret = PTR_ERR(rbd_dev->header.object_prefix);
-               rbd_dev->header.object_prefix = NULL;
-       } else {
-               dout("  object_prefix = %s\n", rbd_dev->header.object_prefix);
-       }
+       *pobject_prefix = object_prefix;
+       dout("  object_prefix = %s\n", object_prefix);
 out:
        kfree(reply_buf);
 
@@ -5591,13 +5558,6 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
        return 0;
 }
 
-static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
-{
-       return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
-                                        rbd_is_ro(rbd_dev),
-                                        &rbd_dev->header.features);
-}
-
 /*
  * These are generic image flags, but since they are used only for
  * object map, store them in rbd_dev->object_map_flags.
@@ -5634,6 +5594,14 @@ struct parent_image_info {
        u64             overlap;
 };
 
+static void rbd_parent_info_cleanup(struct parent_image_info *pii)
+{
+       kfree(pii->pool_ns);
+       kfree(pii->image_id);
+
+       memset(pii, 0, sizeof(*pii));
+}
+
 /*
  * The caller is responsible for @pii.
  */
@@ -5703,6 +5671,9 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
        if (pii->has_overlap)
                ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+            __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+            pii->has_overlap, pii->overlap);
        return 0;
 
 e_inval:
@@ -5741,14 +5712,17 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
        pii->has_overlap = true;
        ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+            __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+            pii->has_overlap, pii->overlap);
        return 0;
 
 e_inval:
        return -EINVAL;
 }
 
-static int get_parent_info(struct rbd_device *rbd_dev,
-                          struct parent_image_info *pii)
+static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev,
+                                 struct parent_image_info *pii)
 {
        struct page *req_page, *reply_page;
        void *p;
@@ -5776,7 +5750,7 @@ static int get_parent_info(struct rbd_device *rbd_dev,
        return ret;
 }
 
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
+static int rbd_dev_setup_parent(struct rbd_device *rbd_dev)
 {
        struct rbd_spec *parent_spec;
        struct parent_image_info pii = { 0 };
@@ -5786,37 +5760,12 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
        if (!parent_spec)
                return -ENOMEM;
 
-       ret = get_parent_info(rbd_dev, &pii);
+       ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
        if (ret)
                goto out_err;
 
-       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
-            __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
-            pii.has_overlap, pii.overlap);
-
-       if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
-               /*
-                * Either the parent never existed, or we have
-                * record of it but the image got flattened so it no
-                * longer has a parent.  When the parent of a
-                * layered image disappears we immediately set the
-                * overlap to 0.  The effect of this is that all new
-                * requests will be treated as if the image had no
-                * parent.
-                *
-                * If !pii.has_overlap, the parent image spec is not
-                * applicable.  It's there to avoid duplication in each
-                * snapshot record.
-                */
-               if (rbd_dev->parent_overlap) {
-                       rbd_dev->parent_overlap = 0;
-                       rbd_dev_parent_put(rbd_dev);
-                       pr_info("%s: clone image has been flattened\n",
-                               rbd_dev->disk->disk_name);
-               }
-
+       if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap)
                goto out;       /* No parent?  No problem. */
-       }
 
        /* The ceph file layout needs to fit pool id in 32 bits */
 
@@ -5828,58 +5777,46 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
        }
 
        /*
-        * The parent won't change (except when the clone is
-        * flattened, already handled that).  So we only need to
-        * record the parent spec we have not already done so.
+        * The parent won't change except when the clone is flattened,
+        * so we only need to record the parent image spec once.
         */
-       if (!rbd_dev->parent_spec) {
-               parent_spec->pool_id = pii.pool_id;
-               if (pii.pool_ns && *pii.pool_ns) {
-                       parent_spec->pool_ns = pii.pool_ns;
-                       pii.pool_ns = NULL;
-               }
-               parent_spec->image_id = pii.image_id;
-               pii.image_id = NULL;
-               parent_spec->snap_id = pii.snap_id;
-
-               rbd_dev->parent_spec = parent_spec;
-               parent_spec = NULL;     /* rbd_dev now owns this */
+       parent_spec->pool_id = pii.pool_id;
+       if (pii.pool_ns && *pii.pool_ns) {
+               parent_spec->pool_ns = pii.pool_ns;
+               pii.pool_ns = NULL;
        }
+       parent_spec->image_id = pii.image_id;
+       pii.image_id = NULL;
+       parent_spec->snap_id = pii.snap_id;
+
+       rbd_assert(!rbd_dev->parent_spec);
+       rbd_dev->parent_spec = parent_spec;
+       parent_spec = NULL;     /* rbd_dev now owns this */
 
        /*
-        * We always update the parent overlap.  If it's zero we issue
-        * a warning, as we will proceed as if there was no parent.
+        * Record the parent overlap.  If it's zero, issue a warning as
+        * we will proceed as if there is no parent.
         */
-       if (!pii.overlap) {
-               if (parent_spec) {
-                       /* refresh, careful to warn just once */
-                       if (rbd_dev->parent_overlap)
-                               rbd_warn(rbd_dev,
-                                   "clone now standalone (overlap became 0)");
-               } else {
-                       /* initial probe */
-                       rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
-               }
-       }
+       if (!pii.overlap)
+               rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
        rbd_dev->parent_overlap = pii.overlap;
 
 out:
        ret = 0;
 out_err:
-       kfree(pii.pool_ns);
-       kfree(pii.image_id);
+       rbd_parent_info_cleanup(&pii);
        rbd_spec_put(parent_spec);
        return ret;
 }
 
-static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev,
+                                   u64 *stripe_unit, u64 *stripe_count)
 {
        struct {
                __le64 stripe_unit;
                __le64 stripe_count;
        } __attribute__ ((packed)) striping_info_buf = { 0 };
        size_t size = sizeof (striping_info_buf);
-       void *p;
        int ret;
 
        ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
@@ -5891,27 +5828,33 @@ static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
        if (ret < size)
                return -ERANGE;
 
-       p = &striping_info_buf;
-       rbd_dev->header.stripe_unit = ceph_decode_64(&p);
-       rbd_dev->header.stripe_count = ceph_decode_64(&p);
+       *stripe_unit = le64_to_cpu(striping_info_buf.stripe_unit);
+       *stripe_count = le64_to_cpu(striping_info_buf.stripe_count);
+       dout("  stripe_unit = %llu stripe_count = %llu\n", *stripe_unit,
+            *stripe_count);
+
        return 0;
 }
 
-static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id)
 {
-       __le64 data_pool_id;
+       __le64 data_pool_buf;
        int ret;
 
        ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
                                  &rbd_dev->header_oloc, "get_data_pool",
-                                 NULL, 0, &data_pool_id, sizeof(data_pool_id));
+                                 NULL, 0, &data_pool_buf,
+                                 sizeof(data_pool_buf));
+       dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
        if (ret < 0)
                return ret;
-       if (ret < sizeof(data_pool_id))
+       if (ret < sizeof(data_pool_buf))
                return -EBADMSG;
 
-       rbd_dev->header.data_pool_id = le64_to_cpu(data_pool_id);
-       WARN_ON(rbd_dev->header.data_pool_id == CEPH_NOPOOL);
+       *data_pool_id = le64_to_cpu(data_pool_buf);
+       dout("  data_pool_id = %lld\n", *data_pool_id);
+       WARN_ON(*data_pool_id == CEPH_NOPOOL);
+
        return 0;
 }
 
@@ -6103,7 +6046,8 @@ out_err:
        return ret;
 }
 
-static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
+                                  struct ceph_snap_context **psnapc)
 {
        size_t size;
        int ret;
@@ -6164,9 +6108,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
        for (i = 0; i < snap_count; i++)
                snapc->snaps[i] = ceph_decode_64(&p);
 
-       ceph_put_snap_context(rbd_dev->header.snapc);
-       rbd_dev->header.snapc = snapc;
-
+       *psnapc = snapc;
        dout("  snap context seq = %llu, snap_count = %u\n",
                (unsigned long long)seq, (unsigned int)snap_count);
 out:
@@ -6215,38 +6157,42 @@ out:
        return snap_name;
 }
 
-static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header,
+                                 bool first_time)
 {
-       bool first_time = rbd_dev->header.object_prefix == NULL;
        int ret;
 
-       ret = rbd_dev_v2_image_size(rbd_dev);
+       ret = _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
+                                   first_time ? &header->obj_order : NULL,
+                                   &header->image_size);
        if (ret)
                return ret;
 
        if (first_time) {
-               ret = rbd_dev_v2_header_onetime(rbd_dev);
+               ret = rbd_dev_v2_header_onetime(rbd_dev, header);
                if (ret)
                        return ret;
        }
 
-       ret = rbd_dev_v2_snap_context(rbd_dev);
-       if (ret && first_time) {
-               kfree(rbd_dev->header.object_prefix);
-               rbd_dev->header.object_prefix = NULL;
-       }
+       ret = rbd_dev_v2_snap_context(rbd_dev, &header->snapc);
+       if (ret)
+               return ret;
 
-       return ret;
+       return 0;
 }
 
-static int rbd_dev_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_header_info(struct rbd_device *rbd_dev,
+                              struct rbd_image_header *header,
+                              bool first_time)
 {
        rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+       rbd_assert(!header->object_prefix && !header->snapc);
 
        if (rbd_dev->image_format == 1)
-               return rbd_dev_v1_header_info(rbd_dev);
+               return rbd_dev_v1_header_info(rbd_dev, header, first_time);
 
-       return rbd_dev_v2_header_info(rbd_dev);
+       return rbd_dev_v2_header_info(rbd_dev, header, first_time);
 }
 
 /*
@@ -6734,60 +6680,49 @@ out:
  */
 static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
 {
-       struct rbd_image_header *header;
-
        rbd_dev_parent_put(rbd_dev);
        rbd_object_map_free(rbd_dev);
        rbd_dev_mapping_clear(rbd_dev);
 
        /* Free dynamic fields from the header, then zero it out */
 
-       header = &rbd_dev->header;
-       ceph_put_snap_context(header->snapc);
-       kfree(header->snap_sizes);
-       kfree(header->snap_names);
-       kfree(header->object_prefix);
-       memset(header, 0, sizeof (*header));
+       rbd_image_header_cleanup(&rbd_dev->header);
 }
 
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+                                    struct rbd_image_header *header)
 {
        int ret;
 
-       ret = rbd_dev_v2_object_prefix(rbd_dev);
+       ret = rbd_dev_v2_object_prefix(rbd_dev, &header->object_prefix);
        if (ret)
-               goto out_err;
+               return ret;
 
        /*
         * Get the and check features for the image.  Currently the
         * features are assumed to never change.
         */
-       ret = rbd_dev_v2_features(rbd_dev);
+       ret = _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
+                                       rbd_is_ro(rbd_dev), &header->features);
        if (ret)
-               goto out_err;
+               return ret;
 
        /* If the image supports fancy striping, get its parameters */
 
-       if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) {
-               ret = rbd_dev_v2_striping_info(rbd_dev);
-               if (ret < 0)
-                       goto out_err;
+       if (header->features & RBD_FEATURE_STRIPINGV2) {
+               ret = rbd_dev_v2_striping_info(rbd_dev, &header->stripe_unit,
+                                              &header->stripe_count);
+               if (ret)
+                       return ret;
        }
 
-       if (rbd_dev->header.features & RBD_FEATURE_DATA_POOL) {
-               ret = rbd_dev_v2_data_pool(rbd_dev);
+       if (header->features & RBD_FEATURE_DATA_POOL) {
+               ret = rbd_dev_v2_data_pool(rbd_dev, &header->data_pool_id);
                if (ret)
-                       goto out_err;
+                       return ret;
        }
 
-       rbd_init_layout(rbd_dev);
        return 0;
-
-out_err:
-       rbd_dev->header.features = 0;
-       kfree(rbd_dev->header.object_prefix);
-       rbd_dev->header.object_prefix = NULL;
-       return ret;
 }
 
 /*
@@ -6982,13 +6917,15 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        if (!depth)
                down_write(&rbd_dev->header_rwsem);
 
-       ret = rbd_dev_header_info(rbd_dev);
+       ret = rbd_dev_header_info(rbd_dev, &rbd_dev->header, true);
        if (ret) {
                if (ret == -ENOENT && !need_watch)
                        rbd_print_dne(rbd_dev, false);
                goto err_out_probe;
        }
 
+       rbd_init_layout(rbd_dev);
+
        /*
         * If this image is the one being mapped, we have pool name and
         * id, image name and id, and snap name - need to fill snap id.
@@ -7017,7 +6954,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        }
 
        if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
-               ret = rbd_dev_v2_parent_info(rbd_dev);
+               ret = rbd_dev_setup_parent(rbd_dev);
                if (ret)
                        goto err_out_probe;
        }
@@ -7043,6 +6980,107 @@ err_out_format:
        return ret;
 }
 
+static void rbd_dev_update_header(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header)
+{
+       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+       rbd_assert(rbd_dev->header.object_prefix); /* !first_time */
+
+       if (rbd_dev->header.image_size != header->image_size) {
+               rbd_dev->header.image_size = header->image_size;
+
+               if (!rbd_is_snap(rbd_dev)) {
+                       rbd_dev->mapping.size = header->image_size;
+                       rbd_dev_update_size(rbd_dev);
+               }
+       }
+
+       ceph_put_snap_context(rbd_dev->header.snapc);
+       rbd_dev->header.snapc = header->snapc;
+       header->snapc = NULL;
+
+       if (rbd_dev->image_format == 1) {
+               kfree(rbd_dev->header.snap_names);
+               rbd_dev->header.snap_names = header->snap_names;
+               header->snap_names = NULL;
+
+               kfree(rbd_dev->header.snap_sizes);
+               rbd_dev->header.snap_sizes = header->snap_sizes;
+               header->snap_sizes = NULL;
+       }
+}
+
+static void rbd_dev_update_parent(struct rbd_device *rbd_dev,
+                                 struct parent_image_info *pii)
+{
+       if (pii->pool_id == CEPH_NOPOOL || !pii->has_overlap) {
+               /*
+                * Either the parent never existed, or we have
+                * record of it but the image got flattened so it no
+                * longer has a parent.  When the parent of a
+                * layered image disappears we immediately set the
+                * overlap to 0.  The effect of this is that all new
+                * requests will be treated as if the image had no
+                * parent.
+                *
+                * If !pii.has_overlap, the parent image spec is not
+                * applicable.  It's there to avoid duplication in each
+                * snapshot record.
+                */
+               if (rbd_dev->parent_overlap) {
+                       rbd_dev->parent_overlap = 0;
+                       rbd_dev_parent_put(rbd_dev);
+                       pr_info("%s: clone has been flattened\n",
+                               rbd_dev->disk->disk_name);
+               }
+       } else {
+               rbd_assert(rbd_dev->parent_spec);
+
+               /*
+                * Update the parent overlap.  If it became zero, issue
+                * a warning as we will proceed as if there is no parent.
+                */
+               if (!pii->overlap && rbd_dev->parent_overlap)
+                       rbd_warn(rbd_dev,
+                                "clone has become standalone (overlap 0)");
+               rbd_dev->parent_overlap = pii->overlap;
+       }
+}
+
+static int rbd_dev_refresh(struct rbd_device *rbd_dev)
+{
+       struct rbd_image_header header = { 0 };
+       struct parent_image_info pii = { 0 };
+       int ret;
+
+       dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+       ret = rbd_dev_header_info(rbd_dev, &header, false);
+       if (ret)
+               goto out;
+
+       /*
+        * If there is a parent, see if it has disappeared due to the
+        * mapped image getting flattened.
+        */
+       if (rbd_dev->parent) {
+               ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
+               if (ret)
+                       goto out;
+       }
+
+       down_write(&rbd_dev->header_rwsem);
+       rbd_dev_update_header(rbd_dev, &header);
+       if (rbd_dev->parent)
+               rbd_dev_update_parent(rbd_dev, &pii);
+       up_write(&rbd_dev->header_rwsem);
+
+out:
+       rbd_parent_info_cleanup(&pii);
+       rbd_image_header_cleanup(&header);
+       return ret;
+}
+
 static ssize_t do_rbd_add(const char *buf, size_t count)
 {
        struct rbd_device *rbd_dev = NULL;