rbd: do not read in parent info before snap context
[firefly-linux-kernel-4.4.55.git] / drivers / block / rbd.c
index c4064c53b9c98936d221fc4266647414421516fd..c4606987e9d1368b435ccc1aa2e2fd48843f272a 100644 (file)
@@ -515,6 +515,7 @@ 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 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,
@@ -971,12 +972,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
        header->snap_names = snap_names;
        header->snap_sizes = snap_sizes;
 
-       /* Make sure mapping size is consistent with header info */
-
-       if (rbd_dev->spec->snap_id == CEPH_NOSNAP || first_time)
-               if (rbd_dev->mapping.size != header->image_size)
-                       rbd_dev->mapping.size = header->image_size;
-
        return 0;
 out_2big:
        ret = -EIO;
@@ -3522,14 +3517,28 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
        if (ret)
                return ret;
 
-       /* If it's a mapped snapshot, validate its EXISTS flag */
+       /*
+        * 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)
+                       return ret;
+       }
+
+       if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
+               if (rbd_dev->mapping.size != rbd_dev->header.image_size)
+                       rbd_dev->mapping.size = rbd_dev->header.image_size;
+       } else {
+               /* validate mapped snapshot's EXISTS flag */
+               rbd_exists_validate(rbd_dev);
+       }
 
-       rbd_exists_validate(rbd_dev);
        up_write(&rbd_dev->header_rwsem);
 
-       if (mapping_size != rbd_dev->mapping.size) {
+       if (mapping_size != rbd_dev->mapping.size)
                rbd_dev_update_size(rbd_dev);
-       }
 
        return 0;
 }
@@ -4480,37 +4489,6 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
                        return ret;
        }
 
-       /*
-        * If the image supports layering, get the parent info.  We
-        * need to probe the first time regardless.  Thereafter we
-        * only need to if there's a parent, to see if it has
-        * disappeared due to the mapped image getting flattened.
-        */
-       if (rbd_dev->header.features & RBD_FEATURE_LAYERING &&
-                       (first_time || rbd_dev->parent_spec)) {
-               bool warn;
-
-               ret = rbd_dev_v2_parent_info(rbd_dev);
-               if (ret)
-                       return ret;
-
-               /*
-                * Print a warning if this is the initial probe and
-                * the image has a parent.  Don't print it if the
-                * image now being probed is itself a parent.  We
-                * can tell at this point because we won't know its
-                * pool name yet (just its pool id).
-                */
-               warn = rbd_dev->parent_spec && rbd_dev->spec->pool_name;
-               if (first_time && warn)
-                       rbd_warn(rbd_dev, "WARNING: kernel layering "
-                                       "is EXPERIMENTAL!");
-       }
-
-       if (rbd_dev->spec->snap_id == CEPH_NOSNAP)
-               if (rbd_dev->mapping.size != rbd_dev->header.image_size)
-                       rbd_dev->mapping.size = rbd_dev->header.image_size;
-
        ret = rbd_dev_v2_snap_context(rbd_dev);
        dout("rbd_dev_v2_snap_context returned %d\n", ret);
 
@@ -5190,14 +5168,28 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
        if (ret)
                goto err_out_probe;
 
+       if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
+               ret = rbd_dev_v2_parent_info(rbd_dev);
+               if (ret)
+                       goto err_out_probe;
+
+               /*
+                * Need to warn users if this image is the one being
+                * mapped and has a parent.
+                */
+               if (mapping && rbd_dev->parent_spec)
+                       rbd_warn(rbd_dev,
+                                "WARNING: kernel layering is EXPERIMENTAL!");
+       }
+
        ret = rbd_dev_probe_parent(rbd_dev);
        if (ret)
                goto err_out_probe;
 
        dout("discovered format %u image, header name is %s\n",
                rbd_dev->image_format, rbd_dev->header_name);
-
        return 0;
+
 err_out_probe:
        rbd_dev_unprobe(rbd_dev);
 err_out_watch:
@@ -5210,9 +5202,6 @@ err_out_format:
        rbd_dev->image_format = 0;
        kfree(rbd_dev->spec->image_id);
        rbd_dev->spec->image_id = NULL;
-
-       dout("probe failed, returning %d\n", ret);
-
        return ret;
 }