drbd: Made the fifo object a self contained object (preparing for RCU)

* Moved rs_planed into it, named total
* When having a pointer to the object the values can
  be embedded into the fifo object.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index ea62838..7fda3d9 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1107,8 +1107,8 @@
 	enum drbd_ret_code retcode;
 	struct drbd_conf *mdev;
 	struct disk_conf *new_disk_conf, *old_disk_conf;
+	struct fifo_buffer *rs_plan_s = NULL;
 	int err, fifo_size;
-	int *rs_plan_s = NULL;
 
 	retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
 	if (!adm_ctx.reply_skb)
@@ -1153,8 +1153,8 @@
 		new_disk_conf->al_extents = DRBD_AL_EXTENTS_MAX;
 
 	fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
-	if (fifo_size != mdev->rs_plan_s.size && fifo_size > 0) {
-		rs_plan_s   = kzalloc(sizeof(int) * fifo_size, GFP_KERNEL);
+	if (fifo_size != mdev->rs_plan_s->size) {
+		rs_plan_s = fifo_alloc(fifo_size);
 		if (!rs_plan_s) {
 			dev_err(DEV, "kmalloc of fifo_buffer failed");
 			retcode = ERR_NOMEM;
@@ -1162,14 +1162,6 @@
 		}
 	}
 
-	if (fifo_size != mdev->rs_plan_s.size) {
-		kfree(mdev->rs_plan_s.values);
-		mdev->rs_plan_s.values = rs_plan_s;
-		mdev->rs_plan_s.size   = fifo_size;
-		mdev->rs_planed = 0;
-		rs_plan_s = NULL;
-	}
-
 	wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
 	drbd_al_shrink(mdev);
 	err = drbd_check_al_size(mdev, new_disk_conf);
@@ -1192,6 +1184,14 @@
 	if (retcode != NO_ERROR)
 		goto fail_unlock;
 
+	spin_lock(&mdev->peer_seq_lock);
+	if (rs_plan_s) {
+		kfree(mdev->rs_plan_s);
+		mdev->rs_plan_s = rs_plan_s;
+		rs_plan_s = NULL;
+	}
+	spin_unlock(&mdev->peer_seq_lock);
+
 	drbd_md_sync(mdev);
 
 	if (mdev->state.conn >= C_CONNECTED)
@@ -1226,6 +1226,7 @@
 	struct disk_conf *new_disk_conf = NULL;
 	struct block_device *bdev;
 	struct lru_cache *resync_lru = NULL;
+	struct fifo_buffer *new_plan = NULL;
 	union drbd_state ns, os;
 	enum drbd_state_rv rv;
 	struct net_conf *nc;
@@ -1272,6 +1273,12 @@
 		goto fail;
 	}
 
+	new_plan = fifo_alloc((new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ);
+	if (!new_plan) {
+		retcode = ERR_NOMEM;
+		goto fail;
+	}
+
 	if (new_disk_conf->meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) {
 		retcode = ERR_MD_IDX_INVALID;
 		goto fail;
@@ -1443,7 +1450,7 @@
 	else
 		clear_bit(MD_NO_FUA, &mdev->flags);
 
-	/* FIXME Missing stuff: rs_plan_s, clip al range */
+	/* FIXME Missing stuff: clip al range */
 
 	/* Point of no return reached.
 	 * Devices and memory are no longer released by error cleanup below.
@@ -1452,9 +1459,11 @@
 	D_ASSERT(mdev->ldev == NULL);
 	mdev->ldev = nbc;
 	mdev->resync = resync_lru;
+	mdev->rs_plan_s = new_plan;
 	nbc = NULL;
 	resync_lru = NULL;
 	new_disk_conf = NULL;
+	new_plan = NULL;
 
 	mdev->write_ordering = WO_bdev_flush;
 	drbd_bump_write_ordering(mdev, WO_bdev_flush);
@@ -1615,6 +1624,7 @@
 	}
 	kfree(new_disk_conf);
 	lc_destroy(resync_lru);
+	kfree(new_plan);
 
  finish:
 	drbd_adm_finish(info, retcode);