lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <174553065546.1161238.2653341081512215032.stgit@frogsfrogsfrogs>
Date: Thu, 24 Apr 2025 14:45:59 -0700
From: "Darrick J. Wong" <djwong@...nel.org>
To: tytso@....edu
Cc: linux-ext4@...r.kernel.org
Subject: [PATCH 2/5] libext2fs: make unix_io cache size configurable

From: Darrick J. Wong <djwong@...nel.org>

Make it so that we can reconfigure the unix IO manager cache size.
fuse2fs might want more than 32 blocks.

Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 lib/ext2fs/unix_io.c |  127 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 120 insertions(+), 7 deletions(-)


diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 207a8e63b77fd4..f8be1fe6f8d2c0 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -91,7 +91,7 @@ struct unix_cache {
 	unsigned		write_err:1;
 };
 
-#define CACHE_SIZE 8
+#define DEFAULT_CACHE_SIZE 8
 #define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
 #define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
 
@@ -102,7 +102,8 @@ struct unix_private_data {
 	int	align;
 	int	access_time;
 	ext2_loff_t offset;
-	struct unix_cache cache[CACHE_SIZE];
+	struct unix_cache *cache;
+	unsigned int cache_size;
 	void	*bounce;
 	struct struct_io_stats io_stats;
 #ifdef HAVE_PTHREAD
@@ -476,7 +477,7 @@ static errcode_t alloc_cache(io_channel channel,
 	int			i;
 
 	data->access_time = 0;
-	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+	for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
 		cache->block = 0;
 		cache->access_time = 0;
 		cache->dirty = 0;
@@ -502,7 +503,7 @@ static void free_cache(struct unix_private_data *data)
 	int			i;
 
 	data->access_time = 0;
-	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+	for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
 		cache->block = 0;
 		cache->access_time = 0;
 		cache->dirty = 0;
@@ -528,7 +529,7 @@ static struct unix_cache *find_cached_block(struct unix_private_data *data,
 	int			i;
 
 	unused_cache = oldest_cache = 0;
-	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+	for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
 		if (!cache->in_use) {
 			if (!unused_cache)
 				unused_cache = cache;
@@ -592,7 +593,7 @@ static errcode_t flush_cached_blocks(io_channel channel,
 
 	if ((flags & FLUSH_NOLOCK) == 0)
 		mutex_lock(data, CACHE_MTX);
-	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+	for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
 		if (!cache->in_use || !cache->dirty)
 			continue;
 		retval = raw_write_blk(channel, data,
@@ -616,7 +617,7 @@ static errcode_t flush_cached_blocks(io_channel channel,
 		if ((flags & FLUSH_NOLOCK) == 0)
 			mutex_lock(data, CACHE_MTX);
 		errors_found = 0;
-		for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+		for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
 			if (!cache->in_use || !cache->write_err)
 				continue;
 			errors_found = 1;
@@ -648,6 +649,89 @@ static errcode_t flush_cached_blocks(io_channel channel,
 	}
 	return retval2;
 }
+
+/* Shrink the cache buffers */
+static errcode_t shrink_cache(io_channel channel,
+			      struct unix_private_data *data,
+			      unsigned int new_size)
+{
+	struct unix_cache	*cache, *new_cache;
+	int			i;
+	errcode_t		retval;
+
+	mutex_lock(data, CACHE_MTX);
+
+	retval = flush_cached_blocks(channel, data,
+			FLUSH_INVALIDATE | FLUSH_NOLOCK);
+	if (retval)
+		goto unlock;
+
+	for (i = new_size, cache = data->cache + new_size;
+	     i < data->cache_size;
+	     i++, cache++) {
+		cache->block = 0;
+		cache->access_time = 0;
+		cache->dirty = 0;
+		cache->in_use = 0;
+		if (cache->buf)
+			ext2fs_free_mem(&cache->buf);
+	}
+
+	new_cache = realloc(data->cache, new_size * sizeof(struct unix_cache));
+	if (!new_cache) {
+		retval = EXT2_ET_NO_MEMORY;
+		goto unlock;
+	}
+
+	data->cache = new_cache;
+	data->cache_size = new_size;
+
+unlock:
+	mutex_unlock(data, CACHE_MTX);
+	return retval;
+}
+
+/* Grow the cache buffers */
+static errcode_t grow_cache(io_channel channel,
+			    struct unix_private_data *data,
+			    unsigned int new_size)
+{
+	struct unix_cache	*cache, *new_cache;
+	int			i;
+	errcode_t		retval;
+
+	mutex_lock(data, CACHE_MTX);
+
+	retval = flush_cached_blocks(channel, data,
+			FLUSH_INVALIDATE | FLUSH_NOLOCK);
+	if (retval)
+		goto unlock;
+
+	new_cache = realloc(data->cache, new_size * sizeof(struct unix_cache));
+	if (!new_cache) {
+		retval = EXT2_ET_NO_MEMORY;
+		goto unlock;
+	}
+
+	for (i = data->cache_size, cache = new_cache + data->cache_size;
+	     i < new_size;
+	     i++, cache++) {
+		cache->block = 0;
+		cache->access_time = 0;
+		cache->dirty = 0;
+		cache->in_use = 0;
+		retval = io_channel_alloc_buf(channel, 0, &cache->buf);
+		if (retval)
+			goto unlock;
+	}
+
+	data->cache = new_cache;
+	data->cache_size = new_size;
+
+unlock:
+	mutex_unlock(data, CACHE_MTX);
+	return retval;
+}
 #endif /* NO_IO_CACHE */
 
 #ifdef __linux__
@@ -743,6 +827,13 @@ static errcode_t unix_open_channel(const char *name, int fd,
 	data->flags = flags;
 	data->dev = fd;
 
+	data->cache_size = DEFAULT_CACHE_SIZE;
+	data->cache = calloc(DEFAULT_CACHE_SIZE, sizeof(struct unix_cache));
+	if (!data->cache) {
+		retval = EXT2_ET_NO_MEMORY;
+		goto cleanup;
+	}
+
 #if defined(O_DIRECT)
 	if (flags & IO_FLAG_DIRECT_IO)
 		io->align = ext2fs_get_dio_alignment(data->dev);
@@ -869,6 +960,8 @@ static errcode_t unix_open_channel(const char *name, int fd,
 		if (data->dev >= 0)
 			close(data->dev);
 		free_cache(data);
+		if (data->cache)
+			free(data->cache);
 		ext2fs_free_mem(&data);
 	}
 	if (io) {
@@ -953,6 +1046,7 @@ static errcode_t unix_close(io_channel channel)
 	if (close(data->dev) < 0)
 		retval = errno;
 	free_cache(data);
+	free(data->cache);
 #ifdef HAVE_PTHREAD
 	if (data->flags & IO_FLAG_THREADS) {
 		pthread_mutex_destroy(&data->cache_mutex);
@@ -1308,6 +1402,25 @@ static errcode_t unix_set_option(io_channel channel, const char *option,
 		}
 		return EXT2_ET_INVALID_ARGUMENT;
 	}
+#ifndef NO_IO_CACHE
+	if (!strcmp(option, "cache_blocks")) {
+		unsigned long long	size;
+
+		if (!arg)
+			return EXT2_ET_INVALID_ARGUMENT;
+
+		errno = 0;
+		size = strtoll(arg, NULL, 0);
+		if (errno || size == 0 || size > INT32_MAX)
+			return EXT2_ET_INVALID_ARGUMENT;
+
+		if (data->cache_size == size)
+			return 0;
+		if (data->cache_size > size)
+			return shrink_cache(channel, data, size);
+		return grow_cache(channel, data, size);
+	}
+#endif
 	return EXT2_ET_INVALID_ARGUMENT;
 }
 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