[Devel] [PATCH RH8 08/11] ploop: Extend file size from kernel

Kirill Tkhai ktkhai at virtuozzo.com
Fri May 21 11:46:45 MSK 2021


Do not wait for userspace truncates file at max length.
We do not need this, since there is no loop anymore.

https://jira.sw.ru/browse/PSBM-129278
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 drivers/md/dm-ploop-map.c |   80 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 77 insertions(+), 3 deletions(-)

diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
index 6504eb6fdfe3..6c0153218124 100644
--- a/drivers/md/dm-ploop-map.c
+++ b/drivers/md/dm-ploop-map.c
@@ -9,6 +9,8 @@
 #include <uapi/linux/falloc.h>
 #include "dm-ploop.h"
 
+#define PREALLOC_SIZE (128ULL * 1024 * 1024)
+
 /*
  * The idea of this driver is that the most part of time it does nothing:
  * ploop_map() just replaces bio->bi_iter.bi_sector with the cluster value
@@ -894,10 +896,76 @@ static int find_dst_cluster_bit(struct ploop *ploop,
 	return 0;
 }
 
+static int truncate_prealloc_safe(struct ploop_delta *delta, loff_t len, const char *func)
+{
+	struct file *file = delta->file;
+	loff_t new_len = len;
+	int ret;
+
+	if (new_len <= delta->file_size)
+		return 0;
+	new_len = ALIGN(new_len, PREALLOC_SIZE);
+
+	ret = vfs_truncate(&file->f_path, new_len);
+	if (ret) {
+		pr_err("ploop: %s->truncate(): %d\n", func, ret);
+		return ret;
+	}
+
+	ret = vfs_fsync(file, 0);
+	if (ret) {
+		pr_err("ploop: %s->fsync(): %d\n", func, ret);
+		return ret;
+	}
+
+	delta->file_size = new_len;
+	delta->file_preallocated_area_start = len;
+	return 0;
+}
+
 static int allocate_cluster(struct ploop *ploop, unsigned int *dst_cluster)
 {
+	struct ploop_delta *top = top_delta(ploop);
+	u32 cluster_log = ploop->cluster_log;
+	u32 clu_size = to_bytes(1 << cluster_log);
+	loff_t off, pos, end, old_size;
+	struct file *file = top->file;
+	int ret;
+
 	if (find_dst_cluster_bit(ploop, dst_cluster) < 0)
 		return -EIO;
+
+	pos = to_bytes(*dst_cluster << cluster_log);
+	end = pos + clu_size;
+	old_size = top->file_size;
+
+	if (pos < top->file_preallocated_area_start) {
+		/* Clu at @pos may contain dirty data */
+		off = min_t(loff_t, old_size, end);
+		ret = punch_hole(file, pos, off - pos);
+		if (ret) {
+			pr_err("ploop: punch hole: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (end > old_size) {
+		ret = truncate_prealloc_safe(top, end, __func__);
+		if (ret)
+			return ret;
+	} else if (pos < top->file_preallocated_area_start) {
+		/*
+		 * Flush punch_hole() modifications.
+		 * TODO: track recentry unused blocks
+		 * and punch holes in background.
+		 */
+		ret = vfs_fsync(file, 0);
+		if (ret)
+			return ret;
+	}
+
+	if (end > top->file_preallocated_area_start)
+		top->file_preallocated_area_start = end;
 	/*
 	 * Mark cluster as used. Find & clear bit is unlocked,
 	 * since currently this may be called only from deferred
@@ -915,6 +983,7 @@ static int ploop_alloc_cluster(struct ploop *ploop, struct ploop_index_wb *piwb,
 			       unsigned int cluster, unsigned int *dst_cluster)
 {
 	struct page *page = piwb->bat_page;
+	bool already_alloced = false;
 	map_index_t *to;
 	int ret = 0;
 
@@ -925,17 +994,22 @@ static int ploop_alloc_cluster(struct ploop *ploop, struct ploop_index_wb *piwb,
 	if (to[cluster]) {
 		/* Already mapped by one of previous bios */
 		*dst_cluster = to[cluster];
-		goto unmap;
+		already_alloced = true;
 	}
+	kunmap_atomic(to);
+
+	if (already_alloced)
+		goto out;
 
 	if (allocate_cluster(ploop, dst_cluster) < 0) {
 		ret = -EIO;
-		goto unmap;
+		goto out;
 	}
 
+	to = kmap_atomic(page);
 	to[cluster] = *dst_cluster;
-unmap:
 	kunmap_atomic(to);
+out:
 	return ret;
 }
 




More information about the Devel mailing list