rbd: read image size for discard check safely

In rbd_img_request_fill() the image size is only checked to determine
whether we can truncate an object instead of zeroing it for discard
requests. Take rbd_dev->header_rwsem while reading the image size, and
move this read into the discard check, so that non-discard ops don't
need to take the semaphore in this function.

Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index e2f7a70..31ace3d 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2332,7 +2332,6 @@
 		(int)type, data_desc);
 
 	img_offset = img_request->offset;
-	img_end = rbd_dev->header.image_size;
 	resid = img_request->length;
 	rbd_assert(resid > 0);
 
@@ -2397,13 +2396,20 @@
 			if (!offset && (length == object_size)
 				&& (!img_request_layered_test(img_request) ||
 					(rbd_dev->parent_overlap <=
-						obj_request->img_offset)))
+						obj_request->img_offset))) {
 				opcode = CEPH_OSD_OP_DELETE;
-			else if ((offset + length == object_size) ||
-				(obj_request->img_offset + length == img_end))
+			} else if ((offset + length == object_size)) {
 				opcode = CEPH_OSD_OP_TRUNCATE;
-			else
-				opcode = CEPH_OSD_OP_ZERO;
+			} else {
+				down_read(&rbd_dev->header_rwsem);
+				img_end = rbd_dev->header.image_size;
+				up_read(&rbd_dev->header_rwsem);
+
+				if (obj_request->img_offset + length == img_end)
+					opcode = CEPH_OSD_OP_TRUNCATE;
+				else
+					opcode = CEPH_OSD_OP_ZERO;
+			}
 		} else if (img_request_write_test(img_request)) {
 			op_type = OBJ_OP_WRITE;
 			opcode = CEPH_OSD_OP_WRITE;