[v2,RH7] ploop: convert prealloced_size to absolute offset

Submitted by Pavel Tikhomirov on Nov. 12, 2018, 8:17 a.m.

Details

Message ID 20181112081738.14409-1-ptikhomirov@virtuozzo.com
State New
Series "ploop: convert prealloced_size to absolute offset"
Headers show

Commit Message

Pavel Tikhomirov Nov. 12, 2018, 8:17 a.m.
We have places, for instance dio_alloc_sync, where we can increase
io->alloc_head without making the corresponding change to
io->prealloced_size that's why we could've got to a situation there we
had non-zero io->prealloced_size without actually having preallocated
anything. So that we get the stack:

[116697.344370] dio_submit_alloc() 763 ploop53190 set error -22
[116697.344379] CPU: 3 PID: 180251 Comm: ploop53190 ve: 0 Kdump: loaded Not tainted 3.10.0-862.14.4.ovz.72.8 #6 72.8
[116697.344384] Hardware name: DEPO Computers To be filled by O.E.M./X79-UD3, BIOS F20 03/19/2014
[116697.344387] Call Trace:
[116697.344400]  [<ffffffffaf94271d>] dump_stack+0x19/0x1b
[116697.344438]  [<ffffffffc0281f24>] dio_submit_alloc+0x184/0x240 [pio_direct]
[116697.344450]  [<ffffffffc0278b92>] ploop1_allocate+0x42/0x90 [pfmt_ploop1]
[116697.344464]  [<ffffffffc0250ee8>] ploop_req_state_process+0x358/0xd60 [ploop]
[116697.344473]  [<ffffffffaf2c0860>] ? wake_up_atomic_t+0x30/0x30
[116697.344486]  [<ffffffffc0251b2d>] ploop_thread+0x23d/0x4f0 [ploop]
[116697.344499]  [<ffffffffc02518f0>] ? ploop_req_state_process+0xd60/0xd60 [ploop]
[116697.344505]  [<ffffffffaf2bf681>] kthread+0xd1/0xe0
[116697.344511]  [<ffffffffaf2bf5b0>] ? create_kthread+0x60/0x60
[116697.344517]  [<ffffffffaf954677>] ret_from_fork_nospec_begin+0x21/0x21
[116697.344523]  [<ffffffffaf2bf5b0>] ? create_kthread+0x60/0x60

and get ploop resize fail.

So we change io->prealloced_size semantics to overcome these problem:

If preallocated region exists io->prealloced_size is set to it's end
offset, else it is set to zero. These way if io->alloc_head goes beyond
or equal to the io->prealloced_size we implicitly detect that there is
no more preallocated region, at the same time if we explicitly truncated
the region and set it's end offset to zero, zero is always <=
io->alloc_head and we detect that there is no preallocated region with
the same comparison "io->prealloced_size <= io->alloc_head".

https://jira.sw.ru/browse/PSBM-89565

v2: add comments about prealloced_size change on truncation and improve
patch description.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 drivers/block/ploop/dev.c       |  6 +++---
 drivers/block/ploop/io_direct.c | 22 ++++++++++++++--------
 drivers/block/ploop/io_kaio.c   | 12 ++++++------
 3 files changed, 23 insertions(+), 17 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index a76915f5a693..a82988c1f538 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -2581,13 +2581,11 @@  static void ploop_req_state_process(struct ploop_request * preq)
 	/* trick: preq->prealloc_size is actually new pos of eof */
 	if (unlikely(preq->prealloc_size && !preq->error)) {
 		struct ploop_io *io = &ploop_top_delta(plo)->io;
-		int log = preq->plo->cluster_log + 9;
 
 		BUG_ON(preq != io->prealloc_preq);
 		io->prealloc_preq = NULL;
 
-		io->prealloced_size = preq->prealloc_size -
-				      ((loff_t)io->alloc_head << log);
+		io->prealloced_size = preq->prealloc_size;
 		preq->prealloc_size = 0; /* only for sanity */
 	}
 
@@ -3919,6 +3917,7 @@  static int ploop_truncate(struct ploop_device * plo, unsigned long arg)
 
 	err = delta->ops->truncate(delta, file, ctl.alloc_head);
 	if (!err)
+		/* See comment in dio_release_prealloced */
 		delta->io.prealloced_size = 0;
 
 	ploop_relax(plo);
