[RHEL7,COMMIT] ploop: convert prealloced_size to absolute offset

Submitted by Konstantin Khorenko on Nov. 13, 2018, 11:15 a.m.

Details

Message ID 201811131115.wADBFFdw018779@finist-ce7.sw.ru
State New
Series "ploop: convert prealloced_size to absolute offset"
Headers show

Commit Message

Konstantin Khorenko Nov. 13, 2018, 11:15 a.m.
The commit is pushed to "branch-rh7-3.10.0-862.20.2.vz7.73.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.20.2.vz7.73.3
------>
commit c36a20d69d1aa9b51f88eeb27a76065916980b95
Author: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Date:   Tue Nov 13 14:15:15 2018 +0300

    ploop: convert prealloced_size to absolute offset
    
    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>
    Acked-by: Konstantin Khorenko <khorenko@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;