@@ -4832,6 +4831,7 @@  static int ploop_relocblks_ioc(struct ploop_device *plo, unsigned long arg)
 		err = delta->ops->truncate(delta, NULL,
 					   ploop_fb_get_first_lost_iblk(plo->fbd));
 		if (!err) {
+			/* See comment in dio_release_prealloced */
 			delta->io.prealloced_size = 0;
 			ctl.alloc_head = ploop_fb_get_lost_range_len(plo->fbd);
 			err = copy_to_user((void*)arg, &ctl, sizeof(ctl));
diff --git a/drivers/block/ploop/io_direct.c b/drivers/block/ploop/io_direct.c
index de41234f907c..5388169c19de 100644
--- a/drivers/block/ploop/io_direct.c
+++ b/drivers/block/ploop/io_direct.c
@@ -366,7 +366,7 @@  cached_submit(struct ploop_io *io, iblock_t iblk, struct ploop_request * preq,
 	file_start_write(io->files.file);
 
 	if (use_prealloc && end_pos > used_pos && may_fallocate) {
-		if (unlikely(io->prealloced_size < clu_siz)) {
+		if (unlikely(io->prealloced_size < used_pos + clu_siz)) {
 			loff_t prealloc = end_pos;
 			if (prealloc > PLOOP_MAX_PREALLOC(plo))
 				prealloc = PLOOP_MAX_PREALLOC(plo);
@@ -387,10 +387,8 @@  cached_submit(struct ploop_io *io, iblock_t iblk, struct ploop_request * preq,
 			if (err)
 				goto end_write;
 
-			io->prealloced_size = prealloc;
+			io->prealloced_size = pos + prealloc;
 		}
-
-		io->prealloced_size -= clu_siz;
 	}
 
 	if (may_fallocate) {
@@ -901,18 +899,26 @@  static int dio_truncate(struct ploop_io *, struct file *, __u32);
 static int dio_release_prealloced(struct ploop_io * io)
 {
 	int ret;
+	loff_t end_pos = (loff_t)io->alloc_head << (io->plo->cluster_log + 9);
 
-	if (!io->prealloced_size)
+	if (io->prealloced_size <= end_pos)
 		return 0;
 
 	ret = dio_truncate(io, io->files.file, io->alloc_head);
 	if (ret)
 		printk("Can't release %llu prealloced bytes: "
 		       "truncate to %llu failed (%d)\n",
-		       io->prealloced_size,
-		       (loff_t)io->alloc_head << (io->plo->cluster_log + 9),
-		       ret);
+		       io->prealloced_size - end_pos, end_pos, ret);
 	else
+		/*
+		 * We've changed semantics here: If preallocated region exists
+		 * io->prealloced_size is set to it's end offset, else it is
+		 * set to zero. If prealloced_size is <= end_pos we act as if
+		 * nothing is preallocated, these will work both for explicitly
+		 * truncated region and for implicitly truncated when
+		 * io->alloc_head goes beyond or equal to the
+		 * io->prealloced_size.
+		 */
 		io->prealloced_size = 0;
 
 	return ret;
diff --git a/drivers/block/ploop/io_kaio.c b/drivers/block/ploop/io_kaio.c
index e97e8e1a334d..3a89d6abb679 100644
--- a/drivers/block/ploop/io_kaio.c
+++ b/drivers/block/ploop/io_kaio.c
@@ -549,6 +549,7 @@  kaio_submit_alloc(struct ploop_io *io, struct ploop_request * preq,
 	iblock_t iblk;
 	int log = preq->plo->cluster_log + 9;
 	loff_t clu_siz = 1 << log;
+	loff_t end_pos = (loff_t)io->alloc_head << (io->plo->cluster_log + 9);
 
 	if (delta->flags & PLOOP_FMT_RDONLY) {
 		PLOOP_FAIL_REQUEST(preq, -EBADF);
@@ -567,7 +568,7 @@  kaio_submit_alloc(struct ploop_io *io, struct ploop_request * preq,
 
 	BUG_ON(preq->prealloc_size);
 
-	if (unlikely(io->prealloced_size < clu_siz)) {
+	if (unlikely(io->prealloced_size < end_pos + clu_siz)) {
 		if (!io->prealloc_preq) {
 			loff_t pos = (((loff_t)(iblk + 1)  << log) |
 				      (KAIO_PREALLOC - 1)) + 1;
@@ -588,7 +589,6 @@  kaio_submit_alloc(struct ploop_io *io, struct ploop_request * preq,
 		}
 	}
 
-	io->prealloced_size -= clu_siz;
 	io->alloc_head++;
 
 	preq->iblock = iblk;
@@ -600,18 +600,18 @@  kaio_submit_alloc(struct ploop_io *io, struct ploop_request * preq,
 static int kaio_release_prealloced(struct ploop_io * io)
 {
 	int ret;
+	loff_t end_pos = (loff_t)io->alloc_head << (io->plo->cluster_log + 9);
 
-	if (!io->prealloced_size)
+	if (io->prealloced_size <= end_pos)
 		return 0;
 
 	ret = kaio_truncate(io, io->files.file, io->alloc_head);
 	if (ret)
 		printk("Can't release %llu prealloced bytes: "
 		       "truncate to %llu failed (%d)\n",
-		       io->prealloced_size,
-		       (loff_t)io->alloc_head << (io->plo->cluster_log + 9),
-		       ret);
+		       io->prealloced_size - end_pos, end_pos, ret);
 	else
+		/* See comment in dio_release_prealloced */
 		io->prealloced_size = 0;
 
 	return ret;